Cheat Sheet

UFW Commands

UFW (Uncomplicated Firewall) is the front end for iptables that Ubuntu and Debian ship, and the firewall most single-server setups use. This sheet lists the ufw commands for enabling it without locking yourself out, opening and closing ports, allowing an IP, deleting rules, rate limiting SSH, and the Docker problem everyone hits once.

Last updated August 29, 2026

Status and Enable

Allow SSH before you enable, every time. A default deny with no SSH rule drops your next login, which shows up as a timeout in PuTTY or (see Network error: Connection timed out). Your current session stays up, so use it to fix the rule.

CommandWhat it does
Active or inactive, plus the rule list
Adds default policies, logging level, and profiles
Rules with the numbers you need for and
Open SSH using the app profile (do this first)
Turn the firewall on and start it at boot
Same, without the "may disrupt SSH" confirmation (scripts)
Turn it off; rules are kept
Rules you have added, including while inactive
Listening ports and which rule, if any, covers each
The underlying iptables rules ufw wrote
Installed version

A safe first setup:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status verbose

Allow Rules

A port with no protocol opens both TCP and UDP. Service names come from , app names from . The firewall rule generator writes these for you.

CommandWhat it does
Open a TCP port
Open a port for TCP and UDP
Same as , by service name
Several ports in one rule
A port range
UDP only (WireGuard)
An app profile; quote names with spaces
Only on one interface
Everything arriving over an interface (Tailscale, for WireGuard)
An outbound rule, only useful after
Long form; the same rule as
Attach a comment that shows in

Deny and Reject

drops packets silently, so the client waits until it times out. sends a refusal back, so the client fails at once with "connection refused". Deny is the usual choice for the internet, reject is kinder on internal networks.

CommandWhat it does
Block a port
Block every packet from one address
Block a subnet
Block one address on one port
Refuse instead of drop
Stop outbound mail from this box
Block all inbound on one interface

Deny rules only work when they sit above the allow rule they override; see Rule Order below.

Allow From an IP or Subnet

CommandWhat it does
Everything from one address
Everything from a subnet
SSH from one address only
SSH from one subnet
MySQL from the private network
To a specific local address, when the server has several
The IPv6 version; needs (see below)

rules and plain port rules combine. Allowing 22 from a subnet and then also opens it to everyone, so check after each change.

Delete Rules

CommandWhat it does
Get the number
Delete rule 3 (asks for confirmation)
Delete without the prompt
Delete by repeating the rule
Works for long rules too; spell it exactly as added
Delete an app profile rule

Numbers renumber after each delete. To remove rules 2, 5, and 7, delete 7 first, then 5, then 2.

Rule Order and Insert

ufw evaluates rules top to bottom and the first match wins. A added after never fires for port 22, because the allow already matched.

CommandWhat it does
Put a rule at position 1, above everything else
Same as (ufw 0.36 and newer)
Insert at a specific position
Confirm where it landed

With IPv6 on, an position counts IPv4 and IPv6 rules together; ufw refuses a position that would split them and tells you so.

Default Policies

Defaults apply to anything no rule matches. The normal shape is deny in, allow out.

CommandWhat it does
Drop anything not explicitly allowed (the sensible default)
Let the server make outbound connections
Refuse instead of drop
Lock down outbound; then you need rules for DNS (53), HTTP, updates
Drop forwarded traffic (default); when the box is a router or VPN gateway
Shows the current defaults on the "Default:" line

Rate Limiting

allows a port but blocks an address that opens 6 or more connections within 30 seconds. It is the cheapest brute-force defence for SSH, and it costs nothing when you also use keys.

CommandWhat it does
Rate-limit SSH ( is the same)
Same, via the app profile
SSH on a non-standard port
Remove it

A rule replaces the rule for that port; you do not need both. For anything beyond 6 hits per 30 seconds, use fail2ban.

Logging

CommandWhat it does
Log blocked packets (the level)
Stop logging
Also log allowed packets that match a rule, rate limited
Log everything, rate limited; noisy
Everything, no rate limit; only for short debugging
Watch it (Ubuntu writes to this file via rsyslog)
The same messages from the kernel log on systemd-only boxes
Recent blocked packets, with SRC, DST, DPT fields
Log new connections matching one rule only ( logs every packet)

App Profiles

Packages such as OpenSSH, nginx, Apache, and Samba drop a profile in that names their ports. Rules made from a profile update when the package updates.

CommandWhat it does
Profiles available on this server
The ports a profile opens
Ports 80 and 443 ( is 80 only, 443 only)
Use a profile in a rule
Reload a profile after its file changed ( to add rules for it)

A profile of your own goes in :

[MyApp]
title=My App
description=Internal API
ports=8080,8443/tcp

Reload and Reset

CommandWhat it does
Re-read the rule files without dropping connections; needed after editing files under
Full restart, including the IPv6 setting
Disable, delete every rule, and restore defaults; backs up the old files to
Reset without confirmation
The service that applies rules at boot

Rules added with , , and apply immediately; no reload needed. The files, if you ever need them:

FileContains
, The rules you added, generated by ufw; do not hand-edit
, Rules run before yours; NAT and masquerade go here
, Rules run after yours; the ufw-docker block lives here
, default policies,
Kernel settings ufw applies, such as

Anything ufw's syntax cannot express (NAT, port forwarding, filtering) goes in or as raw iptables. The iptables to nftables converter helps if you are moving that block elsewhere.

Docker

Docker bypasses ufw. It writes its own iptables rules to publish ports, and traffic to a container goes through the FORWARD chain, not INPUT, so a container is open to the world even with . will not show it.

FixHow
Bind to localhost (or in compose), then reverse proxy through nginx or Caddy
ufw-docker, then and
Allow a container after ufw-docker (container name, port)
Allow with a route rule after ufw-docker
Disable Docker's iptables in ; breaks container-to-internet NAT unless you add it yourself, so not recommended

Docker Desktop and rootless Docker do not publish through iptables this way, so the problem is specific to the standard Linux engine. Full container commands are on the Docker cheat sheet.

IPv6

ufw handles IPv6 when is set in , which is the default on Ubuntu. With it on, every rule you add applies to both stacks and lists each rule twice, the second marked .

CommandWhat it does
Check the setting
Turn it on
Apply the change; is not enough for this one
An IPv6-only rule
Just the IPv6 rules

If the server has an IPv6 address and , that address has no firewall at all.

Gotchas

  • Enabling without an SSH rule is the classic lockout. first, then . If it already happened and the provider has a web console, disable ufw from there; a policy shows as connection refused, a policy as a timeout.
  • opens TCP and UDP. Nothing listens on UDP 22, so it is harmless, but is what you meant.
  • Docker ignores ufw. See the Docker section; saying only 22 is open does not mean 8080 is closed.
  • First match wins. A added after a matching does nothing; use for blocks.
  • keeps your rules and deletes them. says in both cases; tells them apart.
  • on a distribution that uses firewalld (Rocky, Fedora) or on a box with a cloud provider firewall in front is a second layer. Two firewalls with different rules is the usual reason a port that ufw says is open still times out.
  • Editing by hand gets overwritten by the next command. Use the CLI for rules and the and files for the raw iptables ufw cannot express. See the SSH cheat sheet for the side of testing a port after a change.

UFW Cheat Sheet FAQ

Are ufw rules persistent after a reboot?
Yes. Every allow, deny, and limit you add is written to /etc/ufw/user.rules (and user6.rules for IPv6) the moment you run it, and ufw.service reloads them at boot. Nothing else is needed, which is the main reason people pick ufw over raw iptables, where rules vanish at reboot unless you save them. The one way to lose them is sudo ufw reset, which backs the files up with a timestamp suffix in /etc/ufw and then empties them. sudo ufw disable does not delete rules; sudo ufw show added lists them even while the firewall is off.
How do I allow SSH before enabling ufw?
Run sudo ufw allow OpenSSH (or sudo ufw allow 22/tcp if you are not sure the profile exists) and check it with sudo ufw show added, then run sudo ufw enable. ufw warns that enabling may disrupt existing SSH connections; that warning appears regardless, and your current session survives either way because connection tracking treats it as established. The danger is the next login, not this one. If SSH listens on another port, allow that port instead, and if you only ever connect from one network, sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp is tighter than opening 22 to the world.
How do I delete a ufw rule?
Two ways. Repeat the rule with delete in front: sudo ufw delete allow 80/tcp removes exactly the rule you added with sudo ufw allow 80/tcp. Or list rules with sudo ufw status numbered and remove one by position: sudo ufw delete 3. Numbers shift after each deletion, so when removing several, delete from the highest number down, or re-run status numbered each time. Add --force to skip the confirmation in scripts. With IPv6 on, every rule appears twice, once plain and once marked (v6), and each copy has its own number.
Why do ufw rules not work with Docker?
Docker writes its own iptables rules to publish container ports, in the DOCKER and FORWARD chains, and packets to a published port never pass through the INPUT chain where ufw's rules live. So a container started with -p 8080:80 is reachable from the internet even when ufw shows only port 22 open. The clean fixes: bind the port to localhost (-p 127.0.0.1:8080:80) and put nginx or Caddy in front, or install the ufw-docker script, which adds a filter to the DOCKER-USER chain so ufw route allow rules govern container traffic. Setting iptables to false in daemon.json also works but breaks container networking in other ways, so most people avoid it.
Why does ufw say command not found?
Either it is not installed or you are not root. Debian, Raspberry Pi OS, and minimal cloud images do not ship ufw; install it with sudo apt install ufw. Ubuntu Server includes it. If the package is there but a plain user sees command not found, that is because /usr/sbin is not on a normal user's PATH; run it with sudo, which is required anyway. On CentOS, Rocky, Fedora, and Arch the default firewall is firewalld or nftables, and while ufw is packaged for them, the sensible move is to use firewall-cmd on those systems rather than fight the distribution.

Related cheat sheets