I run PiHole for ad-blocking on my home network. I’m an SRE in my day job, so of course I’m not running a single instance of something as important as DNS. I also don’t want to have to update things like local DNS entries or blocklists in multiple places, that will cause weird and annoying inconsistencies in my DNS.

Enter orbital-sync.

Installation

docker-compose

I’m running orbital-sync via docker-compose with this docker-compose.yaml file.

# docker-compose.yaml
version: '3'
services:
  orbital-sync:
    image: mattwebbio/orbital-sync:1
    environment:
      PRIMARY_HOST_BASE_URL: $PRIMARY_HOST_BASE_URL
      PRIMARY_HOST_PASSWORD: $PRIMARY_HOST_PASSWORD
      SECONDARY_HOSTS_1_BASE_URL: $SECONDARY_HOSTS_1_BASE_URL
      SECONDARY_HOSTS_1_PASSWORD: $SECONDARY_HOSTS_1_PASSWORD
      SECONDARY_HOSTS_2_BASE_URL: $SECONDARY_HOSTS_2_BASE_URL
      SECONDARY_HOSTS_2_PASSWORD: $SECONDARY_HOSTS_2_PASSWORD
      # I only have two secondary hosts, but you could sync a third one
      # SECONDARY_HOSTS_3_BASE_URL: 'http://server:8080'
      # SECONDARY_HOSTS_3_PASSWORD: 'your_password4'
      # SECONDARY_HOSTS_3_PATH: '/apps/pi-hole'
      INTERVAL_MINUTES: $INTERVAL_MINUTES

# Run it in the same docker network I run the master pihole in for simplicity.
# You can comment this stanza out if you're not using a ssl proxy.
networks:
  default:
    external:
      name: ssl_proxy_network

Configuration

I have a .env file in the same directory as docker-compose.yaml where I set the configuration variables.

# I run orbital-sync on the same host as the master pihole in the same
# docker network I use for my SSL nginx proxy, so I can refer to it here
# by container name.
PRIMARY_HOST_BASE_URL=http://pihole
PRIMARY_HOST_PASSWORD=YOUR_MASTER_PIHOLE_ADMIN_PASSWORD
SECONDARY_HOSTS_1_BASE_URL=https://dns-secondary-one.example.com
SECONDARY_HOSTS_1_PASSWORD=SECONDARY_ONE_PIHOLE_ADMIN_PASSWORD
SECONDARY_HOSTS_2_BASE_URL=https://dns-secondary-two.example.com
SECONDARY_HOSTS_2_PASSWORD=SECONDARY_TWO_PIHOLE_ADMIN_PASSWORD
# I sync the primary to the secondaries every ten minutes.
INTERVAL_MINUTES=10
# I only run two secondaries, but I could sync a third if I wanted
#SECONDARY_HOSTS_3_BASE_URL=https://dns-secondary-three.example.com
#SECONDARY_HOSTS_3_PASSWORD=SECONDARY_THREE_PIHOLE_ADMIN_PASSWORD

The SSL proxy setup is documented at Set up nginx-proxy-manager with LetsEncrypt SSL certificates

Running

Now you can run docker-compose up -d and your settings will be synced from your master pihole to its secondaries.

Here’s a sanitized example docker log:

$ docker-compose logs
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ➡️ Signing in to http://pihole/admin...
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ✔️ Successfully signed in to http://pihole/admin!
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ➡️ Downloading backup from http://pihole/admin...
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ✔️ Backup from http://pihole/admin completed!
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ➡️ Signing in to https://dns-s1.example.com/admin...
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ✔️ Successfully signed in to https://dns-s1.example.com/admin!
orbital-sync_1  | 12/6/2024, 4:44:28 PM: ➡️ Uploading backup to https://dns-s1.example.com/admin...
orbital-sync_1  | 12/6/2024, 4:44:46 PM: ✔️ Backup uploaded to https://dns-s1.example.com/admin!
orbital-sync_1  | 12/6/2024, 4:44:46 PM: ➡️ Updating gravity on https://dns-s1.example.com/admin...
orbital-sync_1  | 12/6/2024, 4:44:49 PM: ✔️ Gravity updated on https://dns-s1.example.com/admin!
orbital-sync_1  | 12/6/2024, 4:44:49 PM: ✔️ Success: 1/1 hosts synced.
orbital-sync_1  | 12/6/2024, 4:44:49 PM: Waiting 10 minutes...```