125 lines
6.1 KiB
Markdown
125 lines
6.1 KiB
Markdown
+++
|
|
title = "Homelab - IPv4 Expose"
|
|
date = 2026-04-04
|
|
description = "How I expose my IPv6 only Homelab for IPv4 clients"
|
|
draft = true
|
|
|
|
[taxonomies]
|
|
categories = ["Homelab"]
|
|
tags = ["Homelab", "IPv4", "IPv6"]
|
|
|
|
[extra]
|
|
toc = true
|
|
+++
|
|
|
|
How I am currently exposing the services running in my homelab to IPv4 users despite not having a publicly routable IPv4 address/subnet.
|
|
|
|
<!-- more -->
|
|
|
|
|
|
# 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, to expose my self-hosted services to the broader internet.
|
|
|
|
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.
|
|
|
|
# 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 - 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
|
|
|
|
## 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)
|
|
2. apt-get update and apt-get upgrade
|
|
3. Install Jool
|
|
1. Based on the [jool documentation](https://www.jool.mx/en/ubuntu.html)
|
|
2. `sudo apt install jool-dkms jool-tools`
|
|
3. Enable IP forwarding
|
|
- `/sbin/sysctl -w net.ipv4.conf.all.forwarding=1`
|
|
- `/sbin/sysctl -w net.ipv6.conf.all.forwarding=1`
|
|
4. Install NDP Proxy Daemon [ndppd](https://manpages.ubuntu.com/manpages/focal/man1/ndppd.1.html)
|
|
1. `sudo apt-get install ndppd`
|
|
2. `/sbin/sysctl -w net.ipv6.conf.all.proxy_ndp=1`
|
|
5. Configure [Jool](https://www.jool.mx/en/index.html)
|
|
1. `/sbin/modprobe jool_siit`
|
|
2. `jool_siit instance add "example" --netfilter --pool6 2001:0bc8:1640:6554:0:0:0:0/96`
|
|
3. `jool_siit -i "example" eamt add 2001:4dd5:b276:1:f652:14ff:fe94:dc00/128 51.158.177.228/32`
|
|
4. (Optional for debugging) `jool_siit -i "example" global update logging-debug true`
|
|
6. ndppd for neighbor discovery
|
|
1. In `/etc/ndppd.conf`
|
|
```
|
|
proxy ens2 {
|
|
rule 2001:0bc8:1640:6554:0:0:0:0/96 {
|
|
static
|
|
}
|
|
}
|
|
```
|
|
{% end %}
|
|
|
|
## 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
|
|
|
|
Neighbor Solicitation not working
|
|
`13:31:35.919212 IP6 _gateway > ff02::1:ff52:2f24: ICMP6, neighbor solicitation, who has 2001:bc8:1640:6554::4a52:2f24, length 32`
|
|
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
|
|
## 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
|
|
4. Same
|
|
5. Configure [Jool](https://www.jool.mx/en/index.html)
|
|
1. `/sbin/modprobe jool`
|
|
2. `jool instance add "example" --netfilter --pool6 2001:0bc8:1640:6554:0:0:0:0/96`[^nat64_setup]
|
|
3. `jool -i "example" pool4 add --udp 51.158.177.228 1-65535`[^pool4_setup]
|
|
4. `jool -i "example" pool4 add --tcp 51.158.177.228 1-65535`[^pool4_setup]
|
|
6. Same
|
|
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
|
|
- 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)
|
|
[^bib_add_command]: [bib commands](https://www.jool.mx/en/usr-flags-bib.html#add)
|