Valkyrian Labs logo

forti-hole

DNS blocklists as FortiGate threat feeds, deduplicated, budgeted and verified.

forti-hole downloads the DNS blocklists you choose (hagezi, StevenBlack, your own lists), merges them into one deduplicated set, and keeps that set on a FortiGate as push-mode external threat feeds. FortiGate DNS filter profiles block the feeds' categories, so every DNS query that crosses a policy with one of those profiles is filtered by your lists, with no resolver to run.

When forti-hole is the right tool

forti-hole or a real Pi-hole?

forti-hole is for networks that already have a FortiGate and do not want to run their own DNS server. If you are willing to own DNS (a Pi-hole, AdGuard Home or Unbound box), a real resolver does more: per-client query logs, instant allow-listing from a dashboard, regex blocking, CNAME inspection, and no device-wide entry limit. Use one or the other: a Pi-hole behind a FortiGate already filters, and forti-hole adds nothing to it.

You wantUse
Ad, tracker and threat blocking on a FortiGate network, nothing else to runforti-hole
Query logs, per-client dashboards, instant allow-lists, regex rulesPi-hole (or AdGuard Home) as your DNS server
Pi-hole groups kept in step with FortiGate devicesforti-pihole

What it does

  1. Fetch

    Every list is downloaded in parallel with conditional requests: an unchanged list costs a 304 and nothing else. A download that fails, returns a web page, is truncated or shrinks by more than 20% is rejected, and the last good copy is used instead. A failed download never empties a feed.

  2. Compile

    Every name is parsed, canonicalized (lowercase, no trailing dot, punycode) and kept once, across sources and across filtering tiers. Names already covered by a blocked parent domain are dropped. Adblock rules keep their meaning on the FortiGate: ||example.com^ becomes example.com and *.example.com, because a FortiOS feed entry example.com matches that name only.

  3. Budget

    The compiled line count is checked against the device's domain-entry limit (1,000,000 on entry-level models such as the FortiGate-60F) and against its memory, before anything is written. A set that does not fit is refused, never silently truncated. hagezi TIF picks its largest variant that fits (auto: medium, else mini).

  4. Push

    Only what changed is sent: add and remove commands for the entries that differ, a full snapshot only for a new feed or one whose device contents can no longer be trusted.

  5. Verify

    After every push forti-hole reads the device back: the entry count must equal the compiled count, nothing may be invalid or truncated, and sampled entries must be compiled lines. Only then is a feed's content recorded as confirmed.

Measured on a FortiGate-60F

The default configuration (StevenBlack, hagezi pro, pro.plus, ultimate and TIF in four tiers, three profiles), compiled on 2026-10-18 and loaded on a FortiGate-60F (FortiOS 7.4.8, 2 GB RAM):

Valid entries in the five lists962,134
Duplicates removed (within and across lists)495,982
Covered by a blocked parent domain49,141
Unique names published416,765
FortiOS feed lines (TIF mini, strict encoding)807,914 in 11 feeds
TIF medium instead2,221,664 lines: does not fit the 1,000,000-entry limit
Device memory during the first load / an hour later+1.5% / +0.2% of 2 GB
A sync with no upstream change0 writes, about 5 seconds

See Capacity for the limits and how forti-hole stays inside them.

Safety

  • It never touches what it did not create. Feeds and DNS filter profiles are forti-hole's only when they carry its name prefix and its ownership marker; everything else is read-only, and a name collision stops the run. A guard under the engine refuses any other write before it is sent.
  • Policies change only when you say so (forti-hole attach), never during a sync.
  • Nothing is written until "enabled": true, and every write goes through the forti engine's plan and apply: your forti profile's mode (read-only, guarded, autonomous) applies, and every change is audited.

Next

Install

Homebrew, APT, or a source build.

Quick start

From an empty FortiGate to verified feeds.

Where filtering applies

Which network layouts a FortiGate DNS filter can see.