adguardhome-sync: pushing one AdGuard Home config out to every replica
🛡️ Synchronize AdGuard Home config to replicas
At a glance
- What is it?
- bakito/adguardhome-sync is a Go daemon that copies configuration from one AdGuard Home instance to replicas on a cron schedule, covering filters, rewrites, clients, DNS, DHCP and more. It is a one-way replicator, not a clustering solution, and its credentials come from environment variables.
- Who is it for?
- Adopt adguardhome-sync when you run several AdGuard Home instances and want one to be the source of truth, and configure instance and credential settings through environment variables. Do not expect conflict resolution or query log replication: the tool pushes state from the origin and treats each replica as a target.
- Can I use it commercially?
- Yes. Apache-2.0 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 received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One origin, many replicas, one direction
The problem adguardhome-sync solves is operational, not algorithmic. Teams that run AdGuard Home for redundancy end up with N instances that were configured independently, and drift follows: a blocklist added on one, a rewrite on another, and nobody knows which is authoritative. This tool names an origin instance and a set of replica instances, then copies the origin's configuration onto the replicas on a schedule.
Direction is the whole design. There is no merge step, no last-writer-wins comparison and no record of who changed what. Edits made directly on a replica are overwritten on the next run. That behaviour is fine when the origin is genuinely the only place an administrator ever logs in, and it is a data loss risk when it is not. Pick the instance people actually administer and make it the origin.
The project is written in Go and released under Apache-2.0. The module is github.com/bakito/adguardhome-sync and go.mod pins the toolchain to Go 1.27.2.
Eight configuration areas are synced, and all of them are on by default
The README lists the current sync features: General Settings, Filters, Rewrites, Services, Clients, DNS Config, DHCP Config and Theme. All features are enabled by default, and single features can be turned off in the configuration.
That default is worth a second look in a production deployment. DHCP Config in particular is not just a list of leases: the DHCP server is network infrastructure, and copying that configuration from one instance to another means a change on the origin is pushed out to every replica without further review. The same reasoning applies to DNS Config, where a resolver change propagates immediately.
If a replica is meant to serve a different role, disable the areas that must not propagate rather than relying on someone remembering not to edit the origin. The config also carries ORIGIN_DHCP_SERVER_ENABLED and the matching REPLICA#_DHCP_SERVER_ENABLED flag, so the DHCP server state can be kept off on targets independently.
Installation is a release binary, a go install, or a Homebrew cask
The README offers three routes. Binaries are published on the releases page, the source can be installed with the Go toolchain, and there is a Homebrew tap:
go install github.com/bakito/adguardhome-sync@latest# Add the tap
brew tap bakito/tap
brew trust bakito/tap
# install
brew install --cask adguardhome-syncContainer builds are supported as well. The Dockerfile builds with golang:1.27-alpine, sets CGO_ENABLED=0, produces a static binary, and assembles the final image FROM scratch, copying in the CA certificate bundle and the zoneinfo database. The resulting image exposes port 8080 and defaults to running the sync process:
EXPOSE 8080
ENTRYPOINT ["/opt/go/adguardhome-sync"]
CMD ["run", "--config", "/config/adguardhome-sync.yaml"]The scratch base means there is no shell in the final image, which is good for attack surface and awkward for debugging. The systemd/ directory in the repository suggests a unit file is also provided for those who prefer a plain host install.
Every setting is an environment variable, including replica URLs by index
Configuration is available through environment variables, and replicas are addressed positionally. The rule is short: for replicas, replace `#` with the index number, so `REPLICA#_URL` becomes `REPLICA1_URL`. Each replica slot has its own URL, WEB_URL, API_PATH, USERNAME, PASSWORD, COOKIE, REQUEST_HEADERS, INSECURE_SKIP_VERIFY, AUTO_SETUP, INTERFACE_NAME and DHCP_SERVER_ENABLED, mirroring the ORIGIN_ prefixed variables.
That index convention is the single most important thing to get right. A typo in `REPLICA2_URL` when you meant `REPLICA1_URL` leaves the second replica unmanaged, and the failure mode is silence rather than an error, because a variable you did not set simply has no replica. Likewise, ORIGIN_API_PATH and REPLICA#_API_PATH exist because the API can live under a path prefix, and a mismatched prefix between origin and replica produces authentication or routing failures that look like credentials problems.
Two settings change behaviour rather than naming a target. CONTINUE_ON_ERROR decides whether one failing replica aborts the run. PRINT_CONFIG_ONLY prints the current configuration and stops, which is the safe first command to run against a new environment. RUN_ON_START triggers a sync at startup so a restart does not leave replicas stale until the first cron tick.
Replicas must be pre-initialised unless you accept port 3000
The prerequisites section is short and easy to skim: both the origin instance and the replicas must be initially set up with AdGuard Home through the installation wizard. The tool expects to authenticate against instances that already exist and already have an administrator account.
There is an escape hatch. The ORIGIN_AUTO_SETUP and REPLICA#_AUTO_SETUP flags let the tool install and initialise an instance that has not been set up yet. The README warns that during automatic installation the admin interface listens on port 3000 at runtime, which is a short window in which a fresh instance exposes its admin interface on a well-known port. Whether that window is acceptable depends on your network, and the flag is off unless you turn it on.
For the majority of deployments the wizard-first path is the right one: run the sync against instances you created yourself, with credentials you chose, and leave auto setup for throwaway or lab instances.
Failures are quiet by default, and CONTINUE_ON_ERROR decides the blast radius
A sync that touches a network service across HTTP has a long tail of failure modes: an instance restarting, an expired cookie, a TLS interception proxy in the path, a changed API path. Two environment variables govern how much of that reaches you.
CONTINUE_ON_ERROR decides whether a failing replica stops the run. Left off, the first error stops the sync, which keeps the failure visible and leaves later replicas untouched. Turned on, the run continues and you end up with a partially synchronised fleet, which is harder to reason about than an all-or-nothing attempt.
Authentication is handled two ways per instance, USERNAME and PASSWORD or COOKIE. A configured cookie may be stale, and HTTP_CLIENT_TIMEOUT can bound requests to an unresponsive instance. ORIGIN_INSECURE_SKIP_VERIFY and its replica counterpart disable TLS verification, which is convenient for a lab with a self-signed certificate and a bad habit outside one.
Version 0.9.x, weekly-ish releases, and where the docs actually live
The version line tells you what maturity to expect. v0.9.2 was tagged on 2026-06-24, v0.9.3 on 2026-09-13 and v0.9.4 on 2026-10-09, with the last push to the repository on 2026-10-13. A 0.x line with releases spread over a few months is normal for a small infrastructure daemon, and it does mean interfaces may change between minor versions.
The README is deliberately thin and points twice at the wiki, once for FAQ and once for a Deprecations page. That deprecations page is the one to read before an upgrade, because a config key that gets deprecated in a 0.x project is a realistic way to break a working deployment. The env-doc block in the README is generated, and the Makefile has a docs target that runs cmd/docs/main.go to regenerate it, so the variable table in the README is derived from the code rather than maintained by hand.
The Makefile also shows how the project tests itself: unit tests with coverage, an end-to-end suite run under the e2e build tag, a fuzz target for the mask logic, and generated mocks and deepcopy code. The e2e path uses a kind cluster and an install-chart script, which can make upgrades costly to test.
Editorial conclusion
Adopt adguardhome-sync when you run several AdGuard Home instances and want one to be the source of truth, and configure instance and credential settings through environment variables. Do not expect conflict resolution or query log replication: the tool pushes state from the origin and treats each replica as a target. Verify first that your origin and every replica have already been through the AdGuard Home installation wizard, since automatic setup is opt-in through ORIGIN_AUTO_SETUP and puts the admin interface on port 3000 during that run.
Frequently asked questions
How do I install adguardhome-sync?
The README gives three routes: a binary from the releases page, `go install github.com/bakito/adguardhome-sync@latest`, or a Homebrew cask installed with `brew tap bakito/tap` followed by `brew install --cask adguardhome-sync`. A Dockerfile is also provided, producing a scratch-based image that exposes port 8080.
How are multiple AdGuard Home replicas configured in adguardhome-sync?
Through environment variables indexed by replica number: replace `#` with the index, so `REPLICA#_URL` becomes `REPLICA1_URL`. Each replica slot accepts URL, WEB_URL, API_PATH, USERNAME, PASSWORD, COOKIE, REQUEST_HEADERS, INSECURE_SKIP_VERIFY, AUTO_SETUP, INTERFACE_NAME and DHCP_SERVER_ENABLED.
Do the AdGuard Home instances need to be set up before running adguardhome-sync?
Yes. The prerequisites state that both the origin and the replicas must be initially set up with AdGuard Home through the installation wizard. The ORIGIN_AUTO_SETUP and REPLICA#_AUTO_SETUP flags can install an instance automatically, in which case the admin interface listens on port 3000 during that process.
What is synced from the origin instance to the replicas?
General Settings, Filters, Rewrites, Services, Clients, DNS Config, DHCP Config and Theme. All features are enabled by default, and individual features can be disabled in the config.
How often does adguardhome-sync run?
The sync interval is set with the CRON environment variable, and RUN_ON_START triggers a sync at startup. CONTINUE_ON_ERROR decides whether a failing replica aborts the run, and PRINT_CONFIG_ONLY prints the current configuration and exits.
Official sources
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.
[](https://hysenlabs.com/projects/bakito-adguardhome-sync)Was this useful?