AdGuard Cluster

In today’s always-connected world, your DNS resolver is one of the most critical services in your home lab or network. If your AdGuard Home instance goes down — whether due to a hardware failure, software crash, or maintenance — everything from internet browsing to smart home devices can grind to a halt.That’s why many self-hosters are turning to high availability (HA) clustering for AdGuard Home using Keepalived.By combining two (or more) AdGuard Home instances with Keepalived’s Virtual Router Redundancy Protocol (VRRP), you can create a floating Virtual IP (VIP) that automatically fails over to a healthy backup node in seconds. Clients point to a single, reliable DNS IP, and they never notice when the primary server goes offline.

Step 1: Basic Architecture

The following diagram provides overview of the solution:

  • Two (2) adguard servers, each with their own IP address
  • An additional IP address on each adguard server which is ‘clustered’ (HA) via keepalived.

In this solution clients will point to the keepalived (VIP) addresses, if a host fails clients wil have instantanous failover of DNS and will notice any failures.

Step 2: AdGuard Docker

We will deploy two AdGuard servers each with a docker container, isolating its configuration and work directory in a seperate directory structure:

# mkdir /opt/adguardhome
# mkdir /opt/adguardhome/work
# mkdir /opt/adguardhome/conf
# chmod 700 /opt/adguardhome/workCode language: PHP (php)

Create the docker compose configuration file /opt/adguardhome/docker-compose.yml

services:
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguard
    network_mode: host
    volumes:
      - /opt/adguardhome/work:/opt/adguardhome/work
      - /opt/adguardhome/conf:/opt/adguardhome/conf
    environment:
      - TZ=Europe/Amsterdam
    restart: unless-stoppedCode language: JavaScript (javascript)

Start the docker container and check its status:

# cd /opt/adguardhome
# docker compose up -d
# docker psCode language: PHP (php)

This is the moment that adguard is reachable via its webinterface and I configure the following extra details, which i skip in this blog:

  • DNS Settings: define upstream servers
  • DNS Settings: define upstream subdomain forwarders and reverse
  • DNS Settings: define rate limiting
  • Encryption settings: define SSL certificates
  • Define DNS Blocklists
  • etc

After this your basic adguard should be complete.

Step 3: Keepalived

So we will configure a keepalived cluster where each host has an active ip-address and is standby for the remote host. Lets first install the packages:

# apt install keepalivedCode language: PHP (php)

On the first adguard (01) server we define the following configuration file  /etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
   notification_email {
     admin@domain.com
   }
   notification_email_from adguard-01@domain.com
   smtp_server 192.168.0.240
   smtp_connect_timeout 30
   router_id adguard-01
   enable_script_security
   script_user root
   max_auto_priority -1
}

vrrp_script chk_adguard {
    script "/usr/bin/pgrep -f AdGuardHome"
    interval 3       # check every 3 seconds
    weight -20       # drop priority by 20 if check fails → triggers failover
    fall 2           # fail after 2 bad checks
    rise 2           # recover after 2 good checks
}

vrrp_instance VI_1_IPv6 {
    state MASTER
    interface ens33
    smtp_alert
    virtual_router_id 10
    priority 200

   advert_int 1
   virtual_ipaddress {
        2a1a:381:13c:2::70/64 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_1_IPv4 {
    state MASTER
    interface ens33
    smtp_alert
    virtual_router_id 10
    priority 200

   advert_int 1
   virtual_ipaddress {
        192.168.0.70/27 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_2_IPv6 {
    state BACKUP
    interface ens33
    smtp_alert
    virtual_router_id 11
    priority 150

   advert_int 1
   virtual_ipaddress {
        2a1a:381:13c:2::71/64 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_2_IPv4 {
    state BACKUP
    interface ens33
    smtp_alert
    virtual_router_id 11
    priority 150

   advert_int 1
   virtual_ipaddress {
        192.168.0.71/27 dev ens33
   }

   track_script {
       chk_adguard
   }
}Code language: PHP (php)

Start the adguard (01) keepalived service, it should host all the IP’s as the second is not online:

# systemctl enable keepalived
# systemctl start keepalived
# tail -f /var/log/syslog
# ip addr list dev ens33Code language: PHP (php)

On the second adguard (02) server we define the following configuration file  /etc/keepalived/keepalived.conf

 

 

! Configuration File for keepalived

global_defs {
   notification_email_from adguard-02@domain.com
   smtp_server 192.168.0.240
   smtp_connect_timeout 30
   router_id adguard-02
   enable_script_security
   script_user root
   max_auto_priority -1
}

vrrp_script chk_adguard {
    script "/usr/bin/pgrep -f AdGuardHome"
    interval 3       # check every 3 seconds
    weight -20       # drop priority by 20 if check fails → triggers failover
    fall 2           # fail after 2 bad checks
    rise 2           # recover after 2 good checks
}

vrrp_instance VI_1_IPv6 {
    state BACKUP
    interface ens33
    smtp_alert
    virtual_router_id 10
    priority 150

   advert_int 1
   virtual_ipaddress {
        2a1a:381:13c:2::70/64 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_1_IPv4 {
    state BACKUP
    interface ens33
    smtp_alert
    virtual_router_id 10
    priority 150

   advert_int 1
   virtual_ipaddress {
        192.168.0.70/27 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_2_IPv6 {
    state MASTER
    interface ens33
    smtp_alert
    virtual_router_id 11
    priority 200

   advert_int 1
   virtual_ipaddress {
        2a1a:381:13c:2::71/64 dev ens33
   }

   track_script {
       chk_adguard
   }
}

vrrp_instance VI_2_IPv4 {
    state MASTER
    interface ens33
    smtp_alert
    virtual_router_id 11
    priority 200

   advert_int 1
   virtual_ipaddress {
        192.168.0.71/27 dev ens33
   }

   track_script {
       chk_adguard
   }
}Code language: PHP (php)

Start the adguard (02) keepalived service, it should host all its own ip’s, now each adguard hosts is master ip and is backup to the other:

# systemctl enable keepalived
# systemctl start keepalived
# tail -f /var/log/syslog
# ip addr list dev ens33Code language: PHP (php)