This service gives you:
- A protected API endpoint to update the current target IP (your home server).
- A public reverse-proxy endpoint that forwards all incoming requests to that current IP.
- Persistent state in a Docker volume, so last known IP survives restarts.
It is designed to run behind Traefik on your VPS.
- Internet user calls your public host, e.g.
ddns.example.com. - Traefik sends the request to this container.
- This container forwards the request to
http://<current-ip>:<current-port>. - Your home server periodically calls
POST /api/updateto change<current-ip>.
GET /healthz
POST /api/update
Headers:
Authorization: Bearer <DDNS_API_TOKEN>(orX-API-Token: <token>)Content-Type: application/json
Body:
{
"ip": "203.0.113.42",
"port": 80,
"scheme": "http"
}Notes:
ipcan be"auto"or omitted; then request source IP is used (X-Forwarded-Forfirst).schemecan behttporhttps.portdefaults toDDNS_DEFAULT_UPSTREAM_PORT.
GET /api/target
Headers:
Authorization: Bearer <DDNS_API_TOKEN>(orX-API-Token: <token>)
Response:
{
"target": {
"ip": "203.0.113.42",
"port": 80,
"scheme": "http"
}
}Edit docker-compose.yml:
- Set
DDNS_API_TOKENto a long random secret. - Set Traefik host rule to your domain/subdomain.
- Ensure
traefik_proxymatches your existing external Traefik network.
Start:
docker compose up -d --buildcurl -X POST "https://ddns.example.com/api/update" \
-H "Authorization: Bearer YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ip":"auto","port":80,"scheme":"http"}'- Keep
DDNS_API_TOKENsecret and long. - Put
/api/updatebehind additional protections if possible (IP allowlist, mTLS, or VPN). - Prefer HTTPS at Traefik edge.
Build image:
docker build -t ddns-proxy:local .Run:
docker run --rm -p 8080:8080 -e DDNS_API_TOKEN=test-token ddns-proxy:localIn another shell:
curl http://localhost:8080/healthz