VPS Hardening Checklist 2026: 30 Essential Security Steps for Your Production Server

Why Your Production Server Needs a Hardening Checklist

A freshly provisioned VPS is vulnerable by default. Default SSH passwords, open ports, unnecessary services, and misconfigured firewalls are the most common entry points for attackers. According to the 2026 Verizon Data Breach Investigations Report, 68% of server compromises involving VPS instances could have been prevented by following a structured hardening checklist. This guide provides 30 essential security steps organized by priority, with specific commands and configurations for Ubuntu 24.04 LTS and Debian 12 — the most common VPS operating systems in 2026.

Before you begin, ensure your provider supports the security features discussed here. Compare VPS providers on our performance comparison table to confirm your host offers features like encrypted boot volumes, DDoS protection, and firewall-as-a-service.

Phase 1: Immediate Access Hardening (Steps 1–8)

1. Disable Root SSH Login

Root login via SSH is the most targeted attack vector. Create a sudo user and disable root SSH access:

adduser deploy
usermod -aG sudo deploy
# Then edit /etc/ssh/sshd_config:
# PermitRootLogin no

2. Enforce SSH Key Authentication Only

Disable password authentication entirely. Ed25519 keys are now the recommended standard over RSA 4096:

# On your local machine
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/vps_key

# On the server, edit /etc/ssh/sshd_config:
# PasswordAuthentication no
# PubkeyAuthentication yes
# AuthenticationMethods publickey

3. Change Default SSH Port

Moving SSH off port 22 reduces automated attack volume by 95%+:

# In /etc/ssh/sshd_config:
# Port 2222
# Then update your firewall rules accordingly

4. Configure Fail2ban for SSH

Fail2ban adds rate-limiting to SSH attempts, blocking IPs after configurable thresholds:

sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.{conf,local}
# In /etc/fail2ban/jail.local:
# [sshd]
# enabled = true
# port = 2222
# maxretry = 3
# bantime = 3600

sudo systemctl enable --now fail2ban

5. Set Up UFW with Minimal Rules

Uncomplicated Firewall (UFW) provides a simple interface to iptables/nftables:

ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
ufw --force enable

6. Disable Unused Network Services

Audit and stop any services not required for production:

# List listening services
ss -tulpn

# Common services to disable if unused:
# sudo systemctl disable --now cups.service avahi-daemon.service postfix.service

7. Harden SSH Cipher Configuration

Use only modern, secure SSH ciphers in /etc/ssh/sshd_config:

Ciphers [email protected],[email protected]
KexAlgorithms [email protected],diffie-hellman-group16-sha512
MACs [email protected],[email protected]

8. Enable SSH Two-Factor Authentication

For production servers with administrative access, enable TOTP-based 2FA:

sudo apt install -y libpam-google-authenticator
google-authenticator
# In /etc/pam.d/sshd add: auth required pam_google_authenticator.so
# In /etc/ssh/sshd_config: AuthenticationMethods publickey,keyboard-interactive

Phase 2: System Hardening (Steps 9–16)

9. Keep System Packages Updated

Configure automatic security updates to ensure critical patches are never missed:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Ensure only security updates are applied automatically
# Edit /etc/apt/apt.conf.d/50unattended-upgrades

10. Configure Kernel Hardening with sysctl

Add these sysctl settings to /etc/sysctl.d/99-hardening.conf:

# IP spoofing protection
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects=0
net.ipv6.conf.all.accept_redirects=0

# Disable source packet routing
net.ipv4.conf.all.accept_source_route=0
net.ipv6.conf.all.accept_source_route=0

# Enable TCP SYN cookie protection
net.ipv4.tcp_syncookies=1

# Protect against time-wait assassination
net.ipv4.tcp_rfc1337=1

11. Set Filesystem Permissions Correctly

# Restrict /etc/shadow and /etc/gshadow
sudo chmod 640 /etc/shadow /etc/gshadow

# Set secure umask
echo "umask 027" >> /etc/profile

# Restrict world-writable directories
find / -type d -perm -o+w -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null | grep -v '/tmp\|/var/tmp\|/dev/shm'

12. Install and Configure auditd

sudo apt install -y auditd audispd-plugins
# Monitor key system files
auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /etc/shadow -p wa -k shadow_changes
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config

13. Set Up Logwatch for Daily Log Review

sudo apt install -y logwatch
# Daily email summary of system activity
# Configure /etc/cron.daily/00logwatch

14. Restrict cron to Authorized Users

echo root > /etc/cron.allow
echo deploy >> /etc/cron.allow
chmod 600 /etc/cron.allow

15. Disable Unused Filesystems

Prevent attackers from exploiting less common filesystems by disabling them via /etc/modprobe.d/block-filesystems.conf:

install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install udf /bin/true

16. Secure Shared Memory

# In /etc/fstab:
tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0

Phase 3: Application & Service Hardening (Steps 17–24)

17. Run Web Server Under Dedicated User

Ensure Nginx/Apache runs as its own user (www-data) with minimal privileges. Never run applications as root.

18. Set Up a Web Application Firewall (WAF)

# Using Nginx + ModSecurity 3.0
sudo apt install -y libmodsecurity3 nginx-mod-security
# Enable OWASP Core Rule Set 4.0+
# See: https://coreruleset.org/

19. Implement Rate Limiting

# In Nginx:
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/s;
limit_req zone=login burst=10 nodelay;

# In UFW:
ufw limit 2222/tcp

20. Harden PHP Configuration

# In /etc/php/8.4/fpm/php.ini:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,show_source
expose_php = Off
open_basedir = /var/www/html:/tmp
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1

21. Configure Database Security

# MySQL/MariaDB secure installation
sudo mysql_secure_installation

# Bind to localhost only in /etc/mysql/mariadb.conf.d/50-server.cnf:
bind-address = 127.0.0.1

# Create application-specific user with minimal privileges
CREATE USER 'app'@'localhost' IDENTIFIED BY 'strong-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'localhost';

22. Enable HTTPS with Automatic Renewal

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
# Verify auto-renewal
sudo systemctl status certbot.timer

23. Set Up Intrusion Detection with AIDE

sudo apt install -y aide
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Run weekly checks
sudo aide --check

24. Configure AppArmor Profiles

sudo apt install -y apparmor apparmor-profiles apparmor-utils
sudo aa-status  # Check active profiles
sudo aa-enforce /usr/sbin/nginx  # Enforce Nginx profile

Phase 4: Monitoring & Incident Response (Steps 25–30)

25. Set Up Centralized Logging

Forward logs to a remote syslog server or a log aggregation service:

# In /etc/rsyslog.d/remote.conf
*.* @logs.example.com:514

26. Install and Configure CrowdSec

CrowdSec is the modern successor to Fail2ban, using a community-driven IP reputation database:

curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash
sudo apt install -y crowdsec
sudo cscli collections install crowdsecurity/nginx
sudo systemctl enable --now crowdsec

27. Monitor SSH Login Attempts

sudo journalctl -u ssh.service | grep 'Failed password'
# Set up a daily cron to report failed attempts:
sudo journalctl -u ssh.service --since yesterday | grep 'Failed password' | wc -l

28. Take Regular Snapshots and Backups

# Automate daily database dumps
echo "0 2 * * * mysqldump --all-databases | gzip > /backup/db-\$(date +\%Y\%m\%d).sql.gz" | crontab -
# Use provider snapshots or rsync to an off-site location

29. Create an Incident Response Plan

Document the steps to take if a compromise is detected:

  • Isolate the affected server by updating firewall rules to deny all inbound traffic except from your investigation machine
  • Take a forensic snapshot of the server before any cleanup
  • Rotate all credentials (SSH keys, database passwords, API tokens)
  • Review logs with ausearch and journalctl for the attack timeline
  • Restore from the last known-good backup after eliminating the root cause

30. Perform Regular Security Audits

Run automated security scanners monthly:

# Lynis security audit
sudo apt install -y lynis
sudo lynis audit system

# Rootkit detection
sudo apt install -y rkhunter
sudo rkhunter --check

# OpenSCAP compliance scanning
sudo apt install -y libopenscap8 openscap-scanner

Conclusion

Security hardening is not a one-time task — it is an ongoing process. Implement these 30 steps in order of priority, and automate the recurring checks (unattended upgrades, log review, AIDE integrity checks, CrowdSec) to ensure continuous protection. A properly hardened VPS can withstand 99% of automated attacks and significantly raises the bar for targeted intrusions.

For additional protection, choose a VPS provider that offers DDoS mitigation, encrypted boot volumes, and a built-in firewall. Compare VPS providers on our performance comparison table to find a host with enterprise-grade security features at budget-friendly prices.

Leave a Reply