Pass data to an instance to configure it or run scripts after it starts.
ripcord | ||
synterloper | ||
LICENSE | ||
README.md |
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:
📦 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:
#!/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:
# 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/
:
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):
- Delete specific
.flag
files:rm /var/lib/cloud/scripts/user/.sudoers_set.flag
- Re-run the script:
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
📄 License
This script is released under the MIT License. See LICENSE
for details.