How to set up a firewall with UFW on Ubuntu or Debian

A firewall makes sure only the doors you choose are open. For most web servers that is three: SSH, HTTP and HTTPS. UFW makes this a few commands.

Golden rule: allow SSH before you turn the firewall on, and keep your current session open until you've tested a new login.

1. Install UFW

Ubuntu usually has it already. On Debian, install it:

sudo apt update
sudo apt install ufw

2. Choose the defaults

Block everything coming in, allow everything going out:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Nothing changes yet. The firewall is still off.

3. Allow SSH first

sudo ufw allow OpenSSH

If UFW says it can't find a profile called OpenSSH, use the port number instead: sudo ufw allow 22/tcp. If your SSH runs on another port, allow that port, for example sudo ufw allow 2222/tcp.

4. Allow your websites

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Port 80 is HTTP and 443 is HTTPS. Keep 80 open even if you only use HTTPS: it redirects visitors, and Let's Encrypt uses it to renew certificates.

5. Turn it on

sudo ufw enable

UFW warns that this may disconnect SSH. Because you allowed SSH in step 3, answer y. Then check:

sudo ufw status verbose

You should see Status: active, deny (incoming), and your three rules, each twice (once for IPv4, once for IPv6). The firewall stays on after a restart.

6. Test from a new window

Open a new terminal and log in with SSH. Open your website in a browser. If both work, you're done.

Everyday commands

  • See rules with numbers: sudo ufw status numbered
  • Remove a rule: sudo ufw delete allow 80/tcp, or by number: sudo ufw delete 2
  • Allow one address only (for example your office, for a database port): sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp
  • Behind Cloudflare? Allow ports 80 and 443 only from Cloudflare's addresses, with the script in our guide to locking your server to Cloudflare.
  • Slow down password guessing on SSH: sudo ufw limit OpenSSH blocks an address that opens 6 or more connections in 30 seconds. It replaces the plain allow rule. Skip it if your deploy tools open many SSH connections at once.

Don't open these to everyone

Databases (MySQL/MariaDB 3306, PostgreSQL 5432), Redis (6379) and Memcached (11211) should only listen on the server itself. If something outside must reach them, allow only that one address, as above. See our guides for MySQL and MariaDB and Redis, and how to find which ports are open.

Two things that catch people out

  • Docker skips UFW. Ports published by Docker containers (-p 8080:80) are reachable even when UFW says they're blocked, because Docker adds its own rules. Publish only to the server itself (-p 127.0.0.1:8080:80) and put a web server in front, or follow Docker's firewall guide.
  • Your hosting provider may have a firewall too. Many cloud providers have one in their control panel. A port must be open in both places to work. That's fine, and it adds a second layer.

If you get locked out

Use your hosting provider's web console (sometimes called VNC, rescue or serial console), log in there and run sudo ufw allow OpenSSH, or sudo ufw disable to switch the firewall off while you fix it.

Official sources

Next steps: use SSH keys and turn off password login, then work through the security checklist for a new PHP server.

ServerNest is being built to show your firewall rules in a dashboard and change them safely, with automatic undo if a change cuts off the connection. Join early access to try it first.

← Back to the security blog