Skip to content
DevOps devops networking 6 min read

Configuring a Firewall with ufw

A firewall is a gatekeeper for your server. It decides which network connections are allowed in and which are blocked, based on rules you write. Even if a service is running on your machine, the firewall can stop the outside world from reaching it. On Ubuntu the easiest way to manage a firewall is ufw (the “Uncomplicated Firewall”), a friendly front-end for the powerful but cryptic iptables system underneath. This page walks you through enabling ufw safely, opening the ports a web server needs, and removing rules you no longer want.

What ufw actually does

Every network service listens on a port (a numbered “door” on your server — for example web traffic uses port 80, encrypted web traffic uses port 443, and SSH uses port 22). A firewall lets you choose which doors stay open. ufw works by writing rules that match incoming or outgoing traffic and then either allow or deny it.

The most common and safest setup is to deny all incoming traffic by default, then explicitly allow only the few ports you actually need. This is called a “default-deny” policy: if you forget about a service, it stays closed instead of accidentally being exposed.

When to use ufw: on almost any single Ubuntu server (a web server, app server, database box, or VPS). It is the right tool for 95% of servers.

When NOT to use ufw: if you need very complex routing, NAT, or load-balancer-style rules — there you may reach for raw iptables/nftables. ufw is for simple, host-level “which ports are open” control.

Check whether ufw is installed

ufw ships with Ubuntu 22.04 and 24.04 LTS, but it is off by default. Confirm it exists first.

sudo ufw status

Output:

Status: inactive

If for some reason it is missing, install it:

sudo apt update
sudo apt install ufw

The golden rule: allow SSH BEFORE you enable ufw

This is the single most important step on this page. If you turn on ufw with a default-deny policy and you have not allowed SSH (port 22), the firewall will block your own connection. On a remote server (like a cloud VPS) that means you are locked out and cannot get back in without console access.

Warning: Always allow SSH and confirm the rule is listed BEFORE running ufw enable. If you are working over an SSH session, double-check the rule exists. A locked-out remote server may require a provider’s web console or a full rebuild to recover.

Allow SSH using its named profile (ufw ships an app profile called OpenSSH):

sudo ufw allow OpenSSH

Output:

Rules updated
Rules updated (v6)

You can list the available named profiles at any time:

sudo ufw app list

Output:

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

Tip: If you run SSH on a non-standard port (for example 2222 instead of 22), the OpenSSH profile will NOT cover it. Allow the real port directly with sudo ufw allow 2222/tcp before enabling.

Set the default policies

Tell ufw to block everything coming in and allow everything going out. This is the secure baseline.

sudo ufw default deny incoming
sudo ufw default allow outgoing

Output:

Default incoming policy changed to 'deny'
(be sure to update your rules accordingly)
Default outgoing policy changed to 'allow'
(be sure to update your rules accordingly)

“Deny incoming” means nobody can connect to your server unless a rule allows it. “Allow outgoing” means your server can still reach the internet (to run apt update, call APIs, etc.).

Open the ports a web server needs

A typical web server needs three things open: SSH so you can manage it, port 80 for plain HTTP, and port 443 for HTTPS (encrypted web traffic). You can allow ports by number or by named profile.

By port number:

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

If you are running Nginx, the cleaner option is its app profile, which opens both 80 and 443 at once:

sudo ufw allow 'Nginx Full'

Output:

Rules updated
Rules updated (v6)

Here is how the common allow commands compare:

CommandWhat it opensWhen to use it
ufw allow OpenSSHPort 22 (TCP)Always, before enabling ufw
ufw allow 80/tcpPlain HTTPWeb server serving HTTP / redirects
ufw allow 443/tcpHTTPSWeb server serving encrypted traffic
ufw allow 'Nginx Full'Ports 80 + 443Nginx box, both protocols at once
ufw allow from 203.0.113.5 to any port 5432PostgreSQL from one IPLock a database to one trusted client

That last example shows a powerful pattern: you can restrict a rule to a specific source IP address so only one machine can reach a sensitive port. This is ideal for databases (PostgreSQL on port 5432, MySQL on 3306) that should never be open to the whole internet.

Enable the firewall

With SSH allowed and your web ports open, turn ufw on.

sudo ufw enable

Output:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

It also enables ufw on every reboot automatically (via systemd), so you do not need to remember to turn it back on.

Check your rules with ufw status

To see exactly what is allowed, use the verbose status. The numbered version is useful for deleting rules later.

sudo ufw status verbose

Output:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

Deleting rules

Say you no longer want plain HTTP on port 80 (you redirect everything to HTTPS at the load balancer). The simplest way is to delete by the same syntax you used to add the rule:

sudo ufw delete allow 80/tcp

Output:

Rule deleted
Rule deleted (v6)

If you do not remember the exact rule text, list rules with numbers and delete by number. Be careful: the numbers shift after each deletion, so always re-list between deletes.

sudo ufw status numbered

Output:

Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp (OpenSSH)           ALLOW IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
sudo ufw delete 2

Output:

Deleting:
 allow 80/tcp
Proceed with operation (y|n)? y
Rule deleted

To switch the whole firewall off (for example while debugging), use sudo ufw disable. To wipe every rule and start over, use sudo ufw reset.

Best Practices

  • Allow SSH first, then enable. Never run ufw enable until you have confirmed an SSH allow rule exists in ufw status.
  • Default deny incoming. Start closed and open only the ports a service truly needs.
  • Prefer app profiles (OpenSSH, Nginx Full) over raw port numbers — they are self-documenting and stay correct if defaults change.
  • Lock down databases by source IP with ufw allow from <ip> to any port <port> instead of opening them to Anywhere.
  • Re-list before each delete when deleting by number, since the numbering shifts after every removal.
  • Combine ufw with SSH hardening (key-only auth, disabled root login) — a firewall limits exposure but does not replace strong authentication.
  • Review rules periodically with sudo ufw status verbose so old, forgotten ports do not stay open.
Last updated June 15, 2026
Was this helpful?