Back to All ArticlesCloud & Infrastructure
Cloud & Infrastructure2026-10-068 min read1,385 views

The Production Linux VPS Hardening Checklist: From Fresh Install to Battle-Ready

A pragmatic runbook for securing a new Debian 12 or Ubuntu 24.04 instance before exposing ports to the public internet.

Share:𝕏 PostLinkedIn
The Production Linux VPS Hardening Checklist: From Fresh Install to Battle-Ready
The Production Linux VPS Hardening Checklist: From Fresh Install to Battle-Ready — Legion Mind Architecture Dispatch

Key Architecture Takeaways

  • Eliminate 99% of brute-force noise by disabling password authentication and moving the default SSH port.
  • Enforcing strict default-deny firewall posture with UFW rate limiting.
  • Configuring Fail2ban with escalating ban durations for repeated malicious login probes.
  • Setting up automated unattended security upgrades with off-peak automated reboots.

What Happens in the First 15 Minutes of a Public IP

The second a cloud provider assigns an IPv4 address to your new VPS, automated port scanners around the globe begin probing it. If you tail /var/log/auth.log on a brand new Ubuntu or Debian machine with port 22 open, you will see hundreds of brute-force login attempts every hour targeting default accounts (root, admin, ubuntu, test).

Leaving default credentials or password authentication enabled on a production server is asking for a compromised host.

Here is the exact baseline hardening checklist we apply to every production Linux VPS before deploying application containers or databases.

Production Linux VPS Security Hardening Checklist
Figure 1: Hardened Linux architecture overview with firewall, fail2ban, and automated security patching.

1. Create a Non-Root User & Sudo Rights

Never use the root account for routine day-to-day operations or CI/CD deployments. Create a dedicated administrative user and grant it sudo privileges:

BASH
# Add administrative user
adduser deployer

# Grant sudo access
usermod -aG sudo deployer

# Copy your local ed25519 SSH public key to the new user
mkdir -p /home/deployer/.ssh
chmod 700 /home/deployer/.ssh
cp /root/.ssh/authorized_keys /home/deployer/.ssh/
chown -R deployer:deployer /home/deployer/.ssh
chmod 600 /home/deployer/.ssh/authorized_keys

Test logging in with your new deployer account in a separate terminal window before closing your root session.


2. Lock Down OpenSSH: No Passwords, Custom Port

Password authentication is the primary vector for brute-force compromise. Modern ed25519 SSH keys provide superior cryptographic security and resist automated dictionary attacks.

Edit /etc/ssh/sshd_config.d/99-hardening.conf:

INI
# Change default port to reduce automated script noise by 95%
Port 2222

# Completely disable password authentication
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no

# Disable direct root login
PermitRootLogin no

# Only allow ed25519 and modern RSA keys
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# Disconnect idle sessions after 10 minutes
ClientAliveInterval 300
ClientAliveCountMax 2

# Disable insecure X11 forwarding
X11Forwarding no

Test and reload the SSH service:

BASH
sshd -t && systemctl restart ssh

3. Strict Firewall Posture with UFW

A fundamental security principle is default-deny. Nothing should enter your server unless an explicit firewall rule permits it.

BASH
# Set baseline policies
ufw default deny incoming
ufw default allow outgoing

# Allow your custom SSH port (rate-limited)
ufw limit 2222/tcp comment 'Hardened SSH port with rate limiting'

# Allow standard web traffic
ufw allow 80/tcp comment 'HTTP traffic (Let's Encrypt / Redirects)'
ufw allow 443/tcp comment 'HTTPS web traffic'

# Enable firewall
ufw enable
ufw status verbose

ufw limit automatically rate-limits connections to your SSH port, denying IPs that attempt more than 6 connections within 30 seconds.


4. Automated Intrusion Prevention with Fail2ban

Even on a custom SSH port, persistent bots will eventually probe your endpoints. Fail2ban inspects system logs and dynamically writes temporary iptables/nftables ban rules for abusive IPs.

Install and configure Fail2ban:

BASH
apt-get update && apt-get install -y fail2ban

Create /etc/fail2ban/jail.local:

INI
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd

[sshd]
enabled = true
port = 2222
mode = aggressive
bantime.increment = true
bantime.factor = 2

bantime.increment = true ensures that repeat offenders face escalating ban durations—from 1 hour to 2 hours, then 4 hours, and up to several days.


5. Automated Security Patching with Unattended-Upgrades

Zero-day kernel and library vulnerabilities (like OpenSSL or glibc exploits) require rapid patching. You should not have to log into every VPS manually every morning to run apt upgrade.

BASH
apt-get install -y unattended-upgrades update-notifier-common
dpkg-reconfigure -plow unattended-upgrades

Configure /etc/apt/apt.conf.d/50unattended-upgrades:

INI
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};

// Automatically remove unused kernel packages
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Auto-reboot at 03:30 AM only if a kernel patch requires it
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:30";

This guarantees that security updates install automatically as soon as Debian or Ubuntu publishes them, while deferring necessary system reboots to off-peak hours.

Server Security Audit Metrics
Firewall, Fail2ban, and automated patch status verified on production nodes
Bare Metal Production Topology
Hardened multi-tenant production node layout with rootless OCI isolation

6. Kernel Hardening with sysctl

Add these baseline networking and memory optimizations to /etc/sysctl.d/99-hardening.conf:

INI
# Protect against SYN flood denial of service attacks
net.ipv4.tcp_syncookies = 1

# Ignore ICMP echo broadcasts (ping of death mitigation)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Disable IP packet forwarding (unless this node is a router/VPN gateway)
net.ipv4.ip_forward = 0

# Do not accept ICMP redirects (prevents MITM route poisoning)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# Reduce aggressive swapping to preserve SSD lifespan and latency
vm.swappiness = 10

# Increase maximum file descriptors for high-concurrency web traffic
fs.file-max = 2097152

Apply immediately without rebooting:

BASH
sysctl --system

Verification

Once completed, verify your posture from your local development machine:

BASH
# Verify port 22 is blocked
nc -zv <your-server-ip> 22

# Verify custom SSH port works
ssh -p 2222 deployer@<your-server-ip>

Taking 20 minutes to apply this baseline configuration eliminates over 99% of automated Internet noise, keeping your cloud instances stable, resilient, and secure.

Found this architecture guide useful?Share this dispatch with your engineering team
Share:𝕏 PostLinkedIn
Field Engineering Dispatches

Production Runbooks & Architecture Notes

Monthly technical dispatches covering Linux VPS hardening, strict DMARC deliverability, Next.js optimization, and cloud operations. Zero sales fluff.

Need direct help implementing this stack?

Our principal engineers audit and configure infrastructure with guaranteed SLAs.