Skip to content
WebShield Docs

Home server on a dynamic address

Keeping a hostname pointed at a changing home address — router, Linux and Windows setup, proxying, and what to do about SSH.

Home connections hand out an address for a while. Reboot the router, let the ISP re-establish the session, and the address is different — everything that pointed at it stops answering. The cure: the device reports its current address and we keep the DNS record up to date.

You need: a domain delegated to our nameservers, and a device that can run curl every ten minutes.

  1. Control panel → DNS for the domain.
  2. Dynamic IP card → Add hostname. A short name such as home gives you home.example.com.
  3. Copy the token. It is shown once: a lost token cannot be recovered, only replaced.

The name appears in the records list right away, marked Dynamic. Until the first update it says “no address reported yet” — that is expected, there is no record in the zone yet.

Almost every router speaks dyndns2. Find the “DynDNS”, “Dynamic DNS” or “DDNS” section, pick a custom service — Custom, Other, dyndns2 — and fill in:

Field Value
Server / Service dyn.webshield.pro
Username home.example.com
Password the token you copied
Hostname home.example.com

If the firmware wants a full update URL:

https://dyn.webshield.pro/nic/update?hostname=home.example.com&myip=<IP>

It has to be https — we do not accept updates over plain HTTP, the token would travel in the clear. Very old firmware that does not follow the redirect from port 80 will not work; use the curl method below instead.

The built-in RouterOS client is tied to its own service, so schedule the request:

/system scheduler
add name=webshield-dyndns interval=10m on-event={
/tool fetch url="https://dyn.webshield.pro/update?token=TOKEN" keep-result=no
}

The ddns-scripts package, a custom service in /etc/config/ddns:

config service 'webshield'
option enabled '1'
option lookup_host 'home.example.com'
option domain 'home.example.com'
option username 'home.example.com'
option password 'TOKEN'
option update_url 'https://[USERNAME]:[PASSWORD]@dyn.webshield.pro/nic/update?hostname=[DOMAIN]&myip=[IP]'
option use_https '1'
option ip_source 'web'
option ip_url 'https://dyn.webshield.pro/ip'
protocol=dyndns2
server=dyn.webshield.pro
ssl=yes
use=web, web=https://dyn.webshield.pro/ip
login=home.example.com
password='TOKEN'
home.example.com

A machine behind NAT does not know its own public address — and does not need to. Send no address at all and we will use the one the request came from:

Terminal window
curl -fsS "https://dyn.webshield.pro/update?token=TOKEN"

In crontab -e:

*/10 * * * * curl -fsS "https://dyn.webshield.pro/update?token=TOKEN" >/dev/null

Or a systemd timer, if you want logs and a run after resume:

/etc/systemd/system/webshield-dyndns.service
[Service]
Type=oneshot
ExecStart=/usr/bin/curl -fsS "https://dyn.webshield.pro/update?token=TOKEN"
# /etc/systemd/system/webshield-dyndns.timer
[Timer]
OnBootSec=1min
OnUnitActiveSec=10min
Persistent=true
[Install]
WantedBy=timers.target
Terminal window
systemctl enable --now webshield-dyndns.timer

Task Scheduler, action — PowerShell:

Terminal window
Invoke-RestMethod "https://dyn.webshield.pro/update?token=TOKEN"

Or from an elevated console in one line:

schtasks /create /tn "WebShield DynDNS" /sc minute /mo 10 /tr ^
"powershell -NoProfile -WindowStyle Hidden -Command \"Invoke-RestMethod 'https://dyn.webshield.pro/update?token=TOKEN'\""

It depends on whether you know the addresses.

You know them — one request is enough. Both can travel together:

Terminal window
curl -fsS -u "home.example.com:TOKEN" \
"https://dyn.webshield.pro/nic/update?myip=203.0.113.7,2001:db8::5"

Or as separate parameters — myip for IPv4, myipv6 for IPv6. Same result.

You rely on detection — you need two. We see exactly one address: the one the request arrived from. Arrive over IPv4 and IPv4 is all we learn. So:

*/10 * * * * curl -fsS -4 "https://dyn.webshield.pro/update?token=TOKEN" >/dev/null
*/10 * * * * curl -fsS -6 "https://dyn.webshield.pro/update?token=TOKEN" >/dev/null

The two do not fight: an update of one family never touches the other. An IPv4-only request will not drop the AAAA record, and the other way round. So even if IPv6 at home comes and goes, the last known address stays put.

Dual-stack routers usually send both families themselves, in one request — nothing extra to configure. To see what we get:

Terminal window
curl https://dyn.webshield.pro/ip # answers with however you arrived
curl -4 https://dyn.webshield.pro/ip
curl -6 https://dyn.webshield.pro/ip

A home address in public DNS is an invitation — it gets scanned within hours. The cure is proxying: visitors reach our edge, and we connect to your server at its current address.

What you get:

  • your home address stays out of DNS;
  • we issue the certificate, so no need to expose port 80 for validation;
  • WAF, bot filtering, caching and DDoS protection apply;
  • visitors never notice the address moving.

How to turn it on:

  1. Wait for the first update — an A record with your address appears in the DNS list.
  2. Flip its Proxy switch.
  3. Hosts section → protection settings for that name (see CDN and protection).

Everything else keeps working: the client reports its address, and we update not the public record but the address we use to reach you. After a change the switch takes up to a minute.

On the server itself you can then close 80 and 443 to everyone except our addresses. Mind that the list of our nodes changes, so either keep that rule current or leave the ports open and check the Host header on your side — simply refuse requests that arrive with a hostname you do not serve.

5. What goes through the proxy, and what does not

Section titled “5. What goes through the proxy, and what does not”

A proxied hostname carries web traffic only: HTTP and HTTPS on ports 80 and 443, WebSocket included. Everything else — SSH, RDP, VPN, game servers, torrents, arbitrary TCP ports — does not pass through us. We are a reverse proxy for the web, not a tunnel.

Which means: once proxying is on, you can no longer SSH to that name. It resolves to our addresses, and there is nothing on port 22 there.

Two ways around it.

A separate hostname without proxying. Create a second dynamic name, say ssh.example.com, and leave its proxy off. The web lives on the proxied home, while ssh points straight home. The trade is honest: that name exposes your address, so

  • move SSH off the default port and disable password logins — keys only;
  • run fail2ban or similar;
  • if your ISP gives you a static IPv6, allow that address only.

Web access instead of SSH. Anything that speaks HTTPS lives happily behind the proxy: a web terminal, a server control panel, Git over HTTPS, an API. If the goal is “occasionally get into the home machine”, a web console behind our protection beats an SSH port open to the world.

Look at what the update endpoint answers — the reply is short and to the point:

Response Meaning
good <address> accepted and written
nochg <address> same address, nothing to change
badauth the token is wrong or missing
nohost wrong hostname for this token, or updates are switched off
dnserr the address does not look public
911 too often, try again later

The limit is 10 address changes per 10 minutes per hostname. Repeats with the same address — which is what a router reboot looks like — do not count, so reboot as much as you like.

dnserr almost always means the device sent its private LAN address: 192.168.*, 10.* or a carrier-grade NAT range. Such an address is useless in public DNS, so we reject it. Remove the address from the client settings and let us detect it.

Protocol details live on the Dynamic IP page.