The goal is reasonable: only tunnel users should reach the services on this box. The implementation people reach for is an IPv6 input chain that drops everything except WireGuard, which also drops the traffic that keeps the host attached to its own link. Neighbour discovery and path-maintenance messages are not service access, and removing them produces a machine that is unreachable for reasons unrelated to your policy. The tunnel comes up, the services are correctly scoped, and nothing else on the link works.

Three responsibilities, one ruleset

The first responsibility is outer network operation: the host must stay attached to its link, resolve neighbours and learn the path limits of that link. The second is the encrypted listener, which accepts UDP on the address and port you chose. The third is the set of decrypted services you want tunnel users to reach.

Those are three different policies, and only the second and third are about the VPN. A ruleset that treats them as one inherits a failure mode where tightening the application boundary silently breaks the host attachment.

Keep them in separate chains or at least separate comments, so the next person can see which line exists for which reason.

What ICMPv6 is doing for the host

IPv6 relies on ICMPv6 for far more than echo. Neighbour solicitation and advertisement replace ARP and are required for local delivery. Packet Too Big carries path MTU information, and ignoring it produces transfers that stall on large packets. Router advertisements carry the default route and prefix information when the link uses automatic configuration.

RFC 4890 separates the messages a host filter must permit from those that are an administrative choice, and it does so in a host section that is distinct from the rules for a router forwarding between networks. Reading only the forwarding section produces an input policy that is too strict for the host it protects.

The practical rule is to allow the essential error and configuration messages on the interface that needs them, scoped by type and source where the platform allows it, and to make an explicit decision about the rest.

Replacing all of that with a blanket ICMPv6 allowance solves the availability problem and gives up the filtering. Replacing it with a blanket drop solves the filtering problem and gives up the host.

Admit the tunnel, then admit the service

Accept the WireGuard transport on the intended outer address and UDP port, and accept the return traffic through connection tracking. Then allow the application services through the tunnel interface, from the sources you actually authorise.

An allowance for the outer UDP port does not authorise the decrypted requests inside it. That distinction is the whole reason the tunnel interface appears in the service rules.

Read the ruleset as it exists rather than as the file describes it:

sudo nft list ruleset
ip -6 addr show
ip -6 route show default

A listener on a physical address is a separate exposure from the same service on the tunnel address. If the box also forwards traffic to another machine, that is a forward chain decision rather than this input policy, and it needs its own reasoning.

Test the link, not just the tunnel

A working tunnel after the change proves less than it appears to, because an existing neighbour entry and an established connection can hide a control message the policy now drops.

Check the attachment directly, then check that the excluded path still fails:

ip -6 neigh show
ping -6 -c 3 2001:db8:1::1
sudo nft -c -f /etc/nftables.conf

A neighbour table that stays complete after a reboot is the signal that discovery still works. A table that empties and never refills is the signal that you filtered it out. The third command validates the ruleset syntax without applying it, which is worth doing while you still have a session.

Recover a host you locked out

Before changing firewall rules that carry your own administration session, keep a second channel: a console, a serial connection, or a scheduled rollback that removes the new rules if you do not cancel it.

If a change does lock you out, the recovery is through that channel and not through the network you just removed. Restore the previous ruleset from a saved copy, confirm the host is reachable again, and only then reapply the intended policy in smaller pieces.

The final policy is not universal. Addressing, routing and the firewall implementation are deployment inputs, but the boundary is the same everywhere: deny unintended application access while keeping the control traffic that carries the authorised tunnel.

Pennadoù liammet