Self-hosted service
jeessy2/ddns-go avatar
jeessy2/ddns-go

ddns-go: a Go DDNS client that keeps your A and AAAA records pointed at home

Simple and easy to use DDNS. Support Aliyun, Tencent Cloud, Dnspod, Cloudflare, Callback, Huawei Cloud, Baidu Cloud, Porkbun, GoDaddy, Namecheap, NameSilo...

17,386 stars1,892 forksGoMIT

At a glance

What is it?
ddns-go watches your public IPv4 and IPv6 address and pushes the change to one of twenty-plus DNS providers through a browser-based config page. It is a single static binary, and the trade-off is that it holds provider API credentials on the host that runs it.
Who is it for?
Adopt ddns-go if you run a home server, NAS or router with a dynamic public address and you want one web UI covering several DNS providers. Skip it if you need a hosted service that survives your own machine going down, or if you cannot accept provider API tokens sitting in a config file on that host.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What ddns-go solves, and who is actually running it

A residential internet connection hands out a public address that changes. Anything you host at home, a NAS, a game server, a self-hosted app, becomes unreachable by name the moment that address moves. Dynamic DNS closes the gap by rewriting the A or AAAA record at your DNS provider whenever the address changes.

ddns-go is a client for that job. According to the README, it obtains your public IPv4 or IPv6 address automatically and resolves it to the corresponding domain service. The supported provider list is unusually long for a project this size: Aliyun, Aliyun ESA, Tencent Cloud, Dnspod, Cloudflare, Huawei Cloud, Callback, Baidu Cloud, Porkbun, GoDaddy, Namecheap, NameSilo, Dynadot, DNSLA, Eranet, Tnethk, Gcore, EdgeOne, IBM NS1 Connect, and more. If you already pay for DNS somewhere, there is a decent chance it is covered.

The target user is someone comfortable running a background service on Linux, macOS or Windows, or a container on a NAS. The README lists Mac, Windows and Linux on ARM, x86 and RISC-V, and the repository ships a Dockerfile. It is not aimed at people who want a hosted DDNS endpoint they never have to maintain; the process has to keep running somewhere on your network.

How the address detection and provider update loop works

There are two clocks inside ddns-go, and understanding them is the difference between a working setup and a provider rate limit. The first is the sync interval, set with -f in seconds and defaulting to 300, which the README describes as a five minute sync. The second is -cacheTimes, which the README describes as comparing against the provider every N intervals.

The README gives a concrete example of why both exist: check the local IP every 10 seconds, compare against the provider every 30 minutes. That combination triggers an update almost immediately when your address changes while keeping the number of API calls to the provider low. If you use an HTTP interface to discover your address rather than a local network interface, the README warns that the interface itself may rate limit you, so a 10 second check against a third-party IP echo service is a bad idea.

Address discovery itself can come from an interface, an API, or a command, the last documented in the project wiki. Once an address is known, ddns-go compares it with what the provider currently reports and only issues a change when they differ. Multiple providers and multiple domains can be configured at once, including multi-level subdomains. The web UI keeps the most recent 50 log entries, which is where you look when a record silently stops updating.

Installing ddns-go as a system service

The README points to the Releases page for a prebuilt archive. After unpacking, the binary registers itself with the platform's service manager, so it survives reboots without a separate systemd unit or launchd plist.

bash
sudo ./ddns-go -s install

On Windows the equivalent is run from an administrator command prompt as .\ddns-go.exe -s install. Once installed, the README says to open a browser at http://localhost:9876 for initial configuration. That page is where you pick the provider, paste credentials and list the domains to keep updated. The README notes that access from the public internet is disabled by default, and it recommends putting an HTTPS reverse proxy such as Nginx in front if you ever enable it.

Install accepts flags at registration time, so the interval and config path are baked into the service definition rather than edited later. The README's own example sets a ten minute interval and a custom config file:

bash
./ddns-go -s install -f 600 -c /Users/name/.ddns_go_config.yaml

To remove the service later, the same binary takes -s uninstall. If the web password is lost, the README documents a reset path that does not require editing the YAML by hand:

bash
./ddns-go -resetPassword 123456

Running ddns-go in Docker, including on a NAS

The container image is published both to Docker Hub as jeessy/ddns-go and to ghcr.io as ghcr.io/jeessy2/ddns-go. The README's primary example uses host networking and mounts a host directory at /root, since the config file is a hidden file inside that path.

bash
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go

After that, configuration happens at http://Docker主机IP:9876, the Docker host's address on port 9876. Flags can be passed to the container the same way they are passed to the binary, for example to move the listener to port 9877 and set a ten minute interval:

bash
docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go -l :9877 -f 600

If host networking is not acceptable, the README also gives a bridged form with -p 9876:9876. The IPv6 section is where this matters. The README recommends host networking on Linux x86 and ARM for IPv6, and explicitly says that Windows and macOS desktop Docker do not support --net=host. It also warns that a virtual machine may obtain an IPv6 address correctly yet still fail to reach the IPv6 internet, which produces a config that looks right and never updates. For Synology, the README walks through Container Manager: search the registry for ddns-go, launch jeessy/ddns-go, and in advanced settings tick the option to use the same network as the Docker host plus automatic restart.

Where ddns-go is the wrong tool

The first limitation is structural. ddns-go is a client you run yourself, so it can only update records while your own machine, container or NAS is up. If the host is off, the address changes, and nothing runs to correct the record, your domain points at an address that no longer belongs to you. A hosted DDNS provider that runs on someone else's infrastructure does not have that failure mode. If your requirement is a record that is always correct regardless of whether your hardware is powered on, this is not the project for you.

The second is credential handling. To update a record, ddns-go needs an API token or key for your DNS provider, and that secret lives in the YAML config file on the host, or inside the mounted /root directory in the container case. Anyone who reads that file can change your DNS. The README's own note about enabling public access recommends an HTTPS reverse proxy, which tells you the web UI is not designed to be exposed directly. Treat the config file as a secret and scope the provider token to DNS editing only if your provider supports scoped tokens.

The third is IPv6 discovery. The README is candid that a virtual machine may see an IPv6 address but not be able to reach the IPv6 internet, and that Windows and macOS desktop Docker cannot use host networking. Both cases produce a deployment that appears configured and quietly does nothing useful.

How ddns-go differs from ddclient and from router firmware

The closest functional alternative in the same category is ddclient, the long-standing Perl client that also watches an address and updates a provider. The difference in approach is packaging and interface. ddclient is configured by editing a text file and running it from a cron job or init script; ddns-go ships a compiled static binary, registers itself with the platform service manager through -s install, and puts configuration in a browser at port 9876 with a built-in log view. ddns-go also bundles a much wider set of Chinese cloud DNS providers, which is a real distinction if your domains live at Aliyun, Tencent Cloud, Huawei Cloud or Baidu Cloud rather than at a Western registrar.

The second alternative is the DDNS feature built into router firmware, which many people already have. That runs on the router, so it stays up when your server is off, and it usually supports a handful of providers. ddns-go wins on provider coverage, on IPv6 handling, and on the ability to update several domains and several providers from one place. It loses on the always-on property. If your router's built-in client already covers your provider, adding ddns-go is extra moving parts for no gain.

Maintenance, licence and what a version bump costs you

The repository is not archived, and the last push was on 2026-09-14. Releases are frequent and small: v6.17.7 on 2026-09-04, v6.17.6 on 2026-08-19, and v6.17.5 on 2026-08-08. That cadence suggests incremental fixes rather than long release trains, which is normal for a client of this size.

Upgrade cost is low in the common case. A service install is replaced by installing the new binary over the old one and restarting; the config file is a separate YAML document, so it survives the swap. The version is injected at build time through the Makefile, which is why the binary reports a version rather than reading one from a file. For Docker, the tag on jeessy/ddns-go is what you pull, and the container's CMD defaults to -l :9876 -f 300, so anything you relied on from the default flags comes back unless you pass your own. The module path in go.mod is github.com/jeessy2/ddns-go/v6, and the README and examples refer to v6 throughout, so a future major version would be a deliberate migration rather than a silent one.

The licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are included. That is a permissive licence with few obligations, but it is not legal advice and it says nothing about the terms your DNS provider attaches to API access.

Editorial conclusion

Adopt ddns-go if you run a home server, NAS or router with a dynamic public address and you want one web UI covering several DNS providers. Skip it if you need a hosted service that survives your own machine going down, or if you cannot accept provider API tokens sitting in a config file on that host. Before trusting it, verify that your chosen provider is on the supported list, that the container can actually see your public IPv6 address, and that you have noted the reset command for the web password.

Frequently asked questions

What is ddns-go?

It is a DDNS client that obtains your public IPv4 or IPv6 address and updates the matching records at your DNS provider. It runs as a background service on Mac, Windows or Linux, or as a Docker container, and is configured through a web page on port 9876.

what is ddns go

ddns-go is a Go program that keeps a domain name pointed at a changing public address, supporting providers such as Aliyun, Cloudflare, GoDaddy and Namecheap. The README describes it as obtaining your public IPv4 or IPv6 address automatically and resolving it to the corresponding domain service.

Does ddns-go cost anything?

The project is MIT licensed and the README points to its Releases page and Docker images rather than any paid tier. Your DNS provider may charge for the domain or for API usage, but the README does not describe any cost attached to ddns-go itself.

What is the ddns-go default password, and how do I reset it?

The README does not state a default password; the web page at port 9876 is used for initial configuration, which is where a password is set. If it is lost, the README documents resetting it with ./ddns-go -resetPassword 123456, and inside Docker with docker exec ddns-go ./ddns-go -resetPassword 123456 followed by a container restart.

Which port does ddns-go listen on?

The default is 9876, which is the address the README tells you to open in a browser for initial configuration. The listener can be changed with the -l flag, for example -l :9877, both for a service install and for a Docker container.

Can ddns-go update IPv6 records?

Yes. The README has a dedicated IPv6 section and recommends host networking on Linux x86 and ARM, while noting that Windows and macOS desktop Docker do not support --net=host. It also warns that a virtual machine may obtain an IPv6 address but still fail to reach the IPv6 internet.

Official sources

  1. Issues
  2. jeessy2/ddns-go on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jeessy2-ddns-go.svg)](https://hysenlabs.com/projects/jeessy2-ddns-go)