Disclosure up front: I run IPYE, a company that leases IP space. Most of this article is practical how-to; IPYE appears where a free /48, LOA, or ROA helps you try the work, with a short call to action at the end.

The moment a new /48 is announced, scanners start probing it. IPv6 space is too large to sweep completely, but hosts with predictable addresses such as ::1 or addresses published in DNS are found quickly. If you are bringing up an edge for a free /48 from IPYE, write the firewall before the BGP session, not after. This article builds a compact nftables ruleset for a Linux edge that originates 2001:db8:100::/48 and forwards it to a few servers.

Start from default drop

Use one inet table so IPv4 and IPv6 share the same rules where that makes sense:

table inet edge { set mgmt6 { type ipv6_addr; flags interval; elements = { 2001:db8:ffff::/64 } } set web6 { type ipv6_addr; elements = { 2001:db8:100:10::80 } } chain input { type filter hook input priority 0; policy drop; ct state established,related accept ct state invalid drop iif lo accept meta l4proto ipv6-icmp jump icmp6_in tcp dport 179 ip6 saddr 2001:db8:0:1::1 accept tcp dport 22 ip6 saddr @mgmt6 accept } chain forward { type filter hook forward priority 0; policy drop; ct state established,related accept ct state invalid drop meta l4proto ipv6-icmp jump icmp6_fwd ip6 daddr @web6 tcp dport { 80, 443 } accept } chain output { type filter hook output priority 0; policy accept; } } 

Two details matter. BGP on port 179 is accepted only from the upstream's neighbour address. SSH is accepted only from a management set, which you can update without touching the rule itself with nft add element inet edge mgmt6 { 2001:db8:ffff:1::/64 }.

ICMPv6 is not optional

IPv6 depends on ICMPv6 for neighbour discovery and path MTU discovery. Blocking it all breaks the network in slow, confusing ways: connections hang when a large packet needs to be fragmented, and neighbours stop resolving. RFC 4890 lists what to allow. A practical version:

chain icmp6_in { icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem } accept icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } ip6 hoplimit 255 accept icmpv6 type echo-request limit rate 10/second accept drop } chain icmp6_fwd { icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem } accept icmpv6 type echo-request limit rate 50/second accept drop } 

The hop limit check of 255 on neighbour discovery is a cheap guard: legitimate ND packets are sent with hop limit 255, so anything lower has been routed from elsewhere and should not be trusted. Neighbour discovery is not forwarded, so it does not appear in the forward chain.

Anti-spoofing at the edge

Your edge should never receive packets from the Internet that claim a source inside your own /48, and it should never send packets with a source outside it. Add these at the top of the forward chain:

iifname "eth0" ip6 saddr 2001:db8:100::/48 drop oifname "eth0" ip6 saddr != 2001:db8:100::/48 drop 

Adjust the interface name to your WAN. The second rule is BCP 38 for your own network, and it stops a compromised server from spoofing traffic out of your edge.

Load it safely

Never apply a new ruleset over SSH without a way back. A simple pattern:

nft -c -f /etc/nftables.conf # syntax check only cp /etc/nftables.conf /root/nft.good nft -f /etc/nftables.new && sleep 60 && nft -f /root/nft.good 

If the new rules keep your SSH session alive, interrupt the command with Ctrl-C before the timer fires and keep them. If they lock you out, the old ruleset returns after sixty seconds. Start every file with flush ruleset so a reload replaces everything instead of appending duplicates.

Watch what you drop

Add a counter and a rate-limited log before the default drop while you settle in:

counter log prefix "edge-in-drop " limit rate 5/second 

Then use nft list chain inet edge input to read counters and journalctl -k | grep edge-in-drop to see what is being dropped. After a week, remove the log rule or lower the rate; the counters are enough.

Connection tracking limits

A busy proxy or DNS server can fill the conntrack table. Check usage with conntrack -C against sysctl net.netfilter.nf_conntrack_max. For high-rate UDP services, consider notrack rules in a raw priority chain for that traffic so it bypasses connection tracking entirely, and write matching stateless accept rules.

After the session comes up

When the upstream accepts your LOA from the IPYE portal and the prefix is live, scan yourself from outside with nmap -6 -Pn against the published addresses. You should see exactly the ports in the web6 rule and nothing else. Rerun that scan after every firewall change.

Do this next

Write and test the ruleset on a lab VM, then claim a free /48 from IPYE and announce it only once the firewall is in place. Questions: ipye@turnel.com.

About IPYE

IPYE (https://ipye.com) leases IPv4, IPv6 and ASN space with instant setup. Your first IPv6 /48 is free for the first year, a real allocation you can announce on your own ASN, with a LOA from the portal and the ROA created automatically. ASN and region changes apply automatically. IPv4 /24 to /22 leases include LOA, ROA and per-/24 rDNS; WHOIS is editable on IPv6 /44 and larger. Locations: Los Angeles, New York, Ashburn, Salt Lake City, London, Amsterdam, Frankfurt. Claim your free /48: https://my.ipye.com/products/ipv6-rental. Questions: ipye@turnel.com.

Disclosure: I run IPYE