# Unified First-Boot Server Setup Script A complete, self-contained provisioning script for automated server deployment that combines both **Ripcord** and **SYNterloper** with system hardening tasks (user creation, SSH setup, sudoers) in one idempotent user-data script. --- ## ๐Ÿ”ง Purpose This script automates the following tasks on first boot: - Creates a non-root user with SSH access and sudo privileges - Installs Ansible-ready Python packages - Deploys **Ripcord** (emergency disk space reserve) - Deploys **SYNterloper** (rolling SSH connection logger) - Validates each step with `.flag` files - Leaves all components ready for manual management โžก๏ธ **For tool-specific details, see individual READMEs**: - [Ripcord README](./ripcord/README.md) - [SYNterloper README](./synterloper/README.md) --- ## ๐Ÿ“ฆ Repository Structure ``` . โ”œโ”€โ”€ user-data.sh # This script โ”œโ”€โ”€ ripcord/ โ”‚ โ”œโ”€โ”€ ripcord.sh โ”‚ โ””โ”€โ”€ README.md โ”œโ”€โ”€ synterloper/ โ”‚ โ”œโ”€โ”€ synterloper.sh โ”‚ โ””โ”€โ”€ README.md โ””โ”€โ”€ README.md # You are here ``` --- ## ๐Ÿš€ Installation Paste this script into your cloud provider's **User Data** field during instance creation: ```bash #!/bin/bash set -e # Exit on any error # Define user and flag locations USRNAME=fastsoul FLAG_DIR=/var/lib/cloud/scripts/user mkdir -p "$FLAG_DIR" # --- Step 1: Create user --- if [ ! -f "$FLAG_DIR/.user_created.flag" ]; then echo "Creating user: $USRNAME" if ! id "$USRNAME" &>/dev/null; then useradd "$USRNAME" -s /bin/bash -d /home/"$USRNAME" -m || { echo "User creation failed"; exit 1; } chown -R "$USRNAME":"$USRNAME" /home/"$USRNAME" else echo "User $USRNAME already exists. Skipping creation." fi touch "$FLAG_DIR/.user_created.flag" fi # --- Step 2: Create SSH directory and authorized_keys file --- if [ ! -f "$FLAG_DIR/.ssh_setup.flag" ]; then echo "Setting up SSH for $USRNAME" mkdir -p "/home/$USRNAME/.ssh" touch "/home/$USRNAME/.ssh/authorized_keys" chown -R "$USRNAME":"$USRNAME" "/home/$USRNAME/.ssh" chmod 700 "/home/$USRNAME/.ssh" chmod 600 "/home/$USRNAME/.ssh/authorized_keys" touch "$FLAG_DIR/.ssh_setup.flag" fi # --- Step 3: Add SSH keys to authorized_keys --- if [ ! -f "$FLAG_DIR/.ssh_keys_added.flag" ]; then echo "Adding SSH keys to authorized_keys" cat << EOF >> /home/$USRNAME/.ssh/authorized_keys cert-authority ssh-rsa AAAAB3NzaXXXX== user@example.com ssh-rsa AAAAB3NzaYYYYYYYYYYYYYYYYYYYYYYYYYYYYQ== ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXQ== EOF if [ $? -eq 0 ]; then chown -R "$USRNAME":"$USRNAME" "/home/$USRNAME/.ssh/authorized_keys" touch "$FLAG_DIR/.ssh_keys_added.flag" else echo "Failed to write SSH keys to authorized_keys" exit 1 fi fi # --- Step 4: Set NOPASSWD sudoers --- if [ ! -f "$FLAG_DIR/.sudoers_set.flag" ]; then echo "Setting up NOPASSWD sudo for $USRNAME" echo "$USRNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/"$USRNAME" || { echo "Failed to write sudoers file"; exit 1; } touch "$FLAG_DIR/.sudoers_set.flag" fi # --- Step 5: Install python3-apt for Ansible support --- if [ ! -f "$FLAG_DIR/.python_installed.flag" ]; then echo "Updating APT and installing python3-apt" apt update -y || { echo "APT update failed"; exit 1; } apt install -y python3-apt || { echo "Failed to install python3-apt"; exit 1; } touch "$FLAG_DIR/.python_installed.flag" fi # --- Step 6: Download Ripcord and SYNterloper from Git --- if [ ! -f "$FLAG_DIR/.scripts_downloaded.flag" ]; then echo "Downloading Ripcord and SYNterloper scripts" curl -fsSL -o /usr/local/sbin/ripcord.sh https://git.r21.io/primemover/user-data/raw/branch/master/ripcord/ripcord.sh || { echo "Ripcord download failed"; exit 1; } curl -fsSL -o /usr/local/sbin/synterloper.sh https://git.r21.io/primemover/user-data/raw/branch/master/synterloper/synterloper.sh || { echo "SYNterloper download failed"; exit 1; } chmod +x /usr/local/sbin/ripcord.sh /usr/local/sbin/synterloper.sh || { echo "chmod failed"; exit 1; } touch "$FLAG_DIR/.scripts_downloaded.flag" fi # --- Step 7: Setup Ripcord systemd service --- if [ ! -f "$FLAG_DIR/.ripcord_setup.flag" ]; then echo "Setting up Ripcord systemd service" cat << EOF | sudo tee /etc/systemd/system/ripcord.service [Unit] Description=Ripcord Emergency Disk Space Reserve [Service] Type=oneshot ExecStart=/usr/local/sbin/ripcord.sh ExecStartPost=/bin/sh -c "systemctl disable ripcord.service" [Install] WantedBy=multi-user.target EOF systemctl enable ripcord.service || { echo "Failed to enable Ripcord service"; exit 1; } touch "$FLAG_DIR/.ripcord_setup.flag" fi # --- Step 8: Install SYNterloper --- if [ ! -f "$FLAG_DIR/.synterloper_installed.flag" ]; then echo "Installing SYNterloper" /usr/local/sbin/synterloper.sh install || { echo "SYNterloper install failed"; exit 1; } touch "$FLAG_DIR/.synterloper_installed.flag" fi # --- Final Step: Mark completion --- if [ ! -f "$FLAG_DIR/.user_data_complete.flag" ]; then echo "Marking user-data completion" touch /root/user_data_completed.txt touch "$FLAG_DIR/.user_data_complete.flag" fi echo "All steps completed successfully." exit 0 ``` ### โœ… What Gets Installed | Component | Purpose | Validation Flag | |-------------------|----------------------------------|-------------------------------------| | User: `fastsoul` | Primary admin account | `/var/lib/cloud/scripts/user/.user_created.flag` | | SSH Keys | Cert-authority and/or deployment keys | `/var/lib/cloud/scripts/user/.ssh_keys_added.flag` | | Sudoers | NOPASSWD:ALL access | `/var/lib/cloud/scripts/user/.sudoers_set.flag` | | Python 3-apt | Ansible dependency | `/var/lib/cloud/scripts/user/.python_installed.flag` | | Ripcord.sh | Emergency disk ballast | `/var/lib/cloud/scripts/user/.ripcord_setup.flag` | | Synterloper.sh | Rolling SSH connection logger | `/var/lib/cloud/scripts/user/.synterloper_installed.flag` | --- ## โš™๏ธ Configuration Edit these variables at the top of the script to customize: ```bash # Change these to match your needs USRNAME=fastsoul SSH_KEYS=" cert-authority ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXX...user@example.com ssh-rsa AAAAB3NzaYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYQ== ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXQ== ``` --- ## ๐Ÿ” Validation All steps are validated with `.flag` files in `/var/lib/cloud/scripts/user/`: ```bash ls -la /var/lib/cloud/scripts/user/ ``` Expected output: ``` .user_created.flag .ssh_keys_added.flag .sudoers_set.flag .python_installed.flag .scripts_downloaded.flag .ripcord_setup.flag .synterloper_installed.flag .user_data_complete.flag ``` --- ## ๐Ÿงน Re-running To re-run the script (e.g., for testing): 1. Delete specific `.flag` files: ```bash rm /var/lib/cloud/scripts/user/.sudoers_set.flag ``` 2. Re-run the script: ```bash sudo /var/lib/cloud/scripts/user/user-data.sh ``` --- ## โš ๏ธ Known Limitations - **Debian/Ubuntu only** (FreeBSD support would require separate logic) - **Root access required** (must be run via cloud-init) - **Hardcoded SSH keys** (rotate credentials for production use) --- ## ๐Ÿ“š For More Details - [Ripcord README](./ripcord/README.md) - [SYNterloper README](./synterloper/README.md) --- ## ๐Ÿ“„ License This script is released under the **MIT License**. See `LICENSE` for details.