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
| Need | Command |
|---|---|
| Web server on ports 80 and 443 | sudo ufw allow 'Nginx Full' or sudo ufw allow 80,443/tcp |
| A single TCP port | sudo ufw allow 8443/tcp |
| A port range | sudo ufw allow 6000:6010/tcp |
| A UDP service such as WireGuard | sudo ufw allow 51820/udp |
| Database reachable from one app server only | sudo ufw allow from 203.0.113.20 to any port 5432 proto tcp |
| Admin access from your office IP only | sudo ufw allow from 203.0.113.50 to any port 22 proto tcp |
| Block one abusive address | sudo 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, runsudo ufw reload. - Starting over.
sudo ufw resetdisables 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.