FreeBSD.software
Home/Guides/How to Set Up AdGuard Home on FreeBSD
tutorial·2026-03-29·15 min read

How to Set Up AdGuard Home on FreeBSD

Step-by-step guide to setting up AdGuard Home on FreeBSD. Covers installation, web interface, DNS filtering, custom rules, DHCP integration, DNS-over-HTTPS, and comparison with Pi-hole.

How to Set Up AdGuard Home on FreeBSD

AdGuard Home is a network-wide DNS sinkhole that blocks ads, trackers, and malicious domains at the DNS level. Every device on your network benefits without needing per-device software. FreeBSD is an excellent host for AdGuard Home thanks to its stability, jails for isolation, and low resource overhead.

This guide walks through the full setup: downloading the binary, creating an rc.d service script, configuring upstream DNS with encryption, managing filter lists, writing custom rules, enabling DHCP, securing the web interface with HTTPS, and running AdGuard Home inside a FreeBSD jail.

What AdGuard Home Does

AdGuard Home sits between your network clients and upstream DNS resolvers. When a device makes a DNS query, AdGuard Home checks it against filter lists. If the domain is on a blocklist (ad server, tracker, malware host), it returns a null response. The ad never loads. The tracker never fires.

Key capabilities:

  • DNS-level ad and tracker blocking across all devices on the network.
  • Encrypted upstream DNS via DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT).
  • Custom filtering rules using AdBlock-style syntax.
  • DNS rewrites for local name resolution without running a separate DNS server.
  • Built-in DHCP server to replace ISC DHCP or dhcpd.
  • Per-client settings so you can apply different rules to different devices.
  • Query log and statistics with a web dashboard.

It runs as a single static binary with an embedded web interface, which makes deployment on FreeBSD straightforward.

Installation on FreeBSD

Option 1: Direct Binary Install

AdGuard Home ships as a static binary. No dependencies, no package manager conflicts.

Determine your architecture. Most FreeBSD servers run amd64:

sh
uname -m

Download the latest release:

sh
fetch https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_freebsd_amd64.tar.gz tar -xzf AdGuardHome_freebsd_amd64.tar.gz mv AdGuardHome /usr/local/bin/AdGuardHome

Create the working directory where AdGuard Home stores its configuration and data:

sh
mkdir -p /var/db/adguardhome

Test that it runs:

sh
/usr/local/bin/AdGuardHome/AdGuardHome --work-dir /var/db/adguardhome --no-check-update

If port 53 is already in use by local_unbound or another resolver, stop that service first or configure AdGuard Home to listen on a different port during initial setup.

Option 2: Run in a FreeBSD Jail

Running AdGuard Home inside a FreeBSD jail provides process isolation and a clean network namespace. This is the recommended approach for production use. See the dedicated jail section below for details.

Creating an rc.d Service Script

FreeBSD uses rc.d for service management. Create a script so AdGuard Home starts at boot and can be controlled with service commands.

Create /usr/local/etc/rc.d/adguardhome:

sh
#!/bin/sh # PROVIDE: adguardhome # REQUIRE: NETWORKING # KEYWORD: shutdown . /etc/rc.subr name="adguardhome" rcvar="adguardhome_enable" load_rc_config $name : ${adguardhome_enable:="NO"} : ${adguardhome_user:="nobody"} : ${adguardhome_group:="nobody"} : ${adguardhome_dir:="/var/db/adguardhome"} : ${adguardhome_flags:="--work-dir ${adguardhome_dir} --no-check-update"} pidfile="/var/run/${name}.pid" command="/usr/local/bin/AdGuardHome/AdGuardHome" command_args="${adguardhome_flags} &" start_cmd="${name}_start" stop_cmd="${name}_stop" status_cmd="${name}_status" adguardhome_start() { echo "Starting ${name}." /usr/sbin/daemon -f -p ${pidfile} -u ${adguardhome_user} \ ${command} ${adguardhome_flags} } adguardhome_stop() { if [ -f ${pidfile} ]; then echo "Stopping ${name}." kill $(cat ${pidfile}) rm -f ${pidfile} else echo "${name} is not running." fi } adguardhome_status() { if [ -f ${pidfile} ] && kill -0 $(cat ${pidfile}) 2>/dev/null; then echo "${name} is running as pid $(cat ${pidfile})." else echo "${name} is not running." fi } run_rc_command "$1"

Make it executable and enable it:

sh
chmod +x /usr/local/etc/rc.d/adguardhome sysrc adguardhome_enable="YES"

Ensure the working directory is owned by the service user:

sh
chown -R nobody:nobody /var/db/adguardhome

Start the service:

sh
service adguardhome start

Initial Web Setup Wizard

On first launch, AdGuard Home starts a setup wizard on port 3000. Open your browser and navigate to:

shell
http://YOUR_SERVER_IP:3000

The wizard walks through:

  1. Admin credentials -- set a strong username and password.
  2. DNS listen address -- default is 0.0.0.0:53. If you only want it to serve the local network, bind to the LAN interface IP.
  3. Web interface listen address -- default is 0.0.0.0:80. You can change this to a non-standard port or restrict to localhost.

After completing the wizard, AdGuard Home writes its configuration to AdGuardHome.yaml in the working directory. All further configuration happens through the web interface or by editing that YAML file directly.

Configuring Upstream DNS

AdGuard Home needs upstream resolvers to answer queries that are not blocked. Navigate to Settings > DNS settings in the web interface.

DNS-over-HTTPS (DoH)

DoH encrypts DNS queries inside HTTPS. Add upstream servers in this format:

shell
https://dns.cloudflare.com/dns-query https://dns.google/dns-query https://dns.quad9.net/dns-query

DNS-over-TLS (DoT)

DoT uses TLS on port 853:

shell
tls://1.1.1.1 tls://8.8.8.8 tls://9.9.9.9

Local Unbound as Upstream

If you already run Unbound for recursive resolution, point AdGuard Home at it. This gives you DNS filtering plus full recursive resolution without relying on third-party resolvers:

shell
127.0.0.1:5353

Configure Unbound to listen on port 5353 so it does not conflict with AdGuard Home on port 53. This is a powerful combination: AdGuard Home handles filtering and the client-facing interface while Unbound handles recursive lookups.

Bootstrap DNS

When using DoH or DoT, AdGuard Home needs a way to resolve the upstream server hostname itself. Set bootstrap DNS to a plain IP-based resolver:

shell
9.9.9.9 1.1.1.1

Parallel vs. Fastest

Under "DNS upstream mode," choose between:

  • Load-balancing -- distributes queries across upstreams.
  • Parallel requests -- sends to all upstreams, uses the fastest response.
  • Fastest IP -- uses the upstream that historically responds quickest.

For most setups, load-balancing is fine. If latency matters, parallel requests reduces perceived DNS delay at the cost of slightly more upstream traffic.

Filter Lists

AdGuard Home ships with the AdGuard DNS filter enabled by default. This blocks most ads and trackers out of the box.

Navigate to Filters > DNS blocklists to add more lists. Recommended additions:

| List | Purpose |

|------|---------|

| AdGuard DNS filter | Default. Ads, trackers. |

| OISD (Full) | Large consolidated list. Low false positives. |

| Steven Black's Unified Hosts | Ads, malware, fakenews, gambling (pick variants). |

| Hagezi's Multi PRO | Comprehensive tracker and ad blocking. |

| Phishing Army | Phishing domain protection. |

| NoCoin | Cryptocurrency mining scripts. |

Do not add dozens of overlapping lists. Two or three well-maintained lists cover the vast majority of domains. More lists means more memory and slower startup for diminishing returns.

Filter lists update automatically. Set the update interval under Filters > DNS blocklists > Check for updates. Every 24 hours is reasonable.

Custom Filtering Rules

AdGuard Home supports AdBlock-style filter syntax. Navigate to Filters > Custom filtering rules to add your own.

Block a domain

shell
||example-ad-network.com^

The || matches the domain and all subdomains. The ^ is a separator character that prevents partial matches.

Allow a domain (whitelist)

shell
@@||allowed-domain.com^

Prefix with @@ to override blocklist entries.

Block with a regex

shell
/ads?\d+\./

Regex rules are enclosed in forward slashes.

Block a specific service

shell
||facebook.com^ ||fbcdn.net^ ||facebook.net^

Comment lines

shell
! This is a comment # This is also a comment

Important modifiers

Block a domain only for specific clients:

shell
||ads.example.com^$client=192.168.1.50

Block a domain only for DNS type AAAA (IPv6):

shell
||example.com^$dnstype=AAAA

DNS Rewrites (Local DNS)

DNS rewrites let you resolve internal hostnames without running a separate DNS server. Navigate to Filters > DNS rewrites.

Add entries like:

| Domain | Answer |

|--------|--------|

| nas.home.local | 192.168.1.10 |

| printer.home.local | 192.168.1.20 |

| proxmox.home.local | 192.168.1.30 |

This is useful if you are running a FreeBSD router and want local devices to resolve friendly names. DNS rewrites take precedence over upstream results and filter rules.

You can also use DNS rewrites to redirect a domain to a different IP, effectively creating a split-horizon DNS for services you host internally.

DHCP Server

AdGuard Home includes a built-in DHCP server. If you enable it, AdGuard Home can automatically configure clients to use itself as the DNS server, eliminating the need to change DHCP settings on your router.

Navigate to Settings > DHCP settings and configure:

  • Interface -- select the network interface.
  • Gateway IP -- your router's LAN IP.
  • Subnet mask -- typically 255.255.255.0.
  • IP range -- the range of addresses to assign (e.g., 192.168.1.100 to 192.168.1.250).
  • Lease duration -- 24 hours is a common default.

Before enabling, disable the DHCP server on your router or existing DHCP server to avoid conflicts. Two DHCP servers on the same subnet cause unpredictable behavior.

Static leases can be assigned by MAC address, ensuring specific devices always get the same IP.

Clients and Per-Client Settings

Under Settings > Client settings, you can define named clients by IP address, CIDR range, or MAC address (when using the built-in DHCP server).

Per-client options include:

  • Custom upstream DNS servers -- route a specific client through a different resolver.
  • Custom filtering -- enable or disable specific filter lists per client.
  • Parental controls -- block adult content for specific devices.
  • Safe browsing -- force SafeSearch on search engines.
  • Block specific services -- disable TikTok, Instagram, or gaming sites for selected devices.

This is particularly useful in households where children's devices need stricter filtering than adult devices.

Query Log and Statistics

AdGuard Home logs every DNS query by default. The dashboard shows:

  • Total queries over time.
  • Blocked queries percentage.
  • Top queried domains.
  • Top blocked domains.
  • Top clients.

The query log lets you search for specific domains and see which client queried them, whether they were blocked, and which filter list matched.

Configure log retention under Settings > General settings. Options range from 24 hours to 90 days. Longer retention uses more disk space. For a busy network with many clients, 7 days is a practical balance.

You can disable query logging entirely if privacy is a concern, though you lose the ability to debug filtering issues.

HTTPS for the Web Interface

By default the AdGuard Home web interface runs on plain HTTP. For production use, especially if the interface is exposed beyond localhost, enable HTTPS.

Option 1: TLS Certificate in AdGuard Home

Navigate to Settings > Encryption settings and provide:

  • A certificate file (PEM format).
  • A private key file (PEM format).
  • The HTTPS port (443 or a custom port).

You can use a self-signed certificate or a Let's Encrypt certificate. If your FreeBSD server already uses acme.sh or certbot, point AdGuard Home at the existing certificate files.

Option 2: Reverse Proxy

Place nginx or caddy in front of AdGuard Home. This is often simpler if you already run a reverse proxy for other services. Configure AdGuard Home to listen on 127.0.0.1:8080 and proxy HTTPS traffic to it.

Example nginx snippet:

nginx
server { listen 443 ssl; server_name adguard.example.com; ssl_certificate /usr/local/etc/letsencrypt/live/adguard.example.com/fullchain.pem; ssl_certificate_key /usr/local/etc/letsencrypt/live/adguard.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

Enabling HTTPS also allows you to use AdGuard Home as a DNS-over-HTTPS server for your clients, not just as a DNS-over-HTTPS client to upstreams.

Running AdGuard Home in a FreeBSD Jail

FreeBSD jails provide OS-level isolation. Running AdGuard Home in a jail means a compromised process cannot affect the host system.

Create the Jail

Using a basic jail setup:

sh
mkdir -p /jails/adguardhome bsdinstall jail /jails/adguardhome

Or extract a base tarball:

sh
fetch https://download.freebsd.org/releases/amd64/14.2-RELEASE/base.txz tar -xf base.txz -C /jails/adguardhome

Configure the Jail

Add to /etc/jail.conf:

shell
adguardhome { host.hostname = "adguardhome"; path = "/jails/adguardhome"; ip4.addr = "192.168.1.5"; interface = "em0"; mount.devfs; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown jail"; allow.raw_sockets; }

The allow.raw_sockets parameter is needed if you want the built-in DHCP server to work inside the jail.

Install Inside the Jail

sh
jail -c adguardhome jexec adguardhome /bin/sh

Inside the jail, follow the same binary installation steps as above. Copy the rc.d script into the jail's /usr/local/etc/rc.d/ and enable the service.

Start the jail at boot:

sh
sysrc jail_enable="YES" sysrc jail_list+="adguardhome"

Jail Considerations

  • Assign a dedicated IP to the jail. Do not share the host's IP for port 53.
  • If using DHCP inside the jail, the jail needs allow.raw_sockets.
  • Keep the jail's FreeBSD base updated with freebsd-update inside the jail.
  • The jail adds negligible overhead. AdGuard Home typically uses 50-100 MB of RAM.

AdGuard Home vs. Pi-hole

Both are network-wide DNS sinkholes. Here is how they compare on FreeBSD:

| Feature | AdGuard Home | Pi-hole |

|---------|-------------|---------|

| FreeBSD support | Official binary | No official support. Requires Linux or manual porting. |

| Installation | Single binary | PHP, lighttpd, FTL, multiple dependencies |

| DNS-over-HTTPS/TLS | Built-in (client and server) | Requires external tools (cloudflared, stubby) |

| DHCP server | Built-in | Built-in (Linux only) |

| Web interface | Embedded | Separate PHP application |

| Custom filtering syntax | AdBlock syntax, regex | Regex, wildcard |

| Per-client settings | Yes | Partial (groups in v6) |

| Resource usage | ~50-100 MB RAM | ~100-200 MB RAM (with PHP/FTL) |

| Open source | Yes (GPLv3) | Yes (EUPL) |

For FreeBSD users, AdGuard Home is the clear choice. Pi-hole is designed for Linux and does not officially support FreeBSD. Porting it requires significant effort and ongoing maintenance.

AdGuard Home vs. Unbound with Blocklists

Some administrators skip AdGuard Home entirely and feed blocklists directly into Unbound using unbound-adblock or similar scripts.

| Aspect | AdGuard Home | Unbound + Blocklists |

|--------|-------------|---------------------|

| Web interface | Yes | No |

| Query logging/stats | Built-in dashboard | Manual log parsing |

| Filter list updates | Automatic | Cron scripts |

| Custom rules | AdBlock syntax | Unbound local-zone entries |

| DNS-over-HTTPS server | Yes | With additional config |

| Per-client filtering | Yes | No |

| DHCP | Built-in | Separate service |

| Complexity | Low | Moderate |

| DNS resolution | Forwards to upstream | Recursive (no third party needed) |

The best of both worlds: run Unbound as a recursive resolver on port 5353 and point AdGuard Home at it as the upstream. You get AdGuard Home's filtering, dashboard, and per-client control with Unbound's recursive resolution and DNSSEC validation. No reliance on third-party DNS providers.

Updating AdGuard Home

AdGuard Home does not auto-update on FreeBSD when installed as a standalone binary. To update:

sh
service adguardhome stop fetch https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_freebsd_amd64.tar.gz tar -xzf AdGuardHome_freebsd_amd64.tar.gz cp AdGuardHome/AdGuardHome /usr/local/bin/AdGuardHome/AdGuardHome service adguardhome start

Configuration is preserved in /var/db/adguardhome/AdGuardHome.yaml. Back up this file before upgrading.

Frequently Asked Questions

Does AdGuard Home work on FreeBSD?

Yes. AdGuard Team provides official FreeBSD binaries for both amd64 and arm64 architectures. It runs as a standalone static binary with no dependencies on Linux-specific libraries.

Can AdGuard Home replace my existing DNS server?

Yes. AdGuard Home listens on port 53 and handles all DNS queries. If you currently use local_unbound (FreeBSD's default), disable it and point clients at AdGuard Home. Alternatively, keep Unbound running on a non-standard port and use it as AdGuard Home's upstream.

How much RAM does AdGuard Home use?

Typically 50-100 MB depending on the number of filter lists and query log retention. With multiple large blocklists and 30 days of query logging, usage may reach 150-200 MB. This is well within the capability of even modest hardware.

Will AdGuard Home slow down my DNS resolution?

No. DNS filtering happens in memory via hash lookups and is essentially instantaneous. If you use encrypted upstream DNS (DoH/DoT), the first query to a new domain may add a few milliseconds compared to plain DNS, but results are cached. Most users notice no difference.

Can I use AdGuard Home alongside a FreeBSD firewall/router?

Absolutely. This is one of the most common deployments. Set up your FreeBSD router with pf or ipfw, run AdGuard Home on the same box or in a jail, and configure DHCP to hand out AdGuard Home's IP as the DNS server. All network traffic is filtered at the gateway.

How do I block a specific website for one device only?

Use per-client settings. Define the client by IP or MAC address under Settings > Client settings, then add a custom filtering rule with the $client modifier:

shell
||distracting-site.com^$client=192.168.1.50

Can AdGuard Home serve as a DNS-over-HTTPS server for my devices?

Yes. Once you configure TLS certificates under Settings > Encryption settings, AdGuard Home can serve DoH and DoT to clients. This encrypts DNS queries between your devices and AdGuard Home, which is useful when devices connect over untrusted networks via VPN back to your FreeBSD server.

How do I back up my AdGuard Home configuration?

Copy the AdGuardHome.yaml file from your working directory (/var/db/adguardhome/ in this guide). This file contains all settings, filter lists, DNS rewrites, client definitions, and custom rules. Restore by copying it back and restarting the service.

Summary

AdGuard Home on FreeBSD gives you network-wide ad and tracker blocking with minimal resource usage and zero client-side software. The single-binary deployment model, combined with FreeBSD's rc.d service management and jail isolation, makes for a clean and maintainable setup.

For the strongest configuration, pair AdGuard Home with Unbound for recursive DNS resolution. Run it inside a FreeBSD jail for isolation. Use your FreeBSD router or DHCP server to push AdGuard Home's IP as the network DNS server. The result is a fully self-hosted, encrypted, filtered DNS infrastructure with no reliance on third-party services.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.