Skip to content
Cloudj

VPS how-to

UFW firewall on an Ubuntu VPS: setup without locking out

Set up a UFW firewall on an Ubuntu or Debian VPS: default deny, allow SSH first, common rules for web and databases, rate limiting and how to check it.

Updated · 5 min read

A UFW firewall is the simplest way to protect an Ubuntu or Debian VPS. UFW (Uncomplicated Firewall) is a front end for the kernel's packet filter that turns rules like "allow SSH, allow HTTPS, block everything else" into one-line commands. The only real danger is the order of steps: enable it before allowing SSH and you cut off your own connection. This guide follows the safe order, then covers the rules most servers need, rate limiting, and the Docker gotcha that surprises many people.

How a UFW firewall decides

UFW applies a default policy to anything that does not match a rule, and checks rules in the order they were added. The usual setup for a server is:

  • Incoming: deny by default. Only ports you explicitly allow are reachable.
  • Outgoing: allow by default. The server can still fetch updates, call APIs and send mail.
  • Explicit allows for the few services you run, such as SSH, HTTP and HTTPS.

That is it. Most mistakes come from allowing too much ("allow from anywhere to the database") rather than too little.

Step 1: install and check the status

UFW ships with Ubuntu but is inactive by default. On Debian, install it first.

sudo apt update
sudo apt install -y ufw
sudo ufw status

You should see Status: inactive. Do not enable it yet.

Step 2: set the default policies

sudo ufw default deny incoming
sudo ufw default allow outgoing

These commands do not take effect until the firewall is enabled, so they are safe to run over SSH.

Step 3: allow SSH before anything else

This is the step that prevents a lockout. Use the limit rule rather than a plain allow, which also gives you basic brute-force protection (see below):

sudo ufw limit OpenSSH

OpenSSH is an application profile that means TCP port 22. If you moved SSH to another port, use the number instead, for example sudo ufw limit 2222/tcp. List available profiles with sudo ufw app list.

If you want a safety net on a server you cannot afford to lose access to, schedule an automatic disable before you enable the firewall, and cancel it once you have confirmed access:

sudo apt install -y at
echo "/usr/sbin/ufw disable" | sudo at now + 5 minutes

Step 4: enable and verify

sudo ufw enable
sudo ufw status verbose

UFW warns that the command may disrupt existing SSH connections; answer y. Your current session stays up. Now open a second terminal and connect again. If the new SSH session works, the rule is right. If you scheduled the safety net, remove it with sudo atq to find the job number and sudo atrm followed by that number.

status verbose should show Default: deny (incoming), allow (outgoing) and your SSH rule for both IPv4 and IPv6. UFW manages IPv6 rules too, as long as IPV6=yes is set in /etc/default/ufw, which is the default on Ubuntu.

Common rules, ready to copy

NeedCommand
Web server on ports 80 and 443sudo ufw allow 'Nginx Full' or sudo ufw allow 80,443/tcp
A single TCP portsudo ufw allow 8443/tcp
A port rangesudo ufw allow 6000:6010/tcp
A UDP service such as WireGuardsudo ufw allow 51820/udp
Database reachable from one app server onlysudo ufw allow from 203.0.113.20 to any port 5432 proto tcp
Admin access from your office IP onlysudo ufw allow from 203.0.113.50 to any port 22 proto tcp
Block one abusive addresssudo ufw insert 1 deny from 198.51.100.7

Two habits keep the rule set clean. Allow databases, Redis and admin panels only from specific addresses, never from anywhere. And use insert 1 for deny rules, because UFW stops at the first match and an earlier allow would win otherwise.

To remove a rule, list rules with numbers and delete by number:

sudo ufw status numbered
sudo ufw delete 3

Numbers shift after each deletion, so list again before deleting another.

Rate limiting with ufw limit

The limit rule denies a connection from an IP address that has tried to open 6 or more connections in the last 30 seconds. It is a good default for SSH: real users rarely hit it, while password-guessing bots do.

It is not a replacement for proper SSH security. Disable password login and use keys, as described in setting up SSH keys on a VPS, and work through the rest of the secure new VPS checklist. Do not use limit for HTTP, where browsers legitimately open many connections at once.

The Docker gotcha

When you publish a container port with docker run -p 8080:80 or a ports: entry in Compose, Docker writes its own packet filter rules that are evaluated before UFW's. The port becomes reachable from the internet even if UFW has no allow rule for it, and ufw status will not show it.

The simplest fix is to publish ports on the loopback address only and put a reverse proxy in front:

services:
  app:
    image: myapp:latest
    ports:
      - "127.0.0.1:8080:80"

Nginx then reaches the app on 127.0.0.1:8080, and only ports 80 and 443 face the internet. Our guides to installing Docker on a VPS and an Nginx reverse proxy with SSL show both halves.

Checking what is really open

Rules describe intent; check reality from both sides.

sudo ss -tulpn

This lists every listening port and the process behind it. Anything listening on 0.0.0.0 or [::] that you did not mean to expose should either be bound to 127.0.0.1 or blocked. Then test from your own computer, not from the server, with nc -vz 203.0.113.10 5432. A connection that times out is filtered, which is what you want for private services.

To see blocked attempts, turn on logging at a low level and read the kernel log:

sudo ufw logging low
sudo journalctl -k -g UFW --since "1 hour ago"

On systems with rsyslog, the same entries also land in /var/log/ufw.log.

Troubleshooting

  • Locked out after enabling. If you scheduled the safety net, wait for it to run and reconnect. This is why you keep the first session open until a second one connects.
  • A rule seems ignored. Check the order with sudo ufw status numbered; an earlier rule may match first.
  • Changes did not apply. After editing files under /etc/ufw/ by hand, run sudo ufw reload.
  • Starting over. sudo ufw reset disables the firewall and removes all rules. Re-add SSH before enabling again.

FAQ

Do I still need UFW if my app only listens on localhost?

Yes. It is a second layer that catches services you forget about, such as a database installed with default settings that listens on all interfaces.

Does UFW slow the server down?

For a typical VPS with a handful of rules, the overhead is negligible.

Is UFW available on AlmaLinux or Rocky Linux?

Those distributions use firewalld by default. UFW is mainly an Ubuntu and Debian tool, and mixing two firewall managers on one server causes confusion.

Should I open ping?

UFW allows ICMP echo by default through its before.rules. Keeping it helps with diagnostics such as those in testing VPS latency with ping and mtr.

Start with a clean server

A firewall is easiest to get right on day one, before services pile up. Pick a location with the VPS locations guide, deploy an Ubuntu or Debian cloud server in the Cloudj console, and run the four steps above before you install anything else.

Deploy a server or order proxies

Pick a location in the console, see the live price, and pay from your balance.