Server Setup Script Generator
Generate a bash post-install script for a fresh Ubuntu or Debian VPS.
Client-side only — nothing leaves your browser
Options
Sets the system hostname and updates /etc/hosts.
Configures the system timezone via timedatectl.
Creates a new user with passwordless sudo and installs your SSH key.
Paste the contents of your public key (e.g. ~/.ssh/id_ed25519.pub).
Sets PermitRootLogin no in sshd_config.
Forces SSH key-based login only. Make sure your key works first!
Move SSH off port 22 to reduce drive-by scans.
Default-deny incoming, allow listed ports, allow all outgoing.
Comma-separated. Examples: 80, 443, 8080/tcp, 51820/udp. The active SSH port is always allowed.
Bans IPs after repeated failed SSH login attempts.
Installs docker-ce, CLI, buildx, and the compose plugin from docker.com.
curl, wget, git, htop, vim, build-essential, ca-certificates, gnupg.
Auto-installs security patches via unattended-upgrades.
Adds a /swapfile and persists it in /etc/fstab.
SYN cookies, ignore ICMP redirects, disable source routing, log martians.
setup.sh
Upload to your server and run as root: bash setup.sh
#!/usr/bin/env bash
#
# Ubuntu / Debian VPS Initial Setup & Hardening Script
# Generated by https://sshworkbench.com/tools/server-setup-script-generator
#
# Usage:
# 1. Copy this file to your server (e.g. scp setup.sh root@host:/root/)
# 2. Run as root: bash setup.sh
#
# This script is idempotent where reasonable — re-running should be safe.
set -euo pipefail
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root (try: sudo bash setup.sh)" >&2
exit 1
fi
export DEBIAN_FRONTEND=noninteractive
log() { printf "\n\033[1;34m[+] %s\033[0m\n" "$*"; }
############################################################################
# 1. System update
############################################################################
log "Updating package index and upgrading installed packages"
apt-get update -y
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade -y
############################################################################
# 2. Hostname
############################################################################
log "Setting hostname to my-server"
hostnamectl set-hostname 'my-server'
if ! grep -q "my-server" /etc/hosts; then
echo "127.0.1.1 my-server" >> /etc/hosts
fi
############################################################################
# 3. Timezone
############################################################################
log "Setting timezone to UTC"
timedatectl set-timezone 'UTC'
############################################################################
# 4. Common packages
############################################################################
log "Installing common packages"
apt-get install -y \
curl wget git htop vim build-essential \
ca-certificates gnupg lsb-release software-properties-common \
unattended-upgrades apt-listchanges
############################################################################
# 5. Create non-root sudo user
############################################################################
log "Creating sudo user: deploy"
if ! id -u 'deploy' >/dev/null 2>&1; then
adduser --disabled-password --gecos "" 'deploy'
fi
usermod -aG sudo 'deploy'
# Allow passwordless sudo (since we'll be using SSH keys)
echo "deploy ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-deploy
chmod 440 /etc/sudoers.d/90-deploy
# WARNING: no SSH public key was provided.
# Add one to /home/deploy/.ssh/authorized_keys before disabling password auth.
############################################################################
# 6. SSH hardening
############################################################################
log "Hardening SSH daemon configuration"
SSHD_CONFIG=/etc/ssh/sshd_config
cp -n "$SSHD_CONFIG" "${SSHD_CONFIG}.bak.$(date +%s)" || true
mkdir -p /etc/ssh/sshd_config.d
cat > /etc/ssh/sshd_config.d/99-hardening.conf <<'EOF_SSHD'
# Managed by setup.sh — overrides values in /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM yes
PubkeyAuthentication yes
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3
LoginGraceTime 30
EOF_SSHD
chmod 644 /etc/ssh/sshd_config.d/99-hardening.conf
log "Validating sshd config"
sshd -t
log "Restarting SSH service"
systemctl restart ssh
############################################################################
# 7. UFW firewall
############################################################################
log "Configuring UFW firewall"
apt-get install -y ufw
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow 80
ufw allow 443
ufw allow 22/tcp
ufw --force enable
ufw status verbose
############################################################################
# 8. fail2ban
############################################################################
log "Installing and configuring fail2ban"
apt-get install -y fail2ban
cat > /etc/fail2ban/jail.local <<'EOF_F2B'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = 22
EOF_F2B
systemctl enable --now fail2ban
systemctl restart fail2ban
############################################################################
# 10. Unattended security upgrades
############################################################################
log "Enabling unattended security upgrades"
apt-get install -y unattended-upgrades apt-listchanges
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF_AUTO'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
EOF_AUTO
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<'EOF_UU'
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
EOF_UU
systemctl enable --now unattended-upgrades
############################################################################
# 12. sysctl hardening
############################################################################
log "Applying sysctl hardening basics"
cat > /etc/sysctl.d/99-hardening.conf <<'EOF_SYSCTL'
# Managed by setup.sh
# IP spoofing & source routing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Log martians
net.ipv4.conf.all.log_martians = 1
# Disable IPv6 router advertisements
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
# Kernel hardening
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
EOF_SYSCTL
sysctl --system >/dev/null
############################################################################
# Done
############################################################################
log "Server setup complete."
echo " Log in next time as: deploy@<host>"
echo " Reboot recommended if a new kernel was installed."
What is a server setup script?
A server setup script (also called a post-install or initial setup script) is a bash file you run on a fresh Ubuntu or Debian VPS to handle the repetitive first-boot tasks: creating a non-root user, installing your SSH key, locking down SSH, configuring a firewall, installing fail2ban, enabling automatic security updates, and applying basic kernel and network hardening. Running these steps from a single script makes new servers reproducible, auditable, and dramatically harder to compromise than a default cloud image.
What this script configures
| Section | What it does |
|---|---|
| System update | Runs apt-get update && apt-get upgrade non-interactively. |
| Hostname & timezone | hostnamectl and timedatectl set the basics. |
| Sudo user | Creates the user, adds them to the sudo group, and installs your SSH public key. |
| SSH hardening | Drops a /etc/ssh/sshd_config.d/99-hardening.conf with PermitRootLogin no, PasswordAuthentication no, optional custom Port, and sane keepalive/auth limits. |
| UFW | Default-deny incoming, default-allow outgoing, allow your listed ports plus SSH. |
| fail2ban | Installs fail2ban with a sshd jail using the systemd backend. |
| Docker | Adds the official Docker apt repo and installs docker-ce, CLI, buildx, and compose plugin. |
| Unattended upgrades | Enables automatic installation of security updates via unattended-upgrades. |
| Swap file | Allocates /swapfile, enables it, persists in fstab, sets vm.swappiness=10. |
| sysctl hardening | SYN cookies, no ICMP redirects, no source routing, log martians, kernel pointer restrictions. |
How to run the script on a fresh VPS
- Configure the options on the left and click Download to save
setup.sh. - Copy it to your new server:
scp setup.sh root@your-server-ip:/root/
- SSH in and run it as root:
ssh root@your-server-ip bash setup.sh
- If you enabled Disable password auth or Change SSH port, your next SSH session must use the new user, key, and port. Test it in a second terminal before closing your root session.
Frequently Asked Questions
What is server hardening?
Should I disable root SSH login with password?
Is UFW enabled by default on Ubuntu?
How big should a swap file be on a Linux VPS?
How do unattended-upgrades work on Ubuntu?
Related Tools
Need to manage SSH connections?
SSH Workbench lets you connect, browse files, and manage servers visually.
Try SSH Workbench Free