Set Up IPv6 on Raspberry Pi with DNS & Reverse Proxy

IPv6 Setup Raspberry Pi Guide

Introduction

IPv6 on Raspberry Pi isn’t magic, but it does take more work than people expect. You don’t just slap an IPv6 address on a service and walk away. There’s static addressing, reverse proxy setup, DNS records, and if you’re lucky, a router that doesn’t throw a tantrum. Most of the time, it feels like your Pi is perfectly fine talking to the world until you realize nobody’s talking back because DNS is busted or the reverse proxy is clueless.

I’ll walk you through getting your Raspberry Pi online with IPv6, setting up a reverse proxy using Nginx, and making sure your DNS records actually point to the right address. We’ll deal with static IPv6, AAAA records, and a few things your ISP probably didn’t tell you.

Key Takeaways

  • IPv6 gives your Raspberry Pi public access without NAT but needs careful firewall and DNS setup.
  • Static IPv6 setup avoids service downtime due to address changes.
  • Nginx handles multiple services under one IPv6 address using reverse proxy rules.
  • AAAA records are critical for IPv6 reachability and must point to the correct address.
  • Use Dynamic DNS if your public IPv6 prefix isn’t static.

Choosing the Right Raspberry Pi and OS

Picking a model that won’t choke on packets

Not all Raspberry Pi models are equal. If you’re planning to run multiple services, forward traffic, and handle IPv6 lookups without latency, go for at least a Raspberry Pi 4. The 3B+ is decent if you’re patient. Anything older or with only 512MB RAM might crash once you throw a reverse proxy into the mix. Trust me, I’ve tried.

Operating systems that actually speak IPv6

Raspberry Pi OS (formerly Raspbian) handles IPv6 pretty well out of the box, especially the 64-bit version. Ubuntu Server works too, though it uses netplan instead of dhcpcd. Arch Linux ARM and DietPi are lighter and snappier, but you’ll need to configure more by hand.

Enable IPv6 at the system level

Most Pi OSes already have IPv6 enabled, but double-check it didn’t get disabled by accident:

cat /proc/sys/net/ipv6/conf/all/disable_ipv6

If it returns 1, you’ve got a problem. Set it to 0 by editing /etc/sysctl.conf or creating a new file in /etc/sysctl.d/ with this:

net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0

Then reload with:

sudo sysctl -p

Assigning a Static IPv6 Address

Why dynamic IPv6 isn’t enough

Your Raspberry Pi probably got an IPv6 address through SLAAC (Stateless Address Autoconfiguration) or maybe DHCPv6. That’s fine for browsing Reddit, but not great for hosting anything. If your Pi’s address changes every time the router sneezes, your DNS records are toast and your reverse proxy breaks. Static is the way to go.

How to assign a static IPv6 address on Raspberry Pi OS

On Raspberry Pi OS, you’ll want to edit /etc/dhcpcd.conf. Add a block like this:

interface eth0
    ipv6only
    static ip6_address=2001:db8:abcd:1234::100/64
    static routers=2001:db8:abcd:1234::1
    static domain_name_servers=2001:4860:4860::8888 2001:4860:4860::8844

Make sure your IPv6 address is inside your prefix range. You’ll probably get that from your router or ISP. If you’re not sure, check with:

ip -6 route

Ubuntu or other netplan-based OS setups

For distros using netplan, go to /etc/netplan/01-netcfg.yaml or whatever your config file is called:

network:
  version: 2
  ethernets:
    eth0:
      dhcp6: no
      addresses:
        - 2001:db8:abcd:1234::100/64
      gateway6: 2001:db8:abcd:1234::1
      nameservers:
        addresses: [2001:4860:4860::8888, 2001:4860:4860::8844]

Then apply changes:

sudo netplan apply

Verify it’s working

Check your address and routes:

ip -6 addr show dev eth0
ip -6 route

You want to see your assigned address, your gateway, and ideally, no tentative or dadfailed errors.

Testing IPv6 Connectivity

Checking if the thing’s even alive

All right, your Raspberry Pi has a static IPv6 address. Great. But does it actually work? Let’s not assume. A misconfigured gateway or missing DNS server will ruin your day. You need to test it.

Basic connectivity checks

Use ping6 (or just ping with -6) to test reachability:

ping6 google.com

If that fails, try pinging an IPv6 address directly:

ping6 2001:4860:4860::8888

Still failing? That means the issue is probably routing or DNS, not the service.

Testing outbound and inbound traffic

Try reaching a public IPv6 test site:

curl -6 https://icanhazip.com

It should return your public IPv6 address. If it doesn’t, you’re either not getting a routed IPv6 prefix or the firewall is blocking it.

To test if your Raspberry Pi is reachable from the outside:

  1. Use a phone or laptop on a different network (like mobile data).
  2. Run ping6 your-pi-ipv6-address or access it via browser if you have a web service running.

Check open ports

Use nmap to see what services are available over IPv6:

nmap -6 -p 22,80,443 your-pi-ipv6-address

If you see filtered ports, your firewall or router may be interfering.

Useful diagnostics tools

  • ip -6 route show: Confirms your routing table.
  • dig AAAA google.com: Tests DNS resolution over IPv6.
  • netstat -tulnp | grep LISTEN: Shows listening services, so you know if they’re bound to IPv6.
Reverse Proxy with Nginx over IPv6

Reverse Proxy with Nginx over IPv6

Why you need a reverse proxy in the first place

If you’re running more than one service on your Raspberry Pi – like a media server, dashboard, or even your own wiki; you can’t just open up 10 different ports. That’s messy and invites trouble. A reverse proxy like Nginx lets you keep everything on ports 80 and 443, then route traffic by hostname or path. Cleaner, safer, and lets you use SSL certificates without pulling your hair out.

Install Nginx

On Raspberry Pi OS or Ubuntu:

sudo apt update
sudo apt install nginx

Enable and start it:

sudo systemctl enable nginx
sudo systemctl start nginx

Make sure it listens on IPv6

By default, Nginx might only be listening on IPv4. To add IPv6, open your site config in /etc/nginx/sites-available/default (or your custom config) and make sure it includes this:

listen [::]:80 default_server;
listen [::]:443 ssl default_server;

This tells Nginx to listen on all IPv6 interfaces for HTTP and HTTPS. Then reload it:

sudo systemctl reload nginx

Routing traffic to local services

Here’s a basic reverse proxy block for forwarding traffic to something running on port 8123 (like Home Assistant):

server {
    listen [::]:443 ssl;
    server_name yourdomain.example.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.example.com/privkey.pem;

    location / {
        proxy_pass http://[::1]:8123;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

You can add as many of these as you want for different services. Just change the domain and the port.

Check your config before restarting

Always run this to make sure your config won’t break Nginx:

sudo nginx -t

If it says everything is okay, reload it again.

sudo systemctl reload nginx

DNS Configuration with AAAA Records

Assigning a Static IPv6 Address

If nobody can find your Pi, does it even exist?

You can have the slickest IPv6 setup in town, but if DNS doesn’t point to it, nobody’s getting through. AAAA records are what tell the internet, “Hey, this domain lives at this IPv6 address.” It’s like giving out your number but forgetting to tell people which area code to use.

What’s a AAAA record?

Simple: it maps a domain name to an IPv6 address, just like an A record maps to an IPv4 one. The format’s the same, but the address looks scarier.

Example:

ipv6.mypi.example.com.  IN  AAAA  2001:db8:abcd:1234::100

Where to add them

Depends on your DNS provider. Here are some basics:

  • Cloudflare: Go to DNS > Add Record > Type: AAAA > Name: @ or ipv6 > Content: your IPv6 address.
  • DuckDNS: Add your static IPv6 address to the domain settings manually or with a script.
  • Namecheap: Same as above… just use the Advanced DNS panel.

Verify it’s working

Use dig or nslookup:

dig AAAA ipv6.mypi.example.com

You should see the IPv6 address in the answer section. If it doesn’t show, DNS hasn’t propagated or you made a typo (it happens).

DNS propagation times

Even though IPv6 records tend to propagate faster, give it a few minutes. Also check TTL (time to live) on your records – lower values like 300 seconds are good while testing.

Troubleshooting

  • Typo in address: One wrong hex group and you’re toast.
  • Firewall blocking requests: Even if DNS works, your Pi needs to actually respond to traffic.
  • Record conflict: Make sure there’s no CNAME pointing somewhere else.

Firewall and Port Forwarding for IPv6

IPv6 skips NAT, but you’re not totally off the hook

Here’s where things get weird. Unlike IPv4, IPv6 doesn’t usually need NAT. Every device can have a public address. Sounds great, right? Until you realize your Pi is now exposed to the entire internet, and if your firewall’s asleep on the job, someone else might start poking around.

Why port forwarding is different with IPv6

Because there’s no NAT, you don’t technically “forward” ports in the same way. If your Pi has a public IPv6 address, it just needs the router to route properly and your firewall to allow traffic. That’s it. No DNAT, no PAT, just basic routing and filtering.

Using UFW to allow traffic

UFW (Uncomplicated Firewall) works with IPv6 out of the box – if you turn it on for v6:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Make sure UFW is configured to manage IPv6:

Open /etc/ufw/ufw.conf and set:

IPV6=yes

Then reload:

sudo ufw reload

Check what’s open

To verify what’s allowed:

sudo ufw status

You should see both 80 and 443 allowed on “Anywhere (v6)”.

Router configuration for IPv6

Some routers support IPv6 firewall rules separately. If yours is one of them:

  • Log in to your router’s admin panel.
  • Look for “IPv6 Firewall” or “IPv6 Filtering”.
  • Allow inbound connections to the Pi’s IPv6 address on ports 80 and 443.

Watch for ISP-level filtering

Some ISPs block incoming IPv6 traffic unless you ask them nicely (or pay extra). Test this by trying to access your Pi from an external IPv6 device. If it fails and everything looks good on your end, call your ISP. They love those conversations.

Using Dynamic DNS with IPv6

What if your IPv6 changes every Tuesday at 3 a.m.?

Not everyone gets a static IPv6 prefix from their ISP. Some rotate them randomly, some change them on every reconnect, and some just like watching you suffer. If your Raspberry Pi’s public IPv6 address changes, your AAAA records become useless. This is where Dynamic DNS (DDNS) saves the day.

What Dynamic DNS actually does

It updates your DNS records automatically when your IP address changes. Most DDNS providers support IPv4 by default, but not all support IPv6, so check first.

Good IPv6-compatible DDNS providers

  • DuckDNS (free, supports IPv6, works great with scripts)
  • No-IP (supports IPv6 but might require manual updates)
  • Dynu (supports IPv6 with their API)
  • Cloudflare (use API scripts to update AAAA records directly)

Set up DuckDNS with IPv6

  1. Create an account and subdomain at duckdns.org.
  2. Use a script like this in a cron job:
curl "https://www.duckdns.org/update?domains=yourdomain&token=yourtoken&ipv6=your_ipv6_address"

Replace your_ipv6_address with the current one using a command like:

ip -6 addr show eth0 | grep 'global' | awk '{print $2}' | cut -d/ -f1

Put it in a shell script, make it executable, and run it hourly:

crontab -e

Add:

0 * * * * /home/pi/update_duckdns_ipv6.sh >/dev/null 2>&1

Cloudflare DDNS via API for IPv6

You can also use the Cloudflare API to update your AAAA record. Scripts like cloudflare-ddns on GitHub can automate this.

Test it works

Run the script manually and use dig to see if your AAAA record updates correctly:

dig AAAA yourdomain.duckdns.org

If the result changes when your Pi’s IPv6 does, you’re golden.

Securing Services with SSL

Plain HTTP is for people who enjoy living dangerously

If you’ve set up a reverse proxy and exposed it to the internet – even over IPv6 – you’re gonna want SSL. Without it, everything’s flying around unencrypted, and that’s just asking for some script kid to sniff your credentials. Encrypt your traffic. It’s free. It’s easy. There’s no excuse not to.

Use Let’s Encrypt with Certbot

Let’s Encrypt gives you free SSL certificates. Certbot handles the mess of generating, renewing, and installing them. Nginx works smoothly with it, especially when DNS is set up right.

Install Certbot:

sudo apt install certbot python3-certbot-nginx

Then run:

sudo certbot --nginx -d yourdomain.example.com

This does three things:

  • Gets a cert
  • Configures Nginx for HTTPS
  • Sets up auto-renewal

Force HTTPS

Make sure HTTP traffic gets redirected to HTTPS. Add this server block to your config:

server {
    listen [::]:80;
    server_name yourdomain.example.com;

    return 301 https://$host$request_uri;
}

That way, even if someone forgets the “s” in HTTPS, they’re still protected.

Automatic certificate renewal

Certbot sets up a renewal timer by default, but double-check:

sudo systemctl list-timers | grep certbot

You should see something that runs twice a day.

Handling multiple services

Each domain or subdomain gets its own certificate. You can re-run Certbot for each:

sudo certbot --nginx -d service1.example.com -d service2.example.com

Certbot will create a certificate that covers both.

If using a custom DDNS domain

Some free DDNS providers don’t support Let’s Encrypt’s HTTP challenge. In that case, use the DNS challenge, which requires API access to your DNS provider. Cloudflare is great for this.

Monitoring and Maintaining IPv6 Services

It worked yesterday — famous last words

Once your Raspberry Pi is running services over IPv6 with a reverse proxy and proper DNS, you might be tempted to call it a day. Don’t. IPv6 behaves differently from IPv4 in ways that can sneak up on you. Keep an eye on things unless you enjoy surprise downtime.

Watch network activity

Use iftop or vnstat to monitor live traffic. These show what’s using bandwidth, and whether anything suspicious is coming in over IPv6:

sudo apt install iftop
sudo iftop -i eth0

For long-term stats:

sudo apt install vnstat
vnstat -u -i eth0
vnstat -i eth0

Check services with systemctl

Make sure the services behind your reverse proxy are actually running:

sudo systemctl status nginx
sudo systemctl status home-assistant
sudo systemctl status pihole-FTL

Look out for expiring SSL certs

Let’s Encrypt certificates last 90 days. Certbot should renew them automatically, but run a dry-run renewal monthly just to be safe:

sudo certbot renew --dry-run

DNS verification tools

DNS misconfiguration breaks everything. Use dig or host:

dig AAAA yourdomain.com
host yourdomain.com

Make sure it resolves to your IPv6 and not some expired address from last month.

Automate config backups

Services like Nginx, Pi-hole, and DNS setups change over time. Back up /etc/nginx, /etc/pihole, and /etc/systemd/system with something like rsync or a cron job.

Check firewall rules regularly

UFW can lose its mind after updates. Double-check allowed ports:

sudo ufw status verbose

If your IPv6 rules vanish, reapply them manually or use a script.

Log alerts when things go south

Set up log monitoring tools or push notifications for service failures. A simple systemd timer and script combo can email you when Nginx fails to start.

FAQ

Q: Why does my Raspberry Pi have multiple IPv6 addresses?
A: That’s normal. IPv6 assigns multiple addresses including link-local, temporary, and stable private ones. Only use your global unicast address in DNS records.

Q: Can I use IPv6 without a reverse proxy?
A: Sure, but you’ll have to open individual ports and configure SSL manually for each service. A reverse proxy makes management easier.

Q: Do I still need Dynamic DNS with IPv6?
A: Yes, if your ISP changes your IPv6 prefix regularly. DDNS updates your DNS records when your public IP changes, keeping your services reachable.

Q: Why aren’t my AAAA records resolving?
A: Check DNS propagation, record spelling, and if your domain provider supports IPv6. Use dig or nslookup to confirm the record exists.

Q: Is my ISP blocking inbound IPv6?
A: Some do. Test externally or ask support. You may need to enable IPv6 port access on your router or request a public prefix.


References

Was this helpful?

Yes
No
Thanks for your feedback!