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:
shuname -m
Download the latest release:
shfetch 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:
shmkdir -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:
shchmod +x /usr/local/etc/rc.d/adguardhome sysrc adguardhome_enable="YES"
Ensure the working directory is owned by the service user:
shchown -R nobody:nobody /var/db/adguardhome
Start the service:
shservice adguardhome start
Initial Web Setup Wizard
On first launch, AdGuard Home starts a setup wizard on port 3000. Open your browser and navigate to:
shellhttp://YOUR_SERVER_IP:3000
The wizard walks through:
- Admin credentials -- set a strong username and password.
- 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. - 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:
shellhttps://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:
shelltls://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:
shell127.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:
shell9.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:
nginxserver { 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:
shmkdir -p /jails/adguardhome bsdinstall jail /jails/adguardhome
Or extract a base tarball:
shfetch 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:
shelladguardhome { 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
shjail -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:
shsysrc 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-updateinside 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:
shservice 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.