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

SectionWhat it does
System updateRuns apt-get update && apt-get upgrade non-interactively.
Hostname & timezonehostnamectl and timedatectl set the basics.
Sudo userCreates the user, adds them to the sudo group, and installs your SSH public key.
SSH hardeningDrops a /etc/ssh/sshd_config.d/99-hardening.conf with PermitRootLogin no, PasswordAuthentication no, optional custom Port, and sane keepalive/auth limits.
UFWDefault-deny incoming, default-allow outgoing, allow your listed ports plus SSH.
fail2banInstalls fail2ban with a sshd jail using the systemd backend.
DockerAdds the official Docker apt repo and installs docker-ce, CLI, buildx, and compose plugin.
Unattended upgradesEnables automatic installation of security updates via unattended-upgrades.
Swap fileAllocates /swapfile, enables it, persists in fstab, sets vm.swappiness=10.
sysctl hardeningSYN cookies, no ICMP redirects, no source routing, log martians, kernel pointer restrictions.

How to run the script on a fresh VPS

  1. Configure the options on the left and click Download to save setup.sh.
  2. Copy it to your new server:
    scp setup.sh root@your-server-ip:/root/
  3. SSH in and run it as root:
    ssh root@your-server-ip
    bash setup.sh
  4. 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

Need to manage SSH connections?

SSH Workbench lets you connect, browse files, and manage servers visually.

Try SSH Workbench Free