From e66c4f35b9acf40bb48337a52d6333b744ced7c3 Mon Sep 17 00:00:00 2001 From: lol3rrr Date: Fri, 20 Mar 2026 16:05:52 +0100 Subject: [PATCH] Start rewording and rewriting the ipv4 expose post --- content/homelab-ipv4-expose/index.md | 45 +++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/content/homelab-ipv4-expose/index.md b/content/homelab-ipv4-expose/index.md index f961b44..23a1d02 100644 --- a/content/homelab-ipv4-expose/index.md +++ b/content/homelab-ipv4-expose/index.md @@ -7,28 +7,45 @@ draft = true [taxonomies] categories = ["Homelab"] tags = ["Homelab", "IPv4", "IPv6"] + +[extra] +toc = true +++ -## Motivation +How I am currently exposing the services running in my homelab to IPv4 users despite not having a publicly routable IPv4 address/subnet. + + + + +# Motivation The problem I have is one that a lot of people in the self-hosting community will be familiar with. -My ISP does not give me a public IPv4 address, which I could use to expose my self-hosted services to the broader internet. +My ISP does not give me a public IPv4 address, to expose my self-hosted services to the broader internet. -Luckily my ISP provides me with a publicly routable `/48` IPv6 address space. -So I natively expose my services to the internet using IPv6 and use the approach outlined below to expose my services for IPv4 users as well. +Luckily my ISP provides me with a publicly routable `/48` IPv6 subnet. +So I natively expose my services to the internet using IPv6 and then only have the problem of allowing native IPv4 only clients to use my IPv6 services as well. -## Previous Setup +# Old Setup Currently I rent a VPS from DigitalOcean, which then naively forwards any TCP connections to my IPv6 services. For this it periodically loads all services I have registered in Consul and looks for specific tags, which I use to mark services that should be exposed. For each such service, it then starts a TCP-listener on it's public IPv4 address and for all incoming requests connects to the IPv6 service being exposed, forwarding all data in both directions. -## Idea 1 - The Plan +# Idea 1 - SIIT-EAM +## The Idea +SIIT-EAM (Stateless IP/ICMP Translation) allows one to have a "translator" in the network, which receives the incoming IPv4 packets and translates them into their corresponding IPv6 destinations. +The translator needs to have one more public IPv4 and an IPv6 subnet with at least "free" 32 bits. +One can then configure how the public IPv4 addresses should map to IPv6 addresses and the translator will act as a middle-man between IPv4 and IPv6. + +For more details I would recommend going through the jool[^jool] documentation. + +## The Plan Services that need to be exposed get their own virtual IPv6 address using keepalived. The active/master node will be forced to the node on which the service is currently running using priorities. On my external server setup Jool with SIIT-DC and iptable rules. 1. Everything coming in at the given port for the service (for example HTTP, Teamspeak, etc.) is redirected to a different internal IPv4 address using iptables 2. Jool listens on the internal IPv4 address and performs SIIT-DC or SIIT-EAM forwarding to the correct virtual IPv6 address -## Idea 1 - New Setup - Part 1 SIIT-EAM +## Setup +{% details(summary="Detailed instructions on how to setup everything") %} 1. Get a server that supports Dual-Stack networking and in the best case a /64 ipv6 subnet (I choose Scaleway as a European cloud provider, with cheap servers) [Scaleway IPv6 Docs](https://www.scaleway.com/en/docs/instances/how-to/use-flexips/#flexible-ipv6) [Scaleway Check neighbor discovery](https://www.scaleway.com/en/docs/dedibox-ipv6/how-to/debug-ipv6/#check-the-neighbor-discovery-protocol-ndp) @@ -56,8 +73,9 @@ On my external server setup Jool with SIIT-DC and iptable rules. } } ``` +{% end %} -### Idea 1 - Troubles +## Troubles Jool missing pool6, because I first wanted to try with only the EAM entry Lots of debugging with tcpdump on external and local server @@ -68,11 +86,16 @@ fixed using ndppd. Fixed forwarding for everything received on the v4 ip, no way to forward based on service -## Idea 2 - NAT64 with static BIB +# Idea 2 - NAT64 with static BIB +## The Idea The idea with this is to basically perform some static NAT64, to map ports on the ipv4 side to specific addresses and ports on the ipv6 side. This would allow me to have one entry for every port that I want to expose, regardless of the IPv6 or port of the service. +## Compared to Idea 1 +More fine grained stuff +## Setup +{% details(summary="Detailed instructions on how to setup everything") %} 1. Same 2. Same 3. Same @@ -86,13 +109,15 @@ This would allow me to have one entry for every port that I want to expose, rega 7. Example Setup of bib[^bib_explained] entries (for teamspeak3 in this case) 1. `jool -i "example" bib add 2001:4dd5:b276:1:f652:14ff:fe94:dc00#9987 51.158.177.228#9987 --udp`[^bib_add_command] 2. `jool -i "example" bib add 2001:4dd5:b276:1:f652:14ff:fe94:dc00#30033 51.158.177.228#30033 --tcp`[^bib_add_command] +{% end %} -## Future Work +# Future Work - Automate the jool setup (ansible playbook or maybe even using cloud-init) - Automate the configuration of the corresponding entries (likely a custom integration with consul) ## References +[^jool]: [Jool Homepage](https://www.jool.mx/en/index.html) [^nat64_setup]: [basic NAT64 tutorial](https://www.jool.mx/en/run-nat64.html) [^pool4_setup]: We need to configure the [pool4](https://www.jool.mx/en/pool4.html) used by jool using the given [pool4 commands](https://nicmx.github.io/Jool/en/usr-flags-pool4.html) [^bib_explained]: [BIB](https://www.jool.mx/en/bib.html)