Tools: How to Harden a Linux VPS in 30 Minutes (Production Checklist) (2026)

Tools: How to Harden a Linux VPS in 30 Minutes (Production Checklist) (2026)

How to Harden a Linux VPS in 30 Minutes (Production Checklist)

1. Update the System

2. Create a Non-Root User

3. Set Up SSH Key Authentication

4. Configure the Firewall

5. Fail2ban (Block Brute Force)

6. Disable Unused Services

7. Set Up Automatic Security Updates

8. Check for Open Ports

The Complete 30-Minute Checklist You just spun up a new VPS. Before you deploy anything, run through this checklist. These are the baseline hardening steps that prevent 90% of common attacks. Run this first. Always. Never run your app as root. Then disable password authentication: Test your SSH key login in a NEW terminal before closing your current session. Choose "yes" to enable automatic security updates. I built ARIA to solve exactly this.

Try it free at step2dev.com — no credit card needed. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y -weight: 600;">sudo -weight: 500;">apt autoremove -y -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y -weight: 600;">sudo -weight: 500;">apt autoremove -y -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y -weight: 600;">sudo -weight: 500;">apt autoremove -y # Add user adduser deploy # Give -weight: 600;">sudo access usermod -aG -weight: 600;">sudo deploy # Switch to new user su - deploy # Add user adduser deploy # Give -weight: 600;">sudo access usermod -aG -weight: 600;">sudo deploy # Switch to new user su - deploy # Add user adduser deploy # Give -weight: 600;">sudo access usermod -aG -weight: 600;">sudo deploy # Switch to new user su - deploy # On your LOCAL machine, generate a key if you don't have one ssh-keygen -t ed25519 -C "your-email@example.com" # Copy your public key to the server ssh-copy-id deploy@your-server-ip # Or manually: # cat ~/.ssh/id_ed25519.pub | ssh deploy@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" # On your LOCAL machine, generate a key if you don't have one ssh-keygen -t ed25519 -C "your-email@example.com" # Copy your public key to the server ssh-copy-id deploy@your-server-ip # Or manually: # cat ~/.ssh/id_ed25519.pub | ssh deploy@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" # On your LOCAL machine, generate a key if you don't have one ssh-keygen -t ed25519 -C "your-email@example.com" # Copy your public key to the server ssh-copy-id deploy@your-server-ip # Or manually: # cat ~/.ssh/id_ed25519.pub | ssh deploy@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" -weight: 600;">sudo nano /etc/ssh/sshd_config -weight: 600;">sudo nano /etc/ssh/sshd_config -weight: 600;">sudo nano /etc/ssh/sshd_config PasswordAuthentication no PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin no PubkeyAuthentication yes -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ufw -y # Deny everything by default -weight: 600;">sudo ufw default deny incoming -weight: 600;">sudo ufw default allow outgoing # Allow SSH (critical - don't forget this!) -weight: 600;">sudo ufw allow ssh # Allow HTTP and HTTPS -weight: 600;">sudo ufw allow 80/tcp -weight: 600;">sudo ufw allow 443/tcp # Enable -weight: 600;">sudo ufw -weight: 500;">enable -weight: 600;">sudo ufw -weight: 500;">status verbose -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ufw -y # Deny everything by default -weight: 600;">sudo ufw default deny incoming -weight: 600;">sudo ufw default allow outgoing # Allow SSH (critical - don't forget this!) -weight: 600;">sudo ufw allow ssh # Allow HTTP and HTTPS -weight: 600;">sudo ufw allow 80/tcp -weight: 600;">sudo ufw allow 443/tcp # Enable -weight: 600;">sudo ufw -weight: 500;">enable -weight: 600;">sudo ufw -weight: 500;">status verbose -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ufw -y # Deny everything by default -weight: 600;">sudo ufw default deny incoming -weight: 600;">sudo ufw default allow outgoing # Allow SSH (critical - don't forget this!) -weight: 600;">sudo ufw allow ssh # Allow HTTP and HTTPS -weight: 600;">sudo ufw allow 80/tcp -weight: 600;">sudo ufw allow 443/tcp # Enable -weight: 600;">sudo ufw -weight: 500;">enable -weight: 600;">sudo ufw -weight: 500;">status verbose -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y -weight: 600;">sudo nano /etc/fail2ban/jail.local -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y -weight: 600;">sudo nano /etc/fail2ban/jail.local -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y -weight: 600;">sudo nano /etc/fail2ban/jail.local [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start fail2ban # Check -weight: 500;">status -weight: 600;">sudo fail2ban-client -weight: 500;">status sshd -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start fail2ban # Check -weight: 500;">status -weight: 600;">sudo fail2ban-client -weight: 500;">status sshd -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start fail2ban # Check -weight: 500;">status -weight: 600;">sudo fail2ban-client -weight: 500;">status sshd # See what's running -weight: 600;">sudo -weight: 500;">systemctl list-units --type=-weight: 500;">service --state=running # Disable what you don't need -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable bluetooth -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable avahi-daemon -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable cups # printing -weight: 500;">service # See what's running -weight: 600;">sudo -weight: 500;">systemctl list-units --type=-weight: 500;">service --state=running # Disable what you don't need -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable bluetooth -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable avahi-daemon -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable cups # printing -weight: 500;">service # See what's running -weight: 600;">sudo -weight: 500;">systemctl list-units --type=-weight: 500;">service --state=running # Disable what you don't need -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable bluetooth -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable avahi-daemon -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">disable cups # printing -weight: 500;">service -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y -weight: 600;">sudo dpkg-reconfigure -plow unattended-upgrades -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y -weight: 600;">sudo dpkg-reconfigure -plow unattended-upgrades -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y -weight: 600;">sudo dpkg-reconfigure -plow unattended-upgrades # See all open ports -weight: 600;">sudo ss -tlnp # Compare against what you expect # Standard: 22 (SSH), 80 (HTTP), 443 (HTTPS) # Anything else should be intentional # See all open ports -weight: 600;">sudo ss -tlnp # Compare against what you expect # Standard: 22 (SSH), 80 (HTTP), 443 (HTTPS) # Anything else should be intentional # See all open ports -weight: 600;">sudo ss -tlnp # Compare against what you expect # Standard: 22 (SSH), 80 (HTTP), 443 (HTTPS) # Anything else should be intentional # 1. Update -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y # 2. Create non-root user adduser deploy && usermod -aG -weight: 600;">sudo deploy # 3. Set up SSH keys (from local machine) ssh-copy-id deploy@your-server # 4. Disable password auth -weight: 600;">sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd # 5. Firewall -weight: 600;">sudo ufw default deny incoming && -weight: 600;">sudo ufw allow ssh && -weight: 600;">sudo ufw allow 80/tcp && -weight: 600;">sudo ufw allow 443/tcp && -weight: 600;">sudo ufw -weight: 500;">enable # 6. Fail2ban -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y && -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban # 7. Auto updates -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y # 8. Verify open ports -weight: 600;">sudo ss -tlnp # 1. Update -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y # 2. Create non-root user adduser deploy && usermod -aG -weight: 600;">sudo deploy # 3. Set up SSH keys (from local machine) ssh-copy-id deploy@your-server # 4. Disable password auth -weight: 600;">sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd # 5. Firewall -weight: 600;">sudo ufw default deny incoming && -weight: 600;">sudo ufw allow ssh && -weight: 600;">sudo ufw allow 80/tcp && -weight: 600;">sudo ufw allow 443/tcp && -weight: 600;">sudo ufw -weight: 500;">enable # 6. Fail2ban -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y && -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban # 7. Auto updates -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y # 8. Verify open ports -weight: 600;">sudo ss -tlnp # 1. Update -weight: 600;">sudo -weight: 500;">apt -weight: 500;">update && -weight: 600;">sudo -weight: 500;">apt -weight: 500;">upgrade -y # 2. Create non-root user adduser deploy && usermod -aG -weight: 600;">sudo deploy # 3. Set up SSH keys (from local machine) ssh-copy-id deploy@your-server # 4. Disable password auth -weight: 600;">sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">restart sshd # 5. Firewall -weight: 600;">sudo ufw default deny incoming && -weight: 600;">sudo ufw allow ssh && -weight: 600;">sudo ufw allow 80/tcp && -weight: 600;">sudo ufw allow 443/tcp && -weight: 600;">sudo ufw -weight: 500;">enable # 6. Fail2ban -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install fail2ban -y && -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">enable fail2ban # 7. Auto updates -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install unattended-upgrades -y # 8. Verify open ports -weight: 600;">sudo ss -tlnp