DDNS update from interface not working

I am running VyOS 2025.09.17-0018-rolling.

DDNS doesn’t work with certain configurations.
Trying to use interface pppoe0 as the source address with protocol noip will not work.

This is my DDNS configuration:

service {
    dns {
        dynamic {
            name ddns0 {
                address {
                    interface pppoe0
                }
                host-name xy.ddns.net
                password ****************
                protocol noip
                username usr
            }
        }
    }
}

Which generates the following config in /run/ddclient/ddclient.conf:

### Autogenerated by service_dns_dynamic.py ###
ssl=yes
web=googledomains
use=no


# Web service dynamic DNS configuration for ddns0: [noip, xy.ddns.net]
usev4=ifv4, \
ifv4=pppoe0, \
protocol=noip, \
login=usr, \
password='pwd' \
xy.ddns.net
vyos@vyos:~$

This, by default, does not work.

vyos@vyos:~$ sudo ddclient -daemon=0 -debug -verbose -noquiet -cache /run/ddclient/ddclient.cache-2025-09-21 -file /run/ddclient/ddclient.conf
=== opt ====
opt{cache}                           : /run/ddclient/ddclient.cache-2025-09-21
opt{cmd}                             : <undefined>
opt{cmd-skip}                        : <undefined>
opt{cmdv4}                           : <undefined>
opt{cmdv6}                           : <undefined>
opt{daemon}                          : 0
opt{debug}                           : 1
opt{exec}                            : <undefined>
opt{facility}                        : <undefined>
opt{file}                            : /run/ddclient/ddclient.conf
opt{force}                           : <undefined>
opt{foreground}                      : <undefined>
opt{fw}                              : <undefined>
opt{fw-banlocal}                     : CODE(0x555acf228408)
opt{fw-login}                        : <undefined>
opt{fw-password}                     : <undefined>
opt{fw-skip}                         : <undefined>
opt{fw-ssl-validate}                 : <undefined>
opt{fwv4}                            : <undefined>
opt{fwv4-skip}                       : <undefined>
opt{fwv6}                            : <undefined>
opt{fwv6-skip}                       : <undefined>
opt{geturl}                          : <undefined>
opt{help}                            : <undefined>
opt{host}                            : <undefined>
opt{if}                              : <undefined>
opt{if-skip}                         : CODE(0x555acf228408)
opt{ifv4}                            : <undefined>
opt{ifv6}                            : <undefined>
opt{ip}                              : <undefined>
opt{ipv4}                            : <undefined>
opt{ipv6}                            : <undefined>
opt{list-devices}                    : CODE(0x555acf400940)
opt{list-protocols}                  : CODE(0x555acf42bd18)
opt{list-web-services}               : CODE(0x555acf44fcb0)
opt{login}                           : <redacted>
opt{mail}                            : <undefined>
opt{mail-failure}                    : <undefined>
opt{max-interval}                    : 2592000
opt{max-warn}                        : <undefined>
opt{min-error-interval}              : 300
opt{min-interval}                    : 30
opt{options}                         : <undefined>
opt{password}                        : <redacted>
opt{pid}                             : <undefined>
opt{postscript}                      : <undefined>
opt{priority}                        : <undefined>
opt{protocol}                        : <undefined>
opt{proxy}                           : <undefined>
opt{query}                           : <undefined>
opt{quiet}                           : 0
opt{retry}                           : <undefined>
opt{server}                          : <undefined>
opt{ssl}                             : <undefined>
opt{ssl_ca_dir}                      : <undefined>
opt{ssl_ca_file}                     : <undefined>
opt{syslog}                          : <undefined>
opt{test}                            : <undefined>
opt{timeout}                         : <undefined>
opt{use}                             : <undefined>
opt{usev4}                           : <undefined>
opt{usev6}                           : <undefined>
opt{verbose}                         : 1
opt{web}                             : <undefined>
opt{web-skip}                        : <undefined>
opt{web-ssl-validate}                : <undefined>
opt{webv4}                           : <undefined>
opt{webv4-skip}                      : <undefined>
opt{webv6}                           : <undefined>
opt{webv6-skip}                      : <undefined>
=== globals ====
globals{cache}                       : /run/ddclient/ddclient.cache-2025-09-21
globals{daemon}                      : 60
globals{debug}                       : 1
globals{file}                        : /run/ddclient/ddclient.conf
globals{quiet}                       : 0
globals{ssl}                         : 1
globals{use}                         : no
globals{verbose}                     : 1
globals{web}                         : googledomains
=== config ====
config{xy.ddns.net}{atime}    : 0
config{xy.ddns.net}{cacheable} : ARRAY(0x555acf5f9138)
config{xy.ddns.net}{custom}   : 0
config{xy.ddns.net}{host}     : xy.ddns.net
config{xy.ddns.net}{ip}       : <undefined>
config{xy.ddns.net}{login}    : <redacted>
config{xy.ddns.net}{max-interval} : 2160000
config{xy.ddns.net}{min-error-interval} : 300
config{xy.ddns.net}{min-interval} : 30
config{xy.ddns.net}{mtime}    : 0
config{xy.ddns.net}{password} : <redacted>
config{xy.ddns.net}{protocol} : noip
config{xy.ddns.net}{server}   : dynupdate.no-ip.com
config{xy.ddns.net}{static}   : 0
config{xy.ddns.net}{status}   :
config{xy.ddns.net}{warned-min-error-interval} : 0
config{xy.ddns.net}{warned-min-interval} : 0
config{xy.ddns.net}{wtime}    : 30
=== cache ====
cache{xy.ddns.net}{atime}     : 0
cache{xy.ddns.net}{custom}    : 0
cache{xy.ddns.net}{host}      : xy.ddns.net
cache{xy.ddns.net}{mtime}     : 0
cache{xy.ddns.net}{static}    : 0
cache{xy.ddns.net}{status}    :
cache{xy.ddns.net}{warned-min-error-interval} : 0
cache{xy.ddns.net}{warned-min-interval} : 0
cache{xy.ddns.net}{wtime}     : 30
WARNING:  Could not determine an IP for xy.ddns.net
vyos@vyos:~$

The problem seems to be the backslashes breaking the configuration.

If I remove them from the config file:

vyos@vyos# sudo cat /run/ddclient/ddclient.conf
### Autogenerated by service_dns_dynamic.py ###
ssl=yes
web=googledomains
use=no


# Web service dynamic DNS configuration for ddns0: [noip, xy.ddns.net]
usev4=ifv4,
ifv4=pppoe0,
protocol=noip,
login=usr,
password='pwd'
xy.ddns.net
[edit]
vyos@vyos#

DDNS will immediately start updating properly:

vyos@vyos:~$ restart dns dynamic
vyos@vyos:~$ sudo ddclient -daemon=0 -debug -verbose -noquiet -cache /run/ddclient/ddclient.cache-2025-09-21 -file /run/ddclient/ddclient.conf
=== opt ====
opt{cache}                           : /run/ddclient/ddclient.cache-2025-09-21
opt{cmd}                             : <undefined>
opt{cmd-skip}                        : <undefined>
opt{cmdv4}                           : <undefined>
opt{cmdv6}                           : <undefined>
opt{daemon}                          : 0
opt{debug}                           : 1
opt{exec}                            : <undefined>
opt{facility}                        : <undefined>
opt{file}                            : /run/ddclient/ddclient.conf
opt{force}                           : <undefined>
opt{foreground}                      : <undefined>
opt{fw}                              : <undefined>
opt{fw-banlocal}                     : CODE(0x563234c7b238)
opt{fw-login}                        : <undefined>
opt{fw-password}                     : <undefined>
opt{fw-skip}                         : <undefined>
opt{fw-ssl-validate}                 : <undefined>
opt{fwv4}                            : <undefined>
opt{fwv4-skip}                       : <undefined>
opt{fwv6}                            : <undefined>
opt{fwv6-skip}                       : <undefined>
opt{geturl}                          : <undefined>
opt{help}                            : <undefined>
opt{host}                            : <undefined>
opt{if}                              : <undefined>
opt{if-skip}                         : CODE(0x563234c7b238)
opt{ifv4}                            : <undefined>
opt{ifv6}                            : <undefined>
opt{ip}                              : <undefined>
opt{ipv4}                            : <undefined>
opt{ipv6}                            : <undefined>
opt{list-devices}                    : CODE(0x563234e53610)
opt{list-protocols}                  : CODE(0x563234e7e2a8)
opt{list-web-services}               : CODE(0x563234ea2300)
opt{login}                           : <redacted>
opt{mail}                            : <undefined>
opt{mail-failure}                    : <undefined>
opt{max-interval}                    : 2592000
opt{max-warn}                        : <undefined>
opt{min-error-interval}              : 300
opt{min-interval}                    : 30
opt{options}                         : <undefined>
opt{password}                        : <redacted>
opt{pid}                             : <undefined>
opt{postscript}                      : <undefined>
opt{priority}                        : <undefined>
opt{protocol}                        : <undefined>
opt{proxy}                           : <undefined>
opt{query}                           : <undefined>
opt{quiet}                           : 0
opt{retry}                           : <undefined>
opt{server}                          : <undefined>
opt{ssl}                             : <undefined>
opt{ssl_ca_dir}                      : <undefined>
opt{ssl_ca_file}                     : <undefined>
opt{syslog}                          : <undefined>
opt{test}                            : <undefined>
opt{timeout}                         : <undefined>
opt{use}                             : <undefined>
opt{usev4}                           : <undefined>
opt{usev6}                           : <undefined>
opt{verbose}                         : 1
opt{web}                             : <undefined>
opt{web-skip}                        : <undefined>
opt{web-ssl-validate}                : <undefined>
opt{webv4}                           : <undefined>
opt{webv4-skip}                      : <undefined>
opt{webv6}                           : <undefined>
opt{webv6-skip}                      : <undefined>
=== globals ====
globals{cache}                       : /run/ddclient/ddclient.cache-2025-09-21
globals{daemon}                      : 60
globals{debug}                       : 1
globals{file}                        : /run/ddclient/ddclient.conf
globals{ifv4}                        : pppoe0
globals{login}                       : <redacted>
globals{password}                    : <redacted>
globals{protocol}                    : noip
globals{quiet}                       : 0
globals{ssl}                         : 1
globals{use}                         : no
globals{usev4}                       : ifv4
globals{verbose}                     : 1
globals{web}                         : googledomains
=== config ====
config{xy.ddns.net}{atime}    : 0
config{xy.ddns.net}{cacheable} : ARRAY(0x56323504b698)
config{xy.ddns.net}{custom}   : 0
config{xy.ddns.net}{host}     : xy.ddns.net
config{xy.ddns.net}{ip}       : <undefined>
config{xy.ddns.net}{login}    : <redacted>
config{xy.ddns.net}{max-interval} : 2160000
config{xy.ddns.net}{min-error-interval} : 300
config{xy.ddns.net}{min-interval} : 30
config{xy.ddns.net}{mtime}    : 0
config{xy.ddns.net}{password} : <redacted>
config{xy.ddns.net}{protocol} : noip
config{xy.ddns.net}{server}   : dynupdate.no-ip.com
config{xy.ddns.net}{static}   : 0
config{xy.ddns.net}{status}   :
config{xy.ddns.net}{warned-min-error-interval} : 0
config{xy.ddns.net}{warned-min-interval} : 0
config{xy.ddns.net}{wtime}    : 30
=== cache ====
cache{xy.ddns.net}{atime}     : 0
cache{xy.ddns.net}{custom}    : 0
cache{xy.ddns.net}{host}      : xy.ddns.net
cache{xy.ddns.net}{ip}        : x.x.x.x
cache{xy.ddns.net}{mtime}     : 1758479614
cache{xy.ddns.net}{static}    : 0
cache{xy.ddns.net}{status}    : good
cache{xy.ddns.net}{warned-min-error-interval} : 1758479767
cache{xy.ddns.net}{warned-min-interval} : 0
cache{xy.ddns.net}{wtime}     : 30
WARNING:  'if-skip' is deprecated and does nothing for IPv4
DEBUG:    Reply from 'ip -4 -o addr show dev pppoe0 scope global' :
DEBUG:    ------
DEBUG:    8: pppoe0    inet x.x.x.x peer x.x.x.x/32 scope global pppoe0\       valid_lft forever preferred_lft forever
DEBUG:    ------
DEBUG:    get_ipv4: using (ifv4, pppoe0) reports x.x.x.x
Use of uninitialized value in string eq at /usr/bin/ddclient line 3549.
Use of uninitialized value in string ne at /usr/bin/ddclient line 3563.
DEBUG:
DEBUG:    nic_noip_update -------------------
INFO:     setting IP address to x.x.x.x for xy.ddns.net
UPDATE:   updating xy.ddns.net
DEBUG:    proxy    = <undefined>
DEBUG:    protocol = https
DEBUG:    server   = dynupdate.no-ip.com
DEBUG:    url      = nic/update?<redacted>
DEBUG:    ip ver   = 0
SENDING:  Curl system cmd to https://dynupdate.no-ip.com
SENDING:  silent
SENDING:  include
SENDING:  user-agent="ddclient/3.11.2"
SENDING:  connect-timeout=120
SENDING:  max-time=120
SENDING:  request=GET
SENDING:  user="usr:pwd"
SENDING:  url="https://dynupdate.no-ip.com/nic/update?system=noip&hostname=xy.ddns.net&myip=x.x.x.x"
DEBUG:    CURL: \/usr\/bin\/curl
DEBUG:    CURL Tempfile: /tmp/ddclient_saODSxzYiC
RECEIVE:  HTTP/1.1 200 OK
RECEIVE:  Server: nginx
RECEIVE:  Content-Type: text/plain; charset=UTF-8
RECEIVE:  Transfer-Encoding: chunked
RECEIVE:  Connection: keep-alive
RECEIVE:  Cache-Control: no-cache, private
RECEIVE:  Date: Sun, 21 Sep 2025 18:37:04 GMT
RECEIVE:
RECEIVE:  nochg x.x.x.x
WARNING:  updating xy.ddns.net: nochg: No update required; unnecessary attempts to change to the current address are considered abusive
vyos@vyos:~$

This solution works, but upon restarting VyOS, it regenerates the ddclient config with backslashes.

Doing a bit of snooping, I found that the ddclient config file is generated by /usr/share/vyos/templates/dns-dynamic/ddclient.conf.j2.

Editing this file to remove the backslashes from the end of the lines:

vyos@vyos:~$ sudo cat /usr/share/vyos/templates/dns-dynamic/ddclient.conf.j2
{% macro render_config(host, address, web_options, ip_suffixes=['']) %}
{% for ipv in ip_suffixes %}
use{{ ipv }}={{ address if address == 'web' else 'if' }}{{ ipv }},
{%     if address == 'web' %}
{%         if web_options.url is vyos_defined %}
web{{ ipv }}={{ web_options.url }},
{%         endif %}
{%         if web_options.skip is vyos_defined %}
web{{ ipv }}-skip='{{ web_options.skip }}',
{%         endif %}
{%     else %}
if{{ ipv }}={{ address }},
{%     endif %}
{% endfor %}
{% for k,v in kwargs.items() if v is vyos_defined %}
{{ k | replace('_', '-') }}={{ "'%s'" % (v) if k == 'password' else v }}{{ ',' if not loop.last }}
{% endfor %}
{{ host }}
{% endmacro %}
### Autogenerated by service_dns_dynamic.py ###
ssl=yes
web=googledomains
use=no

{% if name is vyos_defined %}
{%     for service, config in name.items() %}
{%         if config.description is vyos_defined %}

# {{ config.description }}
{%         endif %}
{%         for host in config.host_name if config.host_name is vyos_defined %}
{#             ip_suffixes can be either of ['v4'], ['v6'], ['v4', 'v6'] for all protocols except 'nsupdate'
               ip_suffixes must be [''] for nsupdate since it doesn't support usevX/wantipvX yet #}
{%             set ip_suffixes = ['v4', 'v6'] if config.ip_version == 'both'
                                 else ([config.ip_version[2:]] if config.protocol != 'nsupdate'
                                       else ['']) %}
{%             set password = config.key if config.protocol == 'nsupdate'
                              else config.password %}
{%             set address = 'web' if config.address.web is vyos_defined
                              else config.address.interface %}
{%             set web_options = config.address.web | default({}) %}

# Web service dynamic DNS configuration for {{ service }}: [{{ config.protocol }}, {{ host }}]
{{ render_config(host, address, web_options, ip_suffixes,
                 protocol=config.protocol, server=config.server, zone=config.zone,
                 login=config.username, password=password, ttl=config.ttl,
                 min_interval=config.wait_time, max_interval=config.expiry_time) }}
{%         endfor %}
{%     endfor %}
{% endif %}
vyos@vyos:~$

Will make it so that upon rebooting the router, the config file will generate like so:

vyos@vyos:~$ sudo cat /run/ddclient/ddclient.conf
### Autogenerated by service_dns_dynamic.py ###
ssl=yes
web=googledomains
use=no


# Web service dynamic DNS configuration for ddns0: [noip, xy.ddns.net]
usev4=ifv4,
ifv4=pppoe0,
protocol=noip,
login=usr,
password='pwd'
xy.ddns.net
vyos@vyos:~$

Which, as previously explained, works!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.