You maybe wondering what I mean by dynamic DNS for PPPoE connections, well, when you connect to your Internet provider using PPPoE, your public IP address may or may not be dynamic, it means that it will change each time you have to reconnect.

PPPoE connections can stop working by several reasons, when this happens your ppp daemon will try to reconnect.

At this point, your connection is established, but your public IP maybe a new one, if you are self-hosting sites at home behind your Internet router, this change of your public IP can disrupt the availability of your site.

Back in the days of DSL connections or Dial Up connections the alternatives to have a dynamic DNS solution for your always changing public IP was to pay around $10 bucks per year to a dynamic DNS provider such as no-ip.

In contrast with the past, mayor DNS providers exposes an interface (API) so you can manage your DNS records programmatically, this opens the door for solve the problem of your public IP address changing on each connection automatically.

Solution

The Debian package ppp provides a bash script under /etc/ppp/ip-up that will be called each time your pppd daemon have to reconnect.

The script ip-up wil use run-parts to execute programs under the directory /etc/ppp/ip-up.d

I added a script that uses the CloudFlare cli flarectl and updates automatically my DNS records.

The script ip-up provides a set of environment variables that you can use:

#    Arg  Name                          Example
#    $1   Interface name                ppp0
#    $2   The tty                       ttyS1
#    $3   The link speed                38400
#    $4   Local IP number               12.34.56.78
#    $5   Peer  IP number               12.34.56.99
#    $6   Optional ``ipparam'' value    foo

# These variables are for the use of the scripts run by run-parts
PPP_IFACE="$1"
PPP_TTY="$2"
PPP_SPEED="$3"
PPP_LOCAL="$4"
PPP_REMOTE="$5"
PPP_IPPARAM="$6"
export PPP_IFACE PPP_TTY PPP_SPEED PPP_LOCAL PPP_REMOTE PPP_IPPARAM

I am passing the value of the environment variable $PPP_LOCAL that contains my current public IP address to flarectl in order to update my DNS records.

The following script lives under /etc/ppp/ip-up.d and it's still a work in progress, but it's working fine so far:

#!/bin/sh
#
# PPP up hook script for update cloudflare DNS record
#

# PPP_LOCAL environment variable contents the loca IP for PPP connection

# get cloudflare token from pass
export CF_API_TOKEN=$(pass cloudflare.com/token)

# get record id for record to update
ZONE_NAME="walter.bio"
RECORD_NAME="walter.bio"
RECORD_TYPE="A"


RECORD_ID=$(flarectl --json dns l --zone "${ZONE_NAME}" | jq -r ".[] | select(.Name==\"${RECORD_NAME}\" and .Type==\"${RECORD_TYPE}\") | .ID")

if flarectl --json dns u --zone "${ZONE_NAME}" --id "${RECORD_ID}" --content "${PPP_LOCAL}"; then
    echo "flarectl: record ${RECORD_NAME} updated with content: ${PPP_LOCAL}" | systemd-cat -p info
else
    echo "flarectl: unable to update record $RECORD_NAME" | systemd-cat -p err
fi

Requirements

The script requires flarectl and jq, the installation process it's fairly symple:

apt install jq
go install github.com/cloudflare/cloudflare-go/cmd/flarectl@latest

flarectl requires a CloudFlare token or API key for authentication, I am using pass to store the token encrypted:

  apt install pass

  pass init <email@of-the-gpg-key>