Here’s how to schedule your AdGuard Home container to run automatically on boot using a Quadlet file—no manual enabling required. These steps assume you’re on Fedora CoreOS as of December 2025, with a recent Podman version.

If CoreOS is not installed yet, use Beginner’s Guide to Fedora CoreOS or the 2026 Bitwarden + Ignition + AdGuard guide (that one bakes a Quadlet into Butane). This post is the after-boot version: nano a .container file, nftables, auto-update timer. Pi-hole instead of AdGuard: Pi-hole Quadlet. Do not run both resolvers on the same IP and port 53.

Why AdGuard Home on CoreOS?

Same appliance story as Pi-hole: one job, atomic host, containers as systemd. AdGuard Home’s first-run wizard lives on port 3000, then the UI typically moves to 80. It wants host networking in this unit so DNS on port 53 is not DNAT-spaghetti. That also means the container sees the host’s network stack — which is why the nftables section matters.

Prerequisites

  • Fedora CoreOS, SSH as core.
  • Static IP (examples use a LAN 192.168.1.0/24).
  • Nothing else bound to 53, 80, or 3000. systemd-resolved stub on 127.0.0.53 is OK; a host bind on *:53 is not.
  • Timezone string you like (America/Chicago in the sample).
sudo ss -tulpn | grep -E ':53|:80|:3000|:22'
sudo podman ps -a

Remove leftover AdGuard/Pi-hole containers before you start.

Step 1: Create the Quadlet file

Fedora CoreOS uses /etc/containers/systemd/ for Quadlet files, which define containers as systemd services. Let’s create adguardhome.container:

sudo nano /etc/containers/systemd/adguardhome.container

Paste this (modify the network info with yours; AdGuard Home has a setup wizard for passwords and other configs):

[Unit]
Description=AdGuard Home Container
After=network-online.target
Wants=network-online.target

[Container]
ContainerName=adguardhome
Image=docker.io/adguard/adguardhome:latest
AutoUpdate=registry
Network=host
AddCapability=NET_ADMIN
Environment=TZ=America/Chicago
Volume=adguardhome_work:/opt/adguardhome/work:Z
Volume=adguardhome_conf:/opt/adguardhome/conf:Z

[Service]
Restart=always
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target

Save and exit (Ctrl+O, Enter, Ctrl+X in nano).

Why these keys

  • Network=host: AdGuard binds DNS and the web UI on the host’s addresses. Published ports are the wrong model here.
  • AutoUpdate=registry: pairs with podman-auto-update so the image can roll forward without you SSH’ing to podman pull.
  • TimeoutStartSec=900: first image pull.
  • :Z on volumes: SELinux on FCOS.
  • No password env vars: unlike Pi-hole v6, the wizard owns the admin account. That is easier to screenshot and easier to forget — set a real password at first login.

Pin a tag instead of :latest once you like a version. Auto-update plus :latest is convenient and also how surprises arrive; I still show it because that is the homelab default.

Optional volume create:

sudo podman volume create adguardhome_work
sudo podman volume create adguardhome_conf

Step 2: Reload systemd

Tell systemd to process the Quadlet file with Podman’s quadlet generator:

sudo systemctl daemon-reload

This generates a transient adguardhome.service in /run/systemd/generator/.

systemctl cat adguardhome.service

If cat fails, the file name or directory is wrong (*.container under /etc/containers/systemd/).

Step 3: Start the container

Kick it off manually the first time:

sudo systemctl start adguardhome.service

Follow logs:

sudo journalctl -u adguardhome.service -f

Check it’s running:

sudo podman ps -a
sudo systemctl status adguardhome.service

You should see your adguardhome container up and humming.

Enable AUTO-UPDATE:

sudo systemctl enable --now podman-auto-update.timer
systemctl list-timers podman-auto-update.timer

Expected: a timer with a next run. Auto-update only restarts units that opted in with AutoUpdate=registry. A Quadlet without that key will not update. After an update, glance at sudo podman ps so you are not surprised by a new major image.

Open the wizard before you put nftables in front, or you may lock yourself out of port 3000:

http://YOUR_COREOS_IP:3000

Complete admin user, upstream DNS (I use 1.1.1.1 / 1.0.0.1 as a starting point, not as a religion), and listen addresses. After the wizard, the UI is usually http://YOUR_COREOS_IP/ on port 80. Confirm with sudo ss -tulpn | grep -E ':80|:3000|:53'.

Step 4: Configure nftables firewall

For security, we’ll set up a lightweight nftables firewall to control access to AdGuard Home and other services on your Fedora CoreOS host. CoreOS may not ship firewalld; nftables is the right small tool. If you already layered firewalld for the beginner Pi-hole guide, do not run both with competing default-drop policies. Pick one.

Create the firewall configuration

sudo nano /etc/nftables.conf

Add the following rules (adjust 192.168.1.0/24 to match your LAN subnet):

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        
        # Allow established connections
        ct state established,related accept
        
        # Allow loopback
        iif lo accept
        
        # Allow DNS from LAN only
        ip saddr 192.168.1.0/24 udp dport 53 accept
        ip saddr 192.168.1.0/24 tcp dport 53 accept
        
        # Allow AdGuard web interface from LAN
        ip saddr 192.168.1.0/24 tcp dport 80 accept
        
        # Allow SSH from LAN only
        ip saddr 192.168.1.0/24 tcp dport 22 accept
        
        # Allow ICMP ping
        icmp type echo-request accept
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Save and exit (Ctrl+X, Y, Enter in nano — or Ctrl+O / Ctrl+X if that is your muscle memory).

Why default drop on input? An AdGuard box with host networking is a DNS server and a web UI on the same IP. You do not want port 80 or 53 on the WAN. If this host has a public address, this ruleset is incomplete (no mention of 3000, IPv6, or your VPN interface). Add tcp dport 3000 from LAN if you still need the wizard, or finish the wizard before applying drop.

IPv6: this sample only matches ip saddr (IPv4). If your LAN is v6-heavy, add ip6 saddr analogues or you will think AdGuard is “broken” for v6 clients.

Test and apply the configuration

First, test the configuration for syntax errors:

sudo nft -c -f /etc/nftables.conf

If no errors appear, apply the rules:

sudo nft -f /etc/nftables.conf

Keep an SSH session open and test a second SSH from another terminal before you disconnect. A typo in the SSH rule plus default drop is an unscheduled drive to the homelab.

Enable firewall on boot

sudo systemctl enable nftables
sudo systemctl start nftables

On some FCOS builds you may need to confirm the unit name (systemctl list-unit-files | grep nft). The important part is that /etc/nftables.conf is loaded on boot so a reboot does not leave DNS wide open or, worse, fail closed after you already applied drop once.

Verify the configuration

sudo nft list ruleset

Test DNS from another device on your network:

nslookup google.com YOUR_COREOS_IP
dig @YOUR_COREOS_IP example.com

Your AdGuard Home installation is now secured with a firewall that only allows access from your local network while still permitting system updates and outbound connections (output policy accept).

If nslookup times out after nftables but worked before, your client is not in 192.168.1.0/24 (guest Wi-Fi, VPN, different VLAN). Widen the prefix on purpose or do not use guest isolation with this ruleset.

Step 5: Test autostart on reboot

The WantedBy=multi-user.target line ensures AdGuard Home starts on boot. Test it:

sudo reboot

After reboot, verify:

sudo podman ps -a
sudo systemctl status adguardhome.service nftables
sudo nft list ruleset | head

If adguardhome is running, you’re set—no systemctl enable on the container unit, as Quadlets handle autostart dynamically. nftables should still show the LAN-only DNS rules.

Point DHCP at this IP only after reboot + dig succeed. A nightly host reboot (optional) is CoreOS nightly reboots — schedule it when nobody needs DNS.

Notes

  • Why no enable? Generated services in /run/ are transient and can’t be enabled traditionally. The [Install] section ties it to the boot process instead.
  • Tweaks: Older Quadlet guides mention Hostname or RestartPolicy, but these are unsupported now—stick to the basics above.
  • Hostname: Defaults to adguardhome from ContainerName. If you need adguard-home, you’d need a custom workaround or a classic systemd service.
  • Initial setup: After starting, access the AdGuard Home web interface at http://your-server-ip:3000 to complete the initial configuration wizard. Set your admin password, upstream DNS servers (e.g., 1.1.1.1), and any other preferences there. Unlike Pi-hole, many settings are handled via the UI rather than environment variables. After the initial setup, your port will change to http://your-server-ip:80.
  • Volumes: The persistent volumes (adguardhome_work and adguardhome_conf) store your configuration and data. Ensure Podman volumes are created if needed (they’ll be auto-created on first run). Back those volumes up if the box is the only DNS for the house.
  • Port 3000 vs nftables: the sample nftables does not open 3000. Finish the wizard first, or add a LAN-only 3000 rule.
  • Encryption / HTTPS on the UI: do that in AdGuard’s settings behind the LAN firewall; do not expose 80 to the internet “just for a cert.”

Troubleshooting

  • Wizard never loads: container not running, or you applied nftables too early. journalctl -u adguardhome.service, ss -tulpn.
  • DNS works, UI does not: browser is still on 3000 after the wizard moved to 80, or port 80 blocked.
  • Auto-update “broke DNS at 4 AM”: pin an image digest/tag, disable the timer, or watch podman auto-update --dry-run.
  • Conflict with systemd-resolved: if the host insists on 53, follow the resolved stub disable pattern in the 2026 CoreOS Quadlet guide.
  • SELinux volume denials: you dropped :Z. Put it back.

That’s it! Your AdGuard Home is now a proper Fedora CoreOS citizen, managed via Podman Quadlets. Enjoy ad-free browsing.

Best regards,

The Linux IT Guy