Security

Secure your VPS: firewall, SSH keys & fail2ban

A freshly provisioned VPS is exposed to the public internet within seconds. Automated bots scan all IPv4 addresses and attempt to log in via SSH continuously. This guide covers the essential hardening steps every VPS — whether you are running an AI agent, WordPress, or n8n — should have before you do anything else.

Do this first. Every other guide in this Learn hub assumes you have completed these steps. The whole process takes about 15 minutes.

Step 1 — Create a non-root sudo user

Running everything as root is dangerous — a single mistake can wipe the server. Create a regular user and grant it sudo access:

# As root (initial login):
adduser deploy
# Follow the prompts to set a password

usermod -aG sudo deploy

# Verify
su - deploy
sudo whoami   # should print: root

Step 2 — SSH key authentication

SSH keys are far more secure than passwords. Generate a key pair on your local machine (if you don't already have one), then copy the public key to the server:

# Generate an Ed25519 key pair (if needed)
ssh-keygen -t ed25519 -C "your@email.com"

# Copy the public key to the server
ssh-copy-id deploy@YOUR_SERVER_IP
# Or manually:
cat ~/.ssh/id_ed25519.pub | ssh root@YOUR_SERVER_IP "mkdir -p /home/deploy/.ssh && cat >> /home/deploy/.ssh/authorized_keys && chmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys && chown -R deploy:deploy /home/deploy/.ssh"

Step 3 — Harden SSH configuration

Disable password authentication and root login. Optionally move SSH to a non-standard port to reduce automated scan noise:

sudo nano /etc/ssh/sshd_config
# Change or uncomment these lines:
Port 2222                    # Optional: non-standard port
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

sudo systemctl restart sshd

# IMPORTANT: keep your current session open while you verify
# the new config works in a second terminal window first!

If you changed the port, log in with ssh -p 2222 deploy@YOUR_SERVER_IP in a second terminal before closing your existing session.

Step 4 — Configure UFW firewall

UFW (Uncomplicated Firewall) wraps iptables in a simple interface. Allow only the ports your server needs:

sudo apt install -y ufw

# Default: deny all incoming, allow all outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (use your custom port if you changed it)
sudo ufw allow 2222/tcp comment 'SSH'
# Or: sudo ufw allow 22/tcp comment 'SSH'

# Allow web traffic
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# Enable the firewall
sudo ufw enable
sudo ufw status verbose

Only open additional ports as you actually need them — for example port 5432 for PostgreSQL should only ever be open to specific trusted IPs, never to the world.

Step 5 — Install fail2ban

fail2ban watches your log files and automatically bans IPs that show signs of brute-force activity (too many failed SSH attempts):

sudo apt install -y fail2ban

# Create a local override — never edit jail.conf directly
sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
port    = 2222
# Change port to match your SSH port
EOF

sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

# View currently banned IPs
sudo fail2ban-client status sshd

Step 6 — Unattended security upgrades

Most server compromises exploit known, patched vulnerabilities. Automate security-only package updates so you do not fall behind:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Select "Yes" to enable automatic updates

# Verify the configuration
cat /etc/apt/apt.conf.d/20auto-upgrades

Step 7 — Basic monitoring

Know when something goes wrong. A lightweight first step is setting up logwatch for daily email digests, or checking the authentication log for suspicious activity:

# Watch auth log for failed logins
sudo journalctl -u sshd --since "1 hour ago" | grep "Failed"

# Check fail2ban bans
sudo fail2ban-client status sshd

# Install htop for real-time resource monitoring
sudo apt install -y htop
htop

For production workloads, consider a lightweight agent like netdata (open-source, zero config, web dashboard) or vector for log shipping to your alerting stack.

Want this done for you?

AgentOcean VPS plans are provisioned with these hardening steps applied by default — SSH keys only, UFW enabled, fail2ban running. Skip the setup and go straight to deploying your app.

Related