TunnelFleet
Secure a VPS: A Practical Checklist
Security 10 min read 1 views

Secure a VPS: A Practical Checklist

Table of Contents

A new Ubuntu VPS is reachable from the entire internet within minutes of creation. Scanners will find SSH, probe common ports, and try credential stuffing whether you are ready or not. Hardening is not a compliance ritual—it is the minimum so you can run WireGuard or any other service without becoming an easy foothold.

This checklist is ordered for a fresh Ubuntu 22.04 or 24.04 LTS cloud host (including DigitalOcean Droplets). Apply it before you expose application ports. You can finish the baseline in under an hour on a single server.

The goal is a boring, defendable host: key-based SSH, least privilege, firewall default deny, timely patches, basic intrusion throttling, and enough logging to investigate later.

What You'll Learn

  • A prioritized order of operations that avoids lockouts
  • SSH, user, and sudo baseline controls
  • Firewall and provider security group alignment
  • Automatic security updates and package hygiene
  • Fail2Ban, time sync, and logging essentials
  • What to postpone until after the VPN or app is up

Before You Change Anything

  1. Confirm you can log in with an SSH key.
  2. Open a second SSH session before restarting sshd or enabling UFW.
  3. Note the provider console/serial access path (DigitalOcean Recovery/Console) in case you lock yourself out.
  4. Record the server’s public IPv4 (and IPv6 if enabled).

1. Patch the System First

sudo apt update
sudo apt upgrade -y
sudo reboot   # if the kernel updated

Install unattended upgrades:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Confirm:

cat /etc/apt/apt.conf.d/20auto-upgrades

Security updates should install automatically. Reboots after kernel updates still need a maintenance habit—unattended upgrades will not always reboot for you unless you configure that explicitly.

2. Create a Non-Root Admin User

sudo adduser deploy
sudo usermod -aG sudo deploy

Copy authorized keys:

sudo rsync --archive --chown=deploy:deploy /root/.ssh/ /home/deploy/.ssh/

Log in as deploy in a new session and verify sudo -v works before disabling root SSH login.

3. Harden SSH (Minimum Viable)

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

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
AllowTcpForwarding no
MaxAuthTries 3
LoginGraceTime 30
AllowUsers deploy

Validate and reload:

sudo sshd -t
sudo systemctl reload ssh

Only set AllowUsers after your admin account works. If you use cloud-init injected keys on root only, migrate keys first.

Prefer ed25519 keys:

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519_vps

4. Configure the Host Firewall (UFW)

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose

Add application ports only when needed. For WireGuard later:

sudo ufw allow 51820/udp comment 'WireGuard'

5. Align Provider Firewalls

On DigitalOcean, a Cloud Firewall can restrict inbound traffic before it hits the Droplet. Mirror the host policy:

  • Allow TCP 22 from your admin IP CIDRs when practical
  • Allow VPN UDP when you deploy WireGuard
  • Deny everything else inbound

Misaligned layers cause “mysterious” timeouts. Treat provider firewall and UFW as one design.

6. Disable Unused Services

systemctl list-units --type=service --state=running

Stop and disable what you do not need. Fresh Ubuntu cloud images are relatively lean; still remove leftover agents you will not use. Every listening socket is inventory.

sudo ss -tulpn

7. Configure Time Synchronization

Correct time matters for logs, TLS, and correlating incidents:

timedatectl status
sudo timedatectl set-ntp true

Ubuntu 24.04 typically uses systemd-timesyncd. Ensure it is active.

8. Install Fail2Ban for SSH

sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Create /etc/fail2ban/jail.d/sshd.local:

[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 YOUR.ADMIN.IP
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Fail2Ban complements key-only SSH; it does not replace it. It reduces log noise and slows password scanners if something re-enables passwords by mistake.

9. Kernel and Network Sysctl Baseline

Create /etc/sysctl.d/99-hardening.conf:

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

Apply:

sudo sysctl --system

If this host will route VPN traffic, you will later enable net.ipv4.ip_forward=1. Forwarding is a deliberate exception, not a default for non-router hosts.

10. Shared Memory and Temporary Directories (Optional Tightening)

For multi-user or higher assurance hosts, review /etc/fstab options for /tmp (noexec,nodev,nosuid) carefully—some installers break with noexec on /tmp. Apply only if you understand application needs.

11. Logging and Retention

Ensure rsyslog or journald is healthy:

journalctl -u ssh -n 20 --no-pager
sudo journalctl --disk-space

Decide where logs live. For a single VPS, persistent journal plus occasional off-box copy is a start. For fleets, ship to a central store. Do not disable auth logging to “reduce noise.”

12. Swap and Resource Sanity

Small Droplets can OOM under spikes. Check:

free -h

Add swap if you have less than 2 GB RAM and expect bursts—but treat swap as a safety net, not capacity planning.

13. Automatic Reboot Policy (Decide Explicitly)

Either:

  • Schedule maintenance windows and reboot after kernel updates, or
  • Configure unattended-upgrades to reboot when required (Automatic-Reboot settings)

Silent forever-uptime with an outdated kernel is not a security posture.

14. Backup and Recovery Path

Before production data exists:

  • Snapshot the Droplet after baseline hardening
  • Store WireGuard private keys and SSH keys outside the VPS with restricted access
  • Document rebuild steps (cloud-init or your provisioning tool)

Security without recovery still fails the business test.

15. Application and VPN Ports Last

Only after SSH, firewall, updates, and users are sane:

  • Install WireGuard or OpenVPN
  • Open the specific UDP/TCP ports required
  • Re-check ss -tulpn and UFW status

Do not open 0.0.0.0/0 to management UIs “temporarily.” Temporary rules become permanent.

Hardening Checklist (Copy/Paste)

  • apt update && apt upgrade completed
  • Unattended security upgrades enabled
  • Non-root sudo user created; key auth verified
  • Root SSH login disabled; passwords disabled
  • UFW default deny; SSH allowed; enabled
  • Provider firewall matches host policy
  • ss -tulpn reviewed; extras disabled
  • NTP/time sync OK
  • Fail2Ban jail for sshd enabled; admin IP ignored
  • Baseline sysctl applied
  • Snapshot or rebuild notes stored
  • Only required app/VPN ports open

Day-Two Habits That Keep the Baseline Intact

Hardening decays when the next install quietly opens ports or adds users.

After every package that listens on the network, re-run:

sudo ss -tulpn
sudo ufw status numbered

After every staffing change, edit authorized_keys and AllowUsers. Remove keys the same day someone loses access—not during the next audit.

After kernel updates, reboot in a maintenance window and confirm SSH, UFW, WireGuard, and Fail2Ban all returned:

systemctl is-active ssh ufw fail2ban
systemctl is-active wg-quick@wg0   # if installed

Monthly, skim auth logs for unexpected successes:

sudo journalctl -u ssh --since '30 days ago' | grep -i accepted | tail -n 50

Unexpected accepted logins are incident signals. Pure failure noise is normal on port 22; successes from unknown IPs are not.

Minimal Monitoring Without a Platform

You do not need a full observability stack on day one. You do need signals:

  • DigitalOcean bandwidth graphs for egress VPN nodes (sudden spikes)
  • Disk free space (df -h) before logs fill the disk and hide evidence
  • fail2ban-client status sshd after you expose SSH widely
  • A calendar reminder for domain and TLS renewals if any HTTPS lands on the host

When you grow past a handful of servers, centralize logs and inventory. Until then, boring shell checks beat unread dashboards.

Secrets and Access Hygiene

  • Store SSH private keys and WireGuard private keys outside the VPS backups you share casually
  • Prefer agent forwarding only when necessary; prefer ProxyJump with explicit configs
  • Never put production private keys in chat, tickets, or world-readable home directories
  • Rotate keys when a laptop is lost, not only when a CVE drops

A hardened sshd with a leaked laptop key is still a compromised host. Physical and endpoint security are part of the VPS checklist whether you like it or not.

Best Practices

  • Prefer allowlisting admin SSH by source IP at the cloud firewall when your IP is stable
  • Use separate SSH keys per operator; revoke by removing authorized_keys lines
  • Keep sudoers lean; avoid NOPASSWD unless automation requires it and is locked down
  • Re-run ss -tulpn after every major install
  • Treat provider API tokens and SSH keys as production secrets
  • Rebuild from known-good images periodically instead of endless snowflake patching when drift grows
  • For VPN egress nodes, monitor bandwidth—compromise often shows up as traffic anomalies

Common Mistakes

  • Enabling UFW before allowing SSH
  • Disabling password auth before confirming key login in a second session
  • Hardening SSH then never opening provider firewall for UDP VPN ports
  • Leaving PermitRootLogin yes because cloud-init made it convenient
  • Installing Fail2Ban but not whitelisting your own IP, then testing from that IP
  • Calling the host “secure” because a web scanner is clean while SSH passwords remain on
  • Forwarding enabled on hosts that are not routers/VPN gateways
  • No offline copy of recovery procedure

FAQ

Is this checklist enough for compliance frameworks?

It is a practical baseline for self-hosted infrastructure, not a SOC 2 evidence package. Frameworks need policies, access reviews, and continuous control proof beyond a single host guide.

Should I change the SSH port?

Moving off port 22 reduces noisy logs but is not strong security. Key-only auth, allowlists, and Fail2Ban matter more. If you change ports, update UFW and cloud firewalls together.

Do I need SELinux or AppArmor tuning?

Ubuntu ships AppArmor. Keep it enabled. Custom profiles are advanced work—do not disable AppArmor “to make installs easier” on production VPN hosts.

What about IPv6?

If IPv6 is enabled on the VPS, firewall it. UFW IPv6 support should stay on (IPV6=yes in /etc/default/ufw). An open IPv6 stack with a locked-down IPv4-only mental model is a classic hole.

Can I skip Fail2Ban with key-only SSH?

You can, but Fail2Ban is cheap insurance against misconfigurations and reduces brute-force log spam. Keep it unless you have an equivalent control.

How often should I revisit hardening?

After every major role change (new public service), quarterly for sysctl/SSH review, and immediately after staff turnover for authorized_keys cleanup.

Summary

Secure a VPS by working in a safe order: patch, admin user, SSH keys only, firewall, provider rules, disable unused listeners, time sync, Fail2Ban, sysctl baseline, then application ports. Verify each control before tightening the next so you do not lock yourself out.

A hardened Ubuntu host will still be scanned. The difference is whether those scans become a problem or background noise.

If you want to automate VPN server deployment instead of configuring everything manually, TunnelFleet helps you provision and manage VPN infrastructure on your own cloud provider with minimal manual setup.

Tags: Self Hosting Ubuntu Security VPS DevOps Hardening SSH Firewall

Share this article

T

Practical guides on VPN infrastructure, server automation, and self-hosted networking from the TunnelFleet team.

View all articles by TunnelFleet Editorial →

Related Articles