A fresh Ubuntu VPS is not a secure Ubuntu VPS. Out of the box, it accepts password logins over SSH, root is a valid login target, and nothing is blocking brute-force attempts. Bots start scanning new IP addresses within minutes of them going online — this isn't paranoia, it's measurable fact.
This guide gets you from "freshly provisioned" to "sensible production baseline" in under 30 minutes. Run these steps before you deploy anything.
Why this matters before deployment
Most VPS compromises happen not through clever exploits, but through:
- Password-based SSH brute force — automated bots try thousands of password combinations
- Root login over SSH — if root can log in directly, a successful brute force owns everything
- Unpatched packages — known CVEs with public exploits
- Open ports that shouldn't be public
All four are addressed below.
Step 1: Update packages immediately
The first thing to do on any new server is patch it. Every day between OS image creation and now, security updates have been released:
bashsudo apt update && sudo apt upgrade -y sudo apt autoremove -y
This closes known vulnerabilities before you install anything else. Don't skip it.
Step 2: Create a non-root admin user
Never use root for day-to-day operations. Create a dedicated admin user:
bashsudo adduser opsadmin sudo usermod -aG sudo opsadmin id opsadmin
From now on, log in as opsadmin. Use sudo when you need elevated access. Root stays locked as a recovery fallback only.
Replace opsadmin with whatever username makes sense for you — but make it something that isn't admin, ubuntu, or deploy, which are commonly targeted.
Step 3: Set up SSH key authentication
SSH keys are fundamentally more secure than passwords. A key pair is cryptographically strong in a way no human-chosen password is. Generate one on your local machine if you don't have one:
bash# On your LOCAL machine (not the server): ssh-keygen -t ed25519 -C "[email protected]"
Then copy your public key to the server:
bashssh-copy-id opsadmin@your-server-ip
Or manually:
bash# On the server, as opsadmin: mkdir -p ~/.ssh chmod 700 ~/.ssh nano ~/.ssh/authorized_keys # Paste your public key, save chmod 600 ~/.ssh/authorized_keys
Test that key login works before the next step. Open a new terminal and confirm you can connect:
bashssh opsadmin@your-server-ip
Only proceed once this works. If you disable password auth before testing keys, you can lock yourself out.
Step 4: Disable password SSH login and root access
Now that key auth is working, harden the SSH configuration:
bashsudo nano /etc/ssh/sshd_config
Find and set these values (add them if they don't exist):
bashPermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys
Apply the changes:
bashsudo systemctl restart ssh
Test again from a new terminal. If you can still connect with your key, you're good. Any password-based login attempt will now be rejected.
Step 5: Configure UFW firewall
UFW (Uncomplicated Firewall) is the right tool for VPS firewall rules on Ubuntu. The principle is simple: block everything incoming by default, then explicitly allow only what you need.
bashsudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow OpenSSH sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable sudo ufw status verbose
Important: Run sudo ufw allow OpenSSH before enabling the firewall. If you enable UFW without allowing SSH, you lock yourself out immediately.
Output should show:
bashStatus: active To Action From -- ------ ---- OpenSSH ALLOW IN Anywhere 80/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere
If you have other services (custom SSH port, mail, etc.), add rules before enabling.
Step 6: Install fail2ban
UFW blocks ports. fail2ban blocks IPs. These are complementary, not redundant.
fail2ban watches your SSH logs and automatically bans IP addresses that fail authentication too many times — by default, 5 failures in 10 minutes triggers a ban:
bashsudo apt install fail2ban -y sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd
Output should show Number of currently banned: 0 (or more, if bots have already tried). Check back after 24 hours — you'll typically see dozens of banned IPs.
To customize the ban threshold, create a local config:
bashsudo nano /etc/fail2ban/jail.local
ini[sshd] enabled = true maxretry = 3 bantime = 3600 findtime = 600
This bans after 3 failures (instead of 5) for 1 hour. Adjust to your preference.
bashsudo systemctl restart fail2ban
Step 7: Enable unattended security updates
You won't always be available to apply patches the day they're released. Set up automatic security updates so critical fixes are applied even when you're busy:
bashsudo apt install unattended-upgrades -y sudo dpkg-reconfigure --priority=low unattended-upgrades
Select "Yes" when prompted. This enables automatic installation of security-only updates. Major version upgrades still require manual approval.
Verify it's configured:
bashcat /etc/apt/apt.conf.d/20auto-upgrades
You should see:
bashAPT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1";
Step 8: Verify your baseline
Run these checks to confirm everything is in place:
bash# Who are you? whoami # What ports are listening? sudo ss -tulpen # Firewall status sudo ufw status # fail2ban status sudo systemctl status fail2ban --no-pager # Are automatic updates enabled? cat /etc/apt/apt.conf.d/20auto-upgrades
What you want to see:
whoamireturns your non-root userss -tulpenshows only ports you intended to open- UFW shows active with your allow rules
- fail2ban shows active (running)
- Auto-upgrades shows both values as "1"
What this baseline doesn't cover
This gets you to a sensible starting point, not a hardened government server. Depending on your use case, you may also want:
- Custom SSH port — obscures your SSH from port-scanning bots (not real security, but reduces log noise)
- Two-factor authentication for SSH — for high-security environments
- Intrusion detection (AIDE, Lynis) — for compliance or high-value targets
- Log aggregation — shipping logs off-server so they survive a compromise
For most business VPS deployments, the baseline in this guide is sufficient. Revisit it quarterly or before major deployments.
Monthly maintenance habit
Security baseline isn't one-and-done. Add a monthly check to your calendar:
bashsudo apt update && sudo apt upgrade -y sudo fail2ban-client status sshd sudo ufw status sudo ss -tulpen
Five minutes a month catches drift before it becomes a problem.
Running this on a HostAccent VPS? Our Ubuntu VPS plans come with clean base images — ready for this exact setup from first login.











Discussion
Have a question or tip about this topic? Share it below — your comment will appear after review.