Valkyrian Labs logo

Install

Install forti-pihole with Homebrew or APT, or build it from source, and prepare the FortiGate profile and the Pi-hole app password it needs.

Install

forti-pihole ships two executables: forti-pihole, the command-line program, and forti-piholed, the optional service that reacts to FortiGate changes. libcurl is the only runtime dependency. Install them with Homebrew or APT, or build from source, then check the prerequisites below.

Prerequisites

You needWhy
A FortiGate reachable over its REST API, with a forti profileforti-pihole talks to the FortiGate through the forti engine, with a device profile and API key that forti configure (from forti-cli) creates in the forti home. Developed against FortiOS 7.4
Pi-hole v6, FTL 6.7.0 or newerforti-pihole uses the Pi-hole v6 REST API and refuses older FTL versions, and versions it cannot read
A Pi-hole app passwordA periodic job cannot answer two-factor prompts. Create one in Pi-hole under Settings → Web interface / API → Configure app password; forti-pihole setup asks for it once
HTTPS to Pi-holePlain http:// is accepted only for a loopback Pi-hole (localhost, 127.x.x.x, [::1]); anywhere else the password and session would cross the network in clear

The forti profile's mode decides how writes happen, exactly as for forti itself: read-only applies nothing, guarded waits for your forti approve, autonomous applies directly. See Safety.

Install the packages

1brew install valkyrianlabs/tap/forti-cli valkyrianlabs/tap/forti-pihole

Recent Homebrew versions ask you to trust a third-party tap first (brew trust valkyrianlabs/tap). forti-cli provides forti configure; forti-pihole has the engine compiled in and does not need it at run time.

The example configurations are in $(brew --prefix)/share/forti-pihole/. The optional service runs under brew services start forti-pihole (Runtime).

Check the installation

1forti-pihole --version2forti-piholed --version
1forti-pihole 0.1.0 (engine forti-cli 468f9e1, forti-api 1.1.1)2forti-piholed 0.1.0 (engine forti-cli 468f9e1, forti-api 1.1.1)

The version line names what the binary was built from: the forti-cli engine revision and the forti-api version. A build from a modified engine checkout shows the revision with -dirty.

Create the FortiGate profile

1forti configure

forti configure asks for the FortiGate's address, an API key and the profile's mode, and stores the key in forti's secret store. forti-pihole uses the default profile unless the configuration's profile, or --profile NAME, names another.

macOS Keychain prompts

On macOS the API key, the Pi-hole app password and the webhook token live in the login Keychain (service forti). Each item belongs to the binary that created it, so the first time forti-pihole or forti-piholed (and every newly installed or upgraded build of either) reads one, macOS asks. Choose Always Allow. See Troubleshooting.

Where it keeps its files

forti-pihole uses the forti home: ~/.forti, or the directory $FORTI_HOME names. Profiles and credentials are the ones forti configure manages there. Its own files live in pihole/:

PathWritten byWhat
pihole/config.jsonyou, init, setupThe configuration (Configuration)
pihole/state.jsonsync, assign, adopt, confirmDevices seen, pins, adoptions, reassociation candidates, a pending plan
pihole/history.jsonlsyncOne line per write stage (forti-pihole history)
pihole/operations/<id>.jsonmigrate, syncThe journal of each address migration
pihole/lockevery runOne run at a time (a timer, the service and you never overlap)
pihole/daemon.jsonyouforti-piholed settings (Configuration)
pihole/daemon-state.json, daemon-state.lockforti-piholed, pause, resumeThe service's last event and run, backoff, and the pause flag
pihole/events.jsonlforti-piholedAccepted events and finished runs; rotates to events.jsonl.1

Every file forti-pihole and forti-piholed create is 0600, in a 0700 directory. No secret is ever written to any of them: the API key, the Pi-hole app password and the webhook token stay in forti's secret store.

Next