During Winter break I deployed a couple of services in my LAN that I want to make accessible from the internet. I did not want to use Cloudflare tunnel but I still want to use my own domain without using a dynamic IP service.
So after I’ve deployed the services, I created the DNS record and a scheduled job to keep those records updated with the current public IPv4 of my home connectivity.
When I tried to access those services using the DNS name from within my LAN i realized that I was redirected to the Edgerouter Web GUI, my LAN gateway, and of course this was unexpected. After some thinking I recall that this is a common issue that is called NAT reflection or haripin NAT.
After some research I found this article in the Ubiquiti documentation that explains how to configure the hairpin NAT on an Edgerouter. Awesome. I went through it and I realized that this works as long as you have a static public IP, but if the IP of your internet connectivity change, then hairpin NAT is not going to work.
Then I remembered I found somewhere that you can run bash script as a scheduled job in the Edgerouter devices, so after poking around I was able to setup a bash script to update the public IP of the NAT rule in an automated fashion, but in order to be able to do this I had to use a dynamic DNS service, so that I can resolve the DNS record associated with my internet connectivity and compare it to the one that is configured.
So in the end I used a dynamic IP service, but just to keep track of my internet IP address. To access the service I use a domain I own, as planned.
Bash script
I leave here the script i wrote, in case someone may need it. It can also be found on my Github
#/bin/bash
# Hostnames to look up
hostname=example.ddns.net
# NAT rule to update
nat_rule="7"
# get current address configured in the hairpin NAT rule
wan_addr=$(/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration commands | grep "set service nat rule $nat_rule destination address" | awk '{ print $8 }' )
# resolve the hostname
resolved_ip=$(getent hosts $hostname | awk '{ print $1 }')
# Update NAT rule if the IP changed
if [[ $resolved_ip == $wan_addr ]]
then
# IP did not change. Do nothing
:
else
#if addresses have changed, update the NAT rule in place
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper begin
/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper set service nat rule "$nat_rule" destination address "$resolved_ip"
/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper commit
/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper save
/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper end
fi