Wolkra

How to secure an Ubuntu server

Updated

To secure an Ubuntu server, allow SSH with keys only, run a default-deny firewall, install security updates automatically, block repeated login failures, expose only the services you need, and keep tested backups. Those six steps stop the vast majority of attacks a public server sees.

The commands are for Ubuntu 24.04 LTS and work on Debian 12 with small differences. Run them as a user with sudo. If you have not done the basics yet, start with first steps on a new VPS.

1. Patch first, then stay patched

sudo apt update && sudo apt full-upgrade -y
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Check that the timer is active:

systemctl list-timers | grep apt

Security updates now install every day. Check now and then whether a reboot is pending with cat /var/run/reboot-required.

2. Lock down SSH

Keys only

Make sure your key works for a sudo user (see SSH keys). Then:

sudo tee /etc/ssh/sshd_config.d/10-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 20
X11Forwarding no
AllowUsers deploy
EOF
sudo sshd -t && sudo systemctl reload ssh
  • AllowUsers limits SSH to the accounts you name. Replace deploy with your user.
  • sshd -t validates the file; if it prints nothing, the syntax is good.

Test from a new terminal before you close the current one.

Check the effective settings

Drop-in files are read in order, and the first value wins. Confirm what sshd actually uses:

sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|allowusers'

If a cloud-init file such as 50-cloud-init.conf sets PasswordAuthentication yes, your 10- file is read first and wins.

3. Default-deny firewall with UFW

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit OpenSSH          # allow SSH, rate limit repeated attempts
sudo ufw allow 80,443/tcp       # only if you run a web server
sudo ufw enable
sudo ufw status numbered

ufw limit blocks an address that opens six or more connections in 30 seconds, which slows scanners.

UFW covers IPv6 as long as IPV6=yes is set in /etc/default/ufw (the default on Ubuntu).

Restrict SSH to your own addresses

If you connect from a fixed address, allow SSH only from there:

sudo ufw delete limit OpenSSH
sudo ufw allow from 198.51.100.0/24 to any port 22 proto tcp   # example range

Docker warning

Docker writes its own iptables rules, and published container ports bypass UFW. Bind containers to localhost (127.0.0.1:8080:80) and put a reverse proxy in front, or filter at the cloud firewall. The Docker Compose guide shows the pattern.

4. Add a cloud firewall in front

A firewall outside the server keeps working even if someone disables UFW, and one rule set can cover many servers. On Wolkra, firewalls are stateful, support inbound and outbound rules, apply to servers or label selectors and cost nothing. A typical rule set:

Direction Protocol Port Source
Inbound TCP 22 your office or VPN range
Inbound TCP 80, 443 any
Inbound ICMP – any

See firewalls in the docs for the steps.

5. Block brute force with Fail2ban

sudo apt install -y fail2ban python3-systemd
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd

[sshd]
enabled = true
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

backend = systemd reads the journal directly, which is how Ubuntu 24.04 logs SSH. Add your own address to ignoreip in [DEFAULT] so you never ban yourself.

6. Reduce what is listening

Every open port is something to patch. List them:

sudo ss -tulpn

For each line, ask whether it needs to be reachable from the internet. Databases, Redis and admin panels usually do not. Bind them to 127.0.0.1 or to a private network address, and remove packages you don't use:

sudo apt purge --autoremove <package>

7. Protect the kernel and network stack

Ubuntu's defaults are sensible. A few extra settings help on a public server:

sudo tee /etc/sysctl.d/90-hardening.conf >/dev/null <<'EOF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.tcp_syncookies = 1
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
EOF
sudo sysctl --system

Skip the redirect settings if the server routes traffic, for example as a VPN gateway.

8. Use sudo carefully

  • Give sudo only to people who need it: getent group sudo lists them.
  • Never put NOPASSWD: ALL on interactive accounts. Limit passwordless sudo to specific commands for automation.
  • Set a password on your sudo user even if SSH uses keys: sudo passwd deploy.

9. Watch logs and logins

last -n 20                          # recent logins
sudo journalctl -u ssh --since today
sudo journalctl -p err -b           # errors since boot

For file integrity and a quick audit, Lynis is a good start:

sudo apt install -y lynis
sudo lynis audit system

It prints a hardening index and a list of suggestions. Treat them as ideas, not orders.

The Wolkra console shows CPU, disk and network graphs per server (monitoring). A sudden traffic or CPU spike is often the first sign of a compromised service.

10. Secure the account, not only the server

Server hardening is wasted if someone can log in to your cloud account. In the Wolkra console:

  • turn on two-factor authentication (TOTP);
  • review active sessions and sign out old ones;
  • give team members the lowest role that works;
  • use API tokens that are read-only, IP-restricted and expiring where you can.

See account security and API tokens.

11. Back up, and test the restore

Security includes recovery. Enable daily backups or snapshots and keep at least one copy outside the server. Then restore once to a new server to prove it works. The backup strategy guide has a full plan.

Checklist

  • Automatic security updates on
  • SSH keys only, root login off, AllowUsers set
  • UFW default deny, only needed ports open
  • Cloud firewall in front, SSH limited to known ranges
  • Fail2ban running
  • Nothing unexpected in ss -tulpn
  • Sysctl hardening applied
  • Sudo limited, 2FA on the cloud account
  • Backups enabled and a restore tested

If something goes wrong while you tighten rules, the browser console and rescue mode in the server view get you back in without SSH.

Frequently asked questions

What is the most important step to secure an Ubuntu server?

Use SSH keys and disable password login. Most attacks on new servers are automated password guesses, and key-only login stops them.

Do I need Fail2ban if passwords are disabled?

It is less critical, but it still cuts log noise and slows scanners. It is also useful for web logins and other services that use passwords.

Should I change the SSH port?

It reduces log noise but is not real security. Restricting SSH to known source addresses with a firewall does far more.

Is UFW enough, or do I need a cloud firewall too?

UFW protects the server from inside. A cloud firewall filters traffic before it arrives and still works if someone breaks the server's own rules. Using both is a good default.

Do these steps work on Debian 12?

Almost all of them. Debian uses the same packages; install sudo and ufw first if they are missing.