Created
March 16, 2026 19:00
-
-
Save jakelazaroff/be42aa0435df3ff079583fd3af16120e to your computer and use it in GitHub Desktop.
basic vps hardening and setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # provision.sh - basic VPS hardening and setup | |
| # | |
| # Run as root on a fresh server. | |
| set -e | |
| [ "$(id -u)" -ne 0 ] && { echo "Must be run as root"; exit 1; } | |
| # Detect package manager | |
| if command -v apt &>/dev/null; then | |
| PKG="apt" | |
| elif command -v dnf &>/dev/null; then | |
| PKG="dnf" | |
| elif command -v yum &>/dev/null; then | |
| PKG="yum" | |
| else | |
| echo "Unsupported package manager (expected apt, dnf, or yum)"; exit 1 | |
| fi | |
| # Detect sudo group | |
| if getent group sudo &>/dev/null; then | |
| SUDO_GROUP="sudo" | |
| elif getent group wheel &>/dev/null; then | |
| SUDO_GROUP="wheel" | |
| else | |
| echo "Could not find sudo or wheel group"; exit 1 | |
| fi | |
| # --- Prompts --- | |
| read -rp "New sudo username: " NEW_USER | |
| [ -z "$NEW_USER" ] && { echo "Username is required"; exit 1; } | |
| CURRENT_HOSTNAME=$(hostname) | |
| read -rp "Hostname [$CURRENT_HOSTNAME]: " NEW_HOSTNAME | |
| NEW_HOSTNAME=${NEW_HOSTNAME:-$CURRENT_HOSTNAME} | |
| CURRENT_TZ=$(timedatectl show --property=Timezone --value 2>/dev/null \ | |
| || cat /etc/timezone 2>/dev/null \ | |
| || readlink /etc/localtime 2>/dev/null | sed 's|.*/zoneinfo/||' \ | |
| || echo "UTC") | |
| read -rp "Timezone [$CURRENT_TZ]: " NEW_TZ | |
| NEW_TZ=${NEW_TZ:-$CURRENT_TZ} | |
| echo "" | |
| echo "Summary:" | |
| echo " User: $NEW_USER" | |
| echo " Hostname: $NEW_HOSTNAME" | |
| echo " Timezone: $NEW_TZ" | |
| echo "" | |
| read -rp "Proceed? [y/N] " CONFIRM | |
| [[ "$CONFIRM" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; } | |
| echo "" | |
| # --- Update system --- | |
| echo "==> Updating system packages..." | |
| if [ "$PKG" = "apt" ]; then | |
| DEBIAN_FRONTEND=noninteractive apt update -y | |
| DEBIAN_FRONTEND=noninteractive apt upgrade -y -o Dpkg::Options::="--force-confold" | |
| else | |
| $PKG update -y && $PKG upgrade -y | |
| fi | |
| echo " Done." | |
| # --- Create user --- | |
| echo "==> Creating user: $NEW_USER..." | |
| if id "$NEW_USER" &>/dev/null; then | |
| echo " User already exists, skipping." | |
| else | |
| useradd -m -s /bin/bash "$NEW_USER" | |
| echo " Created." | |
| fi | |
| usermod -aG "$SUDO_GROUP" "$NEW_USER" | |
| echo " Added $NEW_USER to $SUDO_GROUP." | |
| echo "$NEW_USER ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/$NEW_USER" | |
| chmod 0440 "/etc/sudoers.d/$NEW_USER" | |
| echo " Configured passwordless sudo." | |
| # Copy root's authorized_keys so the new user can SSH in | |
| if [ -f /root/.ssh/authorized_keys ]; then | |
| mkdir -p "/home/$NEW_USER/.ssh" | |
| cp /root/.ssh/authorized_keys "/home/$NEW_USER/.ssh/authorized_keys" | |
| chown -R "$NEW_USER:$NEW_USER" "/home/$NEW_USER/.ssh" | |
| chmod 700 "/home/$NEW_USER/.ssh" | |
| chmod 600 "/home/$NEW_USER/.ssh/authorized_keys" | |
| echo " Copied SSH authorized_keys from root." | |
| else | |
| echo " WARNING: No /root/.ssh/authorized_keys found." | |
| echo " Add your public key to /home/$NEW_USER/.ssh/authorized_keys before proceeding." | |
| fi | |
| # --- Hostname --- | |
| echo "==> Setting hostname to: $NEW_HOSTNAME..." | |
| hostnamectl set-hostname "$NEW_HOSTNAME" | |
| echo " Done." | |
| # --- Timezone --- | |
| echo "==> Setting timezone to: $NEW_TZ..." | |
| timedatectl set-timezone "$NEW_TZ" | |
| echo " Done." | |
| # --- Firewall --- | |
| echo "==> Configuring firewall (ufw)..." | |
| if ! command -v ufw &>/dev/null; then | |
| $PKG install -y ufw | |
| fi | |
| ufw allow ssh | |
| ufw allow 80 | |
| ufw allow 443 | |
| echo "y" | ufw enable | |
| echo " Done." | |
| # --- fail2ban --- | |
| echo "==> Installing fail2ban..." | |
| $PKG install -y fail2ban | |
| systemctl enable --now fail2ban | |
| echo " Done." | |
| # --- Automatic security updates (apt only) --- | |
| if [ "$PKG" = "apt" ]; then | |
| echo "==> Enabling unattended security upgrades..." | |
| apt install -y unattended-upgrades | |
| dpkg-reconfigure -f noninteractive unattended-upgrades | |
| echo " Done." | |
| fi | |
| # --- Harden SSH --- | |
| echo "==> Hardening SSH..." | |
| SSHD_CONFIG=/etc/ssh/sshd_config | |
| cp "$SSHD_CONFIG" "${SSHD_CONFIG}.bak" | |
| set_sshd() { | |
| local key=$1 value=$2 | |
| if grep -qE "^#?${key}" "$SSHD_CONFIG"; then | |
| sed -i "s|^#\?${key}.*|${key} ${value}|" "$SSHD_CONFIG" | |
| else | |
| echo "${key} ${value}" >> "$SSHD_CONFIG" | |
| fi | |
| } | |
| set_sshd PermitRootLogin no | |
| set_sshd PasswordAuthentication no | |
| systemctl restart ssh 2>/dev/null || systemctl restart sshd | |
| echo " Root login and password authentication disabled." | |
| echo " Original config backed up to ${SSHD_CONFIG}.bak" | |
| # --- Done --- | |
| echo "" | |
| echo "Done! Next steps:" | |
| echo " 1. Open a new terminal and verify SSH access as $NEW_USER before closing this session" | |
| echo " 2. Take a VPS snapshot via your provider's dashboard" | |
| echo " 3. Set up uptime monitoring (e.g. UptimeRobot)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment