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
rsync Command Builder
Build rsync commands visually. Local or remote source/destination, flag toggles, exclude patterns, and presets.
rsync Flag Explainer
Paste any rsync command and instantly see what every flag does, with risky-flag warnings.
Firewall Rule Generator
Cross-platform firewall rule builder (UFW, iptables, nftables, Windows, AWS, GCP). Also explains existing rules.
iptables to nftables
Convert iptables rules to nftables. Translates chains, NAT, conntrack, and common matchers.
Docker Compose Generator
Build docker-compose.yml visually. Add services, volumes, networks, env vars — with live YAML and lint warnings.
Need to manage SSH connections?
SSH Workbench lets you connect, browse files, and manage servers visually.
Try SSH Workbench Free