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!