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
OpenSSHprofile will NOT cover it. Allow the real port directly withsudo ufw allow 2222/tcpbefore 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:
| Command | What it opens | When to use it |
|---|---|---|
ufw allow OpenSSH | Port 22 (TCP) | Always, before enabling ufw |
ufw allow 80/tcp | Plain HTTP | Web server serving HTTP / redirects |
ufw allow 443/tcp | HTTPS | Web server serving encrypted traffic |
ufw allow 'Nginx Full' | Ports 80 + 443 | Nginx box, both protocols at once |
ufw allow from 203.0.113.5 to any port 5432 | PostgreSQL from one IP | Lock 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 enableuntil you have confirmed an SSH allow rule exists inufw 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 toAnywhere. - 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 verboseso old, forgotten ports do not stay open.