Skip to content

Instantly share code, notes, and snippets.

@jakelazaroff
Created March 16, 2026 19:00
Show Gist options
  • Select an option

  • Save jakelazaroff/be42aa0435df3ff079583fd3af16120e to your computer and use it in GitHub Desktop.

Select an option

Save jakelazaroff/be42aa0435df3ff079583fd3af16120e to your computer and use it in GitHub Desktop.
basic vps hardening and setup
#!/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