Gravity Sync is the tool you didn’t know you needed until you’ve got two Pi-holes and started wishing they were twins.
Here’s Pi-hole A, dutifully blocking ads, and Pi-hole B, sitting idle. You’ve just spent an hour whitelisting doubleclick.net on Pi-hole A. Now, the thought of doing it all over again on Pi-hole B is a special kind of pain. Gravity Sync automates this. It’s not about syncing logs or DNS queries; it’s about making one Pi-hole’s configuration identical to another’s. Think blacklists, whitelists, regex filters, custom DNS records, and even settings like DHCP server enablement.
Let’s see it in action. Imagine you have a primary Pi-hole (pihole-primary) and a secondary one (pihole-secondary).
On pihole-primary, we’ve added a custom DNS record:
pihole -a -add -dns "192.168.1.100 mynas.local"
Now, we want this record to appear on pihole-secondary. First, ensure Gravity Sync is installed on both. It’s a simple git clone and install.sh.
On pihole-secondary, we run the sync command, pointing it to pihole-primary:
gravity-sync --pull --source pihole-primary --ssh-user pihole --ssh-key ~/.ssh/id_rsa
The --pull flag tells pihole-secondary to fetch configuration from the source. --source pihole-primary specifies the hostname or IP of the primary. --ssh-user pihole is the user on the primary Pi-hole that Gravity Sync will use to connect, and --ssh-key provides the private key for passwordless SSH access.
After this, if you check pihole-secondary’s custom DNS records:
pihole -a -list -dns
You’ll see 192.168.1.100 mynas.local listed there. It’s that seamless.
The magic behind Gravity Sync is a clever use of SSH and rsync. When you initiate a --pull, the secondary Pi-hole connects to the primary via SSH. It then uses rsync to compare the configuration files on both machines. The key configuration files are located in /etc/pihole/ and /etc/dnsmasq.d/. rsync is efficient; it only transfers the differences. For a --pull operation, rsync copies the newer files from the primary to the secondary. When you do a --push (from secondary to primary), it’s the reverse.
The primary problem Gravity Sync solves is maintaining consistency across multiple Pi-hole instances. This is crucial for redundancy, load balancing, or simply managing a larger network. Without it, you’re manually duplicating every change, which is error-prone and time-consuming. It also means you can use one Pi-hole as a staging environment for configuration changes. Make your changes on the primary, test them, and then sync them to your production secondary Pi-holes.
You control the sync direction and the scope. The default sync includes most critical configuration files. However, you can specify exactly which files or directories to sync using the --copy-pihole-files and --copy-dnsmasq-files options, or even exclude specific files with --exclude. This granular control allows for complex setups where perhaps only certain lists are meant to be shared, or custom configurations are managed independently. The --sync-gravity option is particularly useful; it triggers a pihole -g on the destination after the configuration files are updated, ensuring the ad lists are refreshed immediately.
The most surprising aspect for many is how it handles the gravity.db file. It doesn’t directly sync the database file itself. Instead, Gravity Sync synchronizes the ad lists (/etc/pihole/adlists.list, /etc/pihole/disallowed.list, etc.) and then triggers a gravity update (pihole -g) on the receiving Pi-hole. This means the gravity database is rebuilt locally on each machine, ensuring it’s always fresh and relevant to that specific Pi-hole instance, rather than just copying a potentially stale database.
Beyond basic replication, Gravity Sync can also be configured to sync secrets like API tokens, which is essential if you’re using features that rely on them across multiple devices.
The next logical step after ensuring your configurations are identical is to automate the actual DNS resolution failover.