Security

UFW and IPv6: make sure your rules cover both

Check that UFW filters IPv6 as well as IPv4. Set IPV6=yes, read the (v6) rules in ufw status, allow or deny IPv6 sources and test your server from outside with nmap -6.

IntermediateLinux server5 min read

A firewall that filters only IPv4 leaves a second, wide-open door if your server also has an IPv6 address. Services such as SSH, MySQL and Redis often listen on both. This guide shows how to confirm that UFW covers IPv6, how to read and write IPv6 rules and how to prove the result from outside the server.

Before you start

  • A Linux VPS running Ubuntu 22.04, Ubuntu 24.04 or Debian 12 with UFW installed. See Set up the UFW firewall on Ubuntu and Debian.
  • A sudo user connected over SSH, with SSH allowed in UFW.
  • Find out whether your server has a public IPv6 address:
Bash
  ip -6 addr show scope global

If this prints nothing, the server has no public IPv6 address yet. Your UFW settings still matter if you add one later. Configure IPv6 on a Linux VPS covers setting it up.

Warning: If you connect over SSH using an IPv6 address, make sure an IPv6 SSH rule exists before you reload UFW after changing IPv6 settings. Otherwise your session may drop. The browser console in your VPS provider's control panel always works as a way back in.

Turn on IPv6 support in UFW

UFW reads its IPv6 setting from /etc/default/ufw. Check it:

Bash
grep IPV6 /etc/default/ufw

You want:

IPV6=yes

This is the default on current Ubuntu and Debian releases, but older images and hand-edited files sometimes say no. If it does, edit the file:

Bash
sudo nano /etc/default/ufw

Change the line to IPV6=yes, save, then reload UFW so it builds the IPv6 rules:

Bash
sudo ufw disable
sudo ufw enable

A plain sudo ufw reload is usually enough, but a full disable and enable makes sure the IPv6 tables are created from scratch.

Note: With IPV6=no, UFW does not touch the IPv6 firewall at all. On most systems that means IPv6 traffic is allowed, not blocked.

Read (v6) rules in status output

Bash
sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)

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

When you add a rule without a source address, such as sudo ufw allow 443/tcp, UFW creates two rules: one for IPv4 and a (v6) copy for IPv6. The default policy at the top applies to both.

If you see no (v6) lines at all, IPv6 support is off. Go back to the previous step.

Allow or deny IPv6 sources

Rules with a specific source address apply only to that address family. An IPv4 source creates an IPv4 rule only, and an IPv6 source creates an IPv6 rule only.

Allow SSH from one IPv6 address:

Bash
sudo ufw allow from 2001:db8:10::5 to any port 22 proto tcp comment 'Admin IPv6'

Allow a whole IPv6 network, which is common because home connections usually get a /64 or /56 prefix that can change its last part:

Bash
sudo ufw allow from 2001:db8:10::/56 to any port 22 proto tcp

Block an IPv6 range. Deny rules must sit above allow rules, so use prepend where available:

Bash
sudo ufw prepend deny from 2001:db8:bad::/48

If your UFW version lacks prepend, run sudo ufw status numbered, find the number of the first (v6) rule and use sudo ufw insert <number> deny from....

Tip: If you restrict SSH to a trusted IPv4 address, add the IPv6 equivalent too, or the IPv6 copy of your old public SSH rule may still be open. Review the (v6) lines every time you tighten a rule.

Check the service side

The firewall is half of the picture. See which services listen on IPv6:

Bash
sudo ss -tulpn | grep -F '[::]'

Lines with [::]:3306 or *:6379 mean a service is reachable on IPv6 if the firewall allows it. If a service should be local only, bind it to 127.0.0.1 or ::1 in its config.

Check it works

Test from a machine that has working IPv6. Many home connections do; you can confirm with curl -6 https://ifconfig.co. Then scan your server's IPv6 address:

Bash
nmap -6 -Pn -p 22,80,443,3306,6379 2001:db8:10::10

Expected result for a web server:

PORT     STATE    SERVICE
22/tcp   open     ssh
80/tcp   open     http
443/tcp  open     https
3306/tcp filtered mysql
6379/tcp filtered redis

filtered means UFW dropped the probe. Compare the result with the same scan against the IPv4 address. The open ports should match.

Troubleshooting

  • No (v6) rules appear: IPV6 is not yes in /etc/default/ufw. Fix it and reload UFW.
  • A port is closed on IPv4 but open on IPv6: an old (v6) rule is still allowing it. Delete it by number with sudo ufw status numbered and sudo ufw delete <n>.
  • nmap -6 says "Network is unreachable": the machine you scan from has no IPv6. Use another network or an online IPv6 port checker.
  • IPv6 SSH dropped after a change: connect over IPv4 or your VPS provider's browser console and add the IPv6 SSH rule.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.