ufw = Uncomplicated Firewall, a friendly front-end to nftables/iptables (powerful, but unpleasant to write by hand). Covers reading the rules, removing one safely, checking a port is really closed, and not locking yourself out. Why a VPN client needs no inbound port: vpn-how-it-works.
The big picture
- A doorman with two lists and a memory: default policies (anyone not on a list) · rules (named exceptions) · state (conversations you started, so replies get in; see vpn-how-it-works §5).
- Ubuntu’s sane defaults:
deny (incoming)→ nobody may start a conversation with you ·allow (outgoing)→ you may start one with anyone · replies come back automatically, thanks to state. - Consequence: you only need
allowrules for services other machines must reach (a web server, an SSH daemon). A client of anything needs no rule at all.
1. Check the current state
sudo ufw status verboseStatus: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
51820/udp ALLOW IN Anywhereverboseover plainstatus→ it shows the default policies, without which the rules can’t be interpreted.
sudo ufw status numbered # with numbers, for editing To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 51820/udp ALLOW IN Anywhere2. Remove a rule
sudo ufw delete allow 51820/udp # A. by specification (preferred)
sudo ufw status numbered # B. by number: look again, every time
sudo ufw delete 2 # confirms before actingThe renumbering trap
Rule numbers shift after every delete: delete
[1]and the old[2]becomes the new[1]. Delete[1]twice and you’ve removed two different rules, the second probably not the one you meant.
- A. By spec → immune to renumbering, and documents what you removed.
- B. By number → re-run
status numberedbefore each delete; removing several, work from the highest number downward so the ones you haven’t reached don’t move. ufw deleteasksProceed with operation (y|n)?→ read what it’s about to remove before answering.
3. delete vs deny: not the same thing
sudo ufw delete allow 51820/udp # removes the exception: port falls back to default (deny)
sudo ufw deny 51820/udp # adds an explicit deny rule- With the default already
deny incoming, deleting the allow rule is sufficient: the port is closed either way. - An explicit
denyrecords the intent, so a future you doesn’t re-add the allow by accident. Belt-and-braces, not a correction.
4. Verify a port is really closed
Two different questions, both worth asking:
sudo ufw status | grep 51820 # 1. firewall: no output = no rule = default deny applies
sudo ss -lunp | grep 51820 # 2. listening: no output = nothing is listeningss -lunp, notss-lunp:ssis the command, the rest are flags.-llistening only ·-uUDP ·-tTCP (swap for-u, or use both) ·-nnumeric (51820, not a service name) ·-powning process (needssudo).sudo ss -lunp→ all UDP ·sudo ss -ltnp→ all TCP ·sudo ss -ltunp→ both.- They’re independent. Allowed with nothing listening → harmless but untidy. Listening but blocked → fine, still reachable from localhost. Belt and braces means closing both.
5. Don’t lock yourself out
sudo ufw allow 22/tcp # FIRST: or your custom SSH port
sudo ufw enable
ufw enableon a remote machine without allowing SSHDefault deny incoming includes your own SSH session: you’re locked out, and fixing it needs physical or console access.
ufw enablewarns “Command may disrupt existing ssh connections” → the warning is real.- On this local desktop the risk is nil, but the habit is worth having before it matters.
6. Worked example: close the unused VPN port
This PC is a VPN client, not a server, so an inbound 51820/udp ALLOW rule serves no purpose (why: vpn-how-it-works §4).
sudo ufw status verbose # 1. what's there + defaults
sudo ufw delete allow 51820/udp # 2. remove BY SPEC, no renumbering risk
sudo ufw status | grep 51820 || echo "no rule for 51820 - default deny applies" # 3. rule gone?
sudo ss -lunp | grep 51820 || echo "nothing listening on 51820" # 4. nothing listening?
sudo ufw deny 51820/udp # 5. optional: record the intent- Nothing breaks: outbound connections and their replies are unaffected; only a stranger’s ability to knock on that port is removed.
- If you ever allow
22/tcp, ssh-keys-and-github is what’s behind it.
Quick reference
sudo ufw status verbose # rules + default policies <- start here
sudo ufw status numbered # rules with numbers, for editing
sudo ufw show added # rules as the commands that created them
sudo ufw allow 22/tcp # allow a port
sudo ufw allow ssh # by service name (/etc/services)
sudo ufw allow 51820/udp
sudo ufw allow from 192.168.1.0/24 # a whole subnet, any port
sudo ufw allow from 192.168.1.50 to any port 22 proto tcp # specific
sudo ufw delete allow 51820/udp # remove by spec <- safer
sudo ufw delete 2 # remove by number (re-check numbers first!)
sudo ufw deny 51820/udp # explicit deny rule
sudo ufw enable # ! allow SSH FIRST on a remote box
sudo ufw disable
sudo ufw reload
sudo ufw reset # ! DESTRUCTIVE: wipes every rule
sudo ufw logging on
sudo ufw logging medium # off | low | medium | high | full
sudo tail -f /var/log/ufw.log # watch the log