Wireguard - Dynamic DNS solution for automatic hostname/IP updates

I wanted to contribute something to the VyOS world, so here is a wireguard configuration and script pair
that deal with DHCP and dynamic IP’s for a VPN pair. This has been in production and works flawlessly
for over a year. I dont know how to submit contributions to this product but hopefully this makes its
way in the VyOS release toolset.

There is no firewall, routing or port forwarding information, as this is not a wireguard tutorial.

Both site A and B have Dynamic public IP addresses changed at random by ISP’s, configured via DHCP
on ETH0.

Site A is VyOS 1.5 and Site B is VyOS 1.4 (full versions shown below).

They Dynamic DNS site is afraid.org which allows dynamic hostname updates. I have configured two hostanes,
XXX_YOUR_PUBLIC_HOSTNAME_SITEA_AT_AFRAID_DOT_ORG_XXX and XXX_YOUR_PUBLIC_HOSTNAME_SITEB_AT_AFRAID_DOT_ORG_XXX

Dynamic updates of the Afraid website are done by the “service-dns-dynamic” VyOS configuration.

Once a minute, the VyOS “system-task-scheduler-task” runs the script /config/scripts/wg-peer-XXX_SCRIPTNAMESITEA_XXX
or /config/scripts/wg-peer-XXX_SCRIPTNAMESITEB_XXX on site B.

The script checks the current IP of the hostname shown using “dig” from the afraid nameservers. It then
extracts the current running IP address from the working configuration in VyOS. It checks to make sure
the IP’s are vaild (as dig can return strange things) and then compares the two. If they are different, it
will update the VyOS working configuration for the shown wireguard interface, commit, and save the configuration.
Wireguard should automatically resync.

FYI, there is a typo on the site B config and script (interface wg01 should be named wg02) but the script
and configuration work as shown. Also note the “service-dns-dnyamic” configuration is different between 1.5 and 1.4.
Again this is a working configuration as shown.

Site A (VyOS 1.5-rolling-202403250019):

wireguard wg01 {
    address 10.1.0.1/30
    description VPN-to-wg02
	peer to-wg02 {
        address XXX_PUBLICIP_XXX
        allowed-ips 0.0.0.0/0
        port 51820
        public-key XXX_MyPublicKey_XXX
    }
    port 51820
    private-key XXX_MyPrivateKey_XXX
}

system {
    task-scheduler {
        task update-wg01 {
            executable {
                path /config/scripts/wg-peer-XXX_SCRIPTNAMESITEA_XXX
            }
            interval 1m
        }
    }
}

service {
    dns {
        dynamic {
            name service-afraid-eth0 {
                address {
                    interface eth0
                }
                host-name XXX_YOUR_PUBLIC_HOSTNAME_SITEA_AT_AFRAID_DOT_ORG_XXX
                password "XXX_AFRAID_ORG_PASSWORD_XXX"
                protocol freedns
                server freedns.afraid.org
                username XXX_AFRAID_DOT_ORG_USERNAME_XXX
            }
        }
    }
}

script wg-peer-XXX_SCRIPTNAMESITEA_XXX:

#!/bin/vbash

if [ "$(id -g -n)" != 'vyattacfg' ] ; then
    exec sg vyattacfg -c "/bin/vbash $(readlink -f $0) $@"
fi
source /opt/vyatta/etc/functions/script-template

function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

newIP="$(dig +short XXX_YOUR_PUBLIC_HOSTNAME_SITEA_AT_AFRAID_DOT_ORG_XXX @ns1.afraid.org)"

oldIP=$(run show configuration commands | grep wg01 | grep to-wg02 | grep address | awk '{print $8 }' | awk '{print substr($1,2); }' | awk '{print substr($1, 1, length($1)-1)}')

if ! valid_ip $newIP
then
        echo "bad newIP: " $newIP
elif ! valid_ip $oldIP
then
        echo "bad oldIP: " $oldIP
else

        #echo "new ip" $newIP
        #echo "old ip" $oldIP

        if [ $newIP != $oldIP ]
        then
                echo "new ip" $newIP
                echo "old ip" $oldIP

                configure
                set interfaces wireguard wg01 peer to-wg02 address $newIP
                commit
                save
        fi

fi

exit

Site B (yOS 1.4-rolling-202304040317):

wireguard wg01 {
    address 10.1.0.2/30
    description VPN-to-wg01
    peer to-wg01 {
        address XXX_PUBLICIP_SITEB_XXX
        allowed-ips 0.0.0.0/0
        port 51820
        public-key XXX_MyPublicKey_XXX
    }
    port 51820
    private-key XXX_MyPrivateKey_XXX
}

system {
    task-scheduler {
        task update-wg01 {
            executable {
                path /config/scripts/wg-peer-XXX_SCRIPTNAMESITEB_XXX
            }
            interval 1m
        }
    }
}

service {
    dns {
        dynamic {
            interface eth0 {
                service afraid {
                    host-name XXX_YOUR_PUBLIC_HOSTNAME_SITEB_AT_AFRAID_DOT_ORG_XXX
                    login XXX_AFRAID_DOT_ORG_USERNAME_XXX
                    password "XXX_AFRAID_ORG_PASSWORD_XXX"
                    server freedns.afraid.org
                }
                use-web {
                    url http://ifconfig.me/ip
                }
            }
        }
    }
}

wg-peer-XXX_SCRIPTNAMESITEB_XXX:

#!/bin/vbash

if [ "$(id -g -n)" != 'vyattacfg' ] ; then
    exec sg vyattacfg -c "/bin/vbash $(readlink -f $0) $@"
fi
source /opt/vyatta/etc/functions/script-template

function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

newIP="$(dig +short XXX_YOUR_PUBLIC_HOSTNAME_SITEB_AT_AFRAID_DOT_ORG_XXX @ns1.afraid.org)"

oldIP=$(run show configuration commands | grep wg01 | grep to-wg01 | grep address | awk '{print $8 }' | awk '{print substr($1,2); }' | awk '{print substr($1, 1, length($1)-1)}')

if ! valid_ip $newIP
then
        echo "bad newIP: " $newIP
elif ! valid_ip $oldIP
then
        echo "bad oldIP: " $oldIP
else

        #echo "new ip" $newIP
        #echo "old ip" $oldIP

        if [ $newIP != $oldIP ]
        then
                echo "new ip" $newIP
                echo "old ip" $oldIP

                configure
                set interfaces wireguard wg01 peer to-wg01 address $newIP
                commit
                save
        fi

fi

exit
5 Likes