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, so 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?
Server hardening is the process of reducing a server's attack surface by removing unnecessary services, locking down configurations, and applying security patches. On a fresh Ubuntu or Debian VPS this typically means: creating a non-root user with SSH key auth, disabling root SSH and password authentication, enabling a firewall (UFW), installing fail2ban to block brute-force attempts, turning on automatic security updates, and applying kernel/network sysctl tweaks. The script generated above performs all of those steps in one run.
Should I disable root SSH login with password?
Yes. Allowing root over SSH with a password is one of the highest-risk default settings on a Linux server. Botnets continuously brute-force port 22 looking for weak root passwords. Best practice is to (1) create a non-root sudo user, (2) install your SSH public key for that user, (3) set PermitRootLogin no and PasswordAuthentication no in sshd_config. Always test your key-based login in a second terminal before closing the session that disabled password auth, otherwise you can lock yourself out.
Is UFW enabled by default on Ubuntu?
No. UFW (Uncomplicated Firewall) is installed by default on Ubuntu Server but is not enabled. You have to turn it on explicitly with ufw enable. Critically, you must allow your SSH port before enabling UFW, otherwise the next time you reconnect you will be locked out. The generated script handles this for you: it always allows the active SSH port (whether 22 or your custom port) before running ufw --force enable.
How big should a swap file be on a Linux VPS?
For most cloud VPS workloads a swap file of 1-2x your RAM is reasonable, capped at around 4-8 GB. A 1 GB VPS commonly uses 1-2 GB of swap, a 2 GB VPS uses 2-4 GB, and beyond ~8 GB of RAM most servers do not need much swap at all unless they hibernate (which VPSes do not). Set vm.swappiness=10 (the script does this) so the kernel only uses swap under real memory pressure rather than aggressively swapping idle pages out.
How do unattended-upgrades work on Ubuntu?
unattended-upgrades is an Ubuntu/Debian package that runs in the background and automatically installs updates from configured origins (by default, just the -security pocket). It runs daily via the apt systemd timer (apt-daily.timer and apt-daily-upgrade.timer), checks the allowed origins listed in /etc/apt/apt.conf.d/50unattended-upgrades, and applies matching updates. The script enables it with security-only origins and leaves automatic reboot off, which is the safest production default.
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, and 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