Simple IPv4 to IPv6 proxy
Already a few years ago, I wanted to make my NAS reachable from the internet so that I can host a Nextcloud on my very own hardware, so I don’t have to move my personal data to an (untrusted) machine. There is only one issue: My home network is only reachable via IPv6, but there are so many networks outside that are IPv4 only (e.g. 2 out of 3 mobile networks in Germany). One option would be to pay my ISP to give me an IPv4 address, but this was something like 5€ extra per month, and then I’d still have to fight downtimes due to daily changing IPv4 addresses.
Simple Proxy
After a little research, I found a cheaper solution I’d like to share here: Use a cheap VPS as an IPv4 to IPv6 proxy.
Disclaimer: I don’t run this exact setup myself anymore, but I’m pretty sure that it still works.
A VPS is a cheap virtual machine in a data center you can easily configure online. The cheapest configuration should be sufficient, as long as there is a static IPv4 included. At least a few years ago, this was often available for around 3€/month.
So this is what the setup will look like:
The figure already reveals that all software we need to run on the VPS is socat
.
Socat is a stock-standard command line utility that can be installed on virtually any UNIX like operating system and is incredibly versatile.
To forward any traffic on a certain port to a different host, we can use the following command:
socat TCP4-LISTEN:80,fork,su=nobody,reuseaddr "TCP6:[1234:ab12::4321]:80"
So let’s decipher this a little bit:
TCP4-LISTEN:80
:socat
should listen to any traffic on port80
fork
: create a new process on every new connection. This is necessary to support multiple connections simultaneously.su=nobody
: Not 100% sure, but I think this changes the newly created processes to the unprivilegednobody
user, reducing the risk of security issues.reuseaddr
: With this option,socat
does not bind to port80
exclusively. This is very helpful when restarting the script, as after killing a program using a socket, it takes several seconds, until it is available again."TCP6:[1234:ab12:0:...:4321]:80"
: This tellssocat
to forward any traffic to the specified IPv6 address (e.g.,1234:ab12::4321
) on port80
.
A script to rule it all
Ok, fairly simple, and for testing purposes it is sufficient to run the above command in a terminal on the VPS, but to automate this, I’ve written the following script:
#! /bin/bash
UPDATE_INTERVAL=15 # check for new IPv6 addresses every 15 seconds
IP_ADDR_FILE=/home/jonathan/ipv6address.txt
function start_socat {
socat TCP4-LISTEN:80,fork,su=nobody,reuseaddr "TCP6:[$1]:80" &
ID_SOCAT_80=$!
socat TCP4-LISTEN:443,fork,su=nobody,reuseaddr "TCP6:[$1]:443" &
ID_SOCAT_443=$!
}
SERVERADDR=$(cat $IP_ADDR_FILE)
start_socat $SERVERADDR
# recreate socat processes if necessary
while true; do
SERVERADDR_NEW=$(cat $IP_ADDR_FILE)
if [ "$SERVERADDR_NEW" != "$SERVERADDR" ]; then
SERVERADDR=$SERVERADDR_NEW
date
echo "IP_difference: IP address: $SERVERADDR new IP address: $SERVERADDR_NEW"
kill $ID_SOCAT_80 $ID_SOCAT_443
sleep 5
start_socat $SERVERADDR
fi
sleep $UPDATE_INTERVAL
done
What this script does is, that it reads my NAS’ IPv6 address from a file ipv6address.txt
and starts two socat
processes - one for port 80 (http
) and one for port 443 (https
).
The remainder of the script is simply polling the file with the IPv6 address and recreates the socat
processes with adjusted IPv6 addresses if necessary.
At the same time, a cronjob on my NAS was constantly updating the IPv6 address file via SSH, something like:
IPv6_ADDRESS=$(ip -6 a | grep 'global' | grep -v 'deprecated'| \
awk '{print $2}' | grep -v '^fd' | grep -v '^fc' | \
sed 's|/.*||' | head -n1)
ssh user@vps-server 'echo IPv6_address > /home/jonathan/ipv6address.txt'
Systemd Service
Ok, last thing to do is to create a systemd service, so that the script above is started automatically and output is logged nicely with journald. Create /etc/systemd/socat_forward.service
with the following content:
[Unit]
Description=Socat IPv4 to IPv6 forward
[Service]
ExecStart=/home/jonathan/socatscript.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
Execute systemctl enable socat_forward.service && systemctl start socat_forward.service
, and the VPS forwards all port 80 & 443 traffic to the NAS.
I’d be happy to hear if you are using this technique or something similar! 🙂👍