UFW

On this page 7

UFW, short for Uncomplicated Firewall, is a command-line frontend for the netfilter packet filter in Linux that translates short, readable commands such as ufw allow 22/tcp into the underlying iptables or nftables rules. In Linux networking it serves as the default host firewall tool on Ubuntu and several related distributions, aimed at administrators who need a stateful, default-deny policy on a single machine without writing raw rule chains.

UFW does not filter packets itself. The kernel’s netfilter subsystem does the filtering; UFW manages rule files, loads them at boot and offers a consistent syntax for the most common tasks: opening ports, restricting sources, rate limiting and logging.

How UFW builds rules on top of netfilter

UFW works as a rule generator and loader. When an administrator adds a rule, UFW writes it to /etc/ufw/user.rules (and user6.rules for IPv6) and inserts it into its own dedicated chains, such as ufw-user-input, which hang off the standard INPUT, OUTPUT and FORWARD hooks. On current distributions the iptables command is usually the iptables-nft compatibility layer, so UFW rules end up as nftables objects even though UFW still speaks iptables syntax.

Around the user rules sit fixed rule files that the administrator can edit directly. before.rules runs first and accepts established and related connections, loopback traffic and essential ICMP messages; after.rules runs last; the default policies apply to anything left unmatched. Because the generated rules use connection tracking, a single allow rule for inbound port 443 also admits the reply packets of that connection automatically.

The table below lists the files that define UFW behavior and what each one controls.

FilePurposeTypical edit
/etc/default/ufwGlobal settings and default policiesIPV6=yes, forward policy
/etc/ufw/ufw.confEnabled state and log levelENABLED=yes, LOGLEVEL=low
/etc/ufw/before.rulesRules evaluated before user rulesNAT, ICMP handling
/etc/ufw/user.rulesRules created with ufw commandsNot edited by hand
/etc/ufw/after.rulesRules evaluated after user rulesLate catch-all logging
/etc/ufw/applications.d/Application profilesNamed port sets per service
Main UFW configuration files

Core commands, policies and rule options

A UFW setup starts with default policies: the usual baseline is ufw default deny incoming and ufw default allow outgoing, which blocks unsolicited inbound traffic while letting the host initiate connections. Individual rules then punch precise holes in that baseline, by port, protocol, source address, interface or application profile.

Rules are evaluated in order, first match wins, so a broad allow placed above a narrow deny makes the deny useless. ufw status numbered shows the order, and ufw insert 1 places a rule at the top. The following table summarizes the options that administrators use most often.

CommandEffectNote
ufw allow 22/tcpOpens TCP port 22 from anywhereApplies to IPv4 and IPv6
ufw allow from 10.0.0.0/24 to any port 5432Opens a port for one subnetPreferred for databases
ufw limit sshAllows with rate limitingBlocks 6 or more connections in 30 seconds
ufw deny out 25/tcpBlocks outbound SMTPUseful against spam relays
ufw route allow in on eth1 out on eth0Permits forwarded trafficNeeds IP forwarding enabled
ufw delete 3Removes rule number 3Check numbering first
ufw logging mediumRaises log verbosityLevels: off, low, medium, high, full
Frequently used UFW commands

Application profiles in /etc/ufw/applications.d give names such as “OpenSSH” or “Nginx Full” to sets of ports, so ufw allow "Nginx Full" opens ports 80 and 443 together. Adding comment 'reason' to a rule records why the hole exists, which pays off during later audits.

UFW compared with nftables, iptables and firewalld

UFW sits at the simplest end of the Linux firewall stack. Raw nftables and iptables expose every table, chain and match, while UFW hides them behind a host-centric vocabulary. The comparison below shows where each tool fits; nftables and iptables have their own pages and are summarized only briefly here.

ToolAbstraction levelTypical useMain limitation
UFWHigh, port and source rulesSingle servers, desktopsLittle support for complex routing
firewalldHigh, zones and servicesFedora, RHEL family hostsZone model adds learning curve
nftablesLow, full rule languageRouters, complex policiesVerbose for simple tasks
iptablesLow, legacy rule chainsOlder systems and scriptsSeparate IPv4 and IPv6 tools
Linux firewall tools side by side

Running two firewall managers at once is a classic mistake: UFW and firewalld both rewrite netfilter state and can silently override each other. A host should have exactly one tool in charge, and hand-written nftables rules should go into UFW’s before or after files rather than into a separate service.

Enabling UFW safely on a remote server

The most important rule for remote administration is to allow SSH before enabling the firewall. Because the default incoming policy is deny, running ufw enable over an SSH session without an SSH rule can lock the administrator out of the machine. UFW warns that the command may disrupt existing SSH connections for this reason.

  1. Set the defaults with ufw default deny incoming and ufw default allow outgoing.
  2. Add the management access rule, ideally ufw limit OpenSSH or a rule restricted to an admin subnet.
  3. Add the service ports the host actually serves, such as 80 and 443.
  4. Run ufw enable, then verify with ufw status verbose from a second session before closing the first.
  5. Keep console or out-of-band access available on critical machines in case a rule goes wrong.

Rules persist across reboots because the ufw service reloads them at startup. ufw reload reapplies the files after manual edits, and ufw reset returns to an empty, disabled state while saving backups of the old rule files.

Pitfalls and limitations of UFW

The best-known surprise involves Docker and published container ports. Docker inserts its own NAT and filter rules, so traffic to a published port is forwarded before it reaches UFW’s input chains, and a port that ufw status shows as closed can still be reachable from the internet. The usual remedies are binding containers to 127.0.0.1, filtering in the DOCKER-USER chain or adding forward rules in after.rules.

SymptomLikely causeFix
Container port open despite denyDocker rules bypass UFW input chainsFilter in DOCKER-USER or bind locally
Deny rule has no effectEarlier allow rule matches firstUse ufw insert 1 for the deny
IPv6 traffic unfilteredIPV6=no in /etc/default/ufwSet IPV6=yes and reload
SSH lost after enableNo allow rule for port 22Recover via console, add rule
Forwarded traffic droppedDefault forward policy is DROPAdd ufw route rules
Common UFW symptoms and their causes

UFW is a host firewall, not a network design tool. It handles NAT and routing only through hand-edited rule files, offers no zone concept and does not inspect application payloads. For gateways with many interfaces or complex policy routing, writing nftables directly or using a dedicated firewall distribution is the cleaner choice.

Understanding it simply

Think of a server as a building with thousands of numbered doors. UFW is the receptionist with a guest list. By default, nobody from outside may enter, but the owner can say “let visitors use door 443” or “only staff from this office may use door 22”, and the receptionist enforces it.

The receptionist does not build walls; the Linux kernel already has them. UFW simply makes it easy to say who may come in in short, readable sentences, so a small mistake in a complicated rulebook is less likely to leave a door open.

Applied in practice

A small company runs its website and a PostgreSQL database on one Ubuntu virtual server. Before launch, the administrator sets deny incoming and allow outgoing as defaults, adds ufw limit OpenSSH, opens “Nginx Full” for ports 80 and 443, and allows port 5432 only from the office subnet 198.51.100.0/24. After ufw enable, a second SSH session confirms access, and ufw status numbered shows five rules with comments.

A week later, the logs show thousands of rejected connection attempts on port 22 and on the database port from unknown addresses. The rate limit stops repeated SSH guessing, and the database never accepts a connection from outside the office. The result is a small, auditable rule set that a colleague can read and understand in under a minute.