Onboarding
From a forti profile to a first sync: setup, reviewing networks and groups, slice proposals, the plan, enabling, and the optional service.
Onboarding
This guide takes an installed forti-pihole to a FortiGate and a Pi-hole that stay in step. Every step before Enable is read-only on both systems: you can stop, change your mind and start again at any point. Plan on reviewing the output of each step before moving on.
Before you start
- forti-pihole is installed, and
forti(forti-cli) is available forforti configure. - Pi-hole v6 with FTL 6.7.0 or newer, reachable over HTTPS, and an app password (Settings → Web interface / API → Configure app password).
- The Pi-hole groups you want devices to land in already exist in Pi-hole, with their blocklists. forti-pihole maps device groups to Pi-hole groups by name; it never creates them during a sync.
Connect the FortiGate
1forti configure2forti-pihole statusforti configurecreates the device profile and stores its API key.statusshows the profile and its mode, and saysNOT enabled: plans onlyuntil you enable the configuration. Prefer aguardedprofile while you onboard: every FortiGate change then waits for yourforti approve.Run setup
1forti-pihole setup --pihole-url https://pihole.example.netsetupwrites a starting configuration to$FORTI_HOME/pihole/config.jsonwhen there is none (the same oneforti-pihole initwrites), then:- reads the FortiGate's identity, FortiOS version and the profile's mode;
- logs in to Pi-hole. When no password is stored yet, it asks for the app password (input hidden; or
pipe it with
--password-stdin), verifies it, and stores it in forti's secret store aspihole/<name>/password, bound to the Pi-hole's host and port; - lists every LAN-side interface with an address and suggests a strategy:
subnetfor a VLAN,slicesfor a flat network with a DHCP server,observeotherwise. Interfaces with a DHCP server that the configuration does not list yet are added inobservemode; - suggests a Pi-hole group for every device group without one: an unambiguous, case-insensitive match
of the names (
tvs→TVs). Suggestions are written to the configuration and marked[suggested]; names that do not exist in Pi-hole are marked[missing in Pi-hole].
1FortiGate2 FortiGate 60F (fw01), FortiOS v7.4.8, profile fw01 in guarded mode3 4Pi-hole5 stored the password in forti's secret store (keychain) as pihole/default/password6 FTL v6.7.1 at https://pihole.example.net7 groups: Default, TVs, IoT8 client entries: 19 10Networks11 internal 192.168.1.0/24 hard-switch suggested: slices (a flat network with DHCP: slice it per group)12 13Group mappings14 trusted -> (Default)15 work -> (Default)16 tvs -> TVs [suggested]17 iot_trusted -> (Default)18 iot_untrusted -> IoT [suggested]19 default -> (Default)20 21updated /home/you/.forti/pihole/config.json22nothing was written to the FortiGate or Pi-hole. Review the networks (mode, slices) and groups, then:23 forti-pihole slices --propose forti-pihole plan and set "enabled": true when the plan looks rightRun
setupagain whenever you like: it keeps what you configured and only adds what is missing.Review networks and groups
1forti-pihole networks2forti-pihole groups3forti-pihole devices -vnetworkslists every non-WAN interface with its subnet, VLAN id, configured strategy, DHCP pools and device count.groupsshows each device group, its FortiGate address group (fp-grp-<group>), its member count and its Pi-hole group.devices -vshows every device, the group it is classified into and why.Now edit
config.json:- Networks: give each network its
modeandgroup. A VLAN whose whole subnet should get one filtering policy issubnet; a flat network isslices; a VLAN with a few groups carved out of it ishybrid. See Allocation strategies. - Groups: set
pihole_groupwhere the suggestion is wrong or missing. Mark the groups that grant trust (trusted,work)"privileged": true: no rule can ever put a device there. - Rules: adjust the example rules (vendor, family, type, OS, hostname, DHCP vendor class, MAC prefix). See Device groups and rules.
- Pins: put the devices you know into their group with
forti-pihole assign MAC GROUP, or move them in the FortiGate GUI later. Devices that must never be touched go inprotected.
- Networks: give each network its
Propose slices
For
slicesandhybridnetworks, let the allocation planner size and place a slice for every Pi-hole mapped group with members there:1forti-pihole slices --propose1internal 192.168.1.0/24 (slices)2 192.168.1.200/29 tvs proposed3 192.168.1.208/28 iot_untrusted proposed4 192.168.1.200/29 used 0/85 192.168.1.208/28 used 0/16Here the DHCP pool is
192.168.1.10-192.168.1.199, three TVs need a/29and eight smart plugs a/28. Nothing is written: copy the slices you accept into the network'sslicesinconfig.json. Slices are placed outside the DHCP pools; when there is not enough room, the planner says how many addresses are missing and lists options. See Address slicing.Read the plan
1forti-pihole planplanshows everything a sync would do, on both systems: device objects and group membership on the FortiGate, Pi-hole client entries to create or update, notes about Pi-hole entries that shadow the managed ones, address-slice actions, and migrations (with the reason when one would be refused). It writes nothing, not even forti-pihole's own state.plan --jsongives the same as JSON.Iterate on the configuration until the plan is what you want.
Enable and sync
Set
"enabled": trueinconfig.json, then:1forti-pihole syncThe FortiGate objects are planned and applied through the forti engine. With a
guardedprofile the output sayswaiting for approval: forti approve <plan id>and exits7; approve it withforti approve <plan id>and runforti-pihole syncagain, which applies the approved plan. Pi-hole's managed client entries are written in the same run.The output ends with an
Appliedsection: one line per stage, with(rollback: forti apply <plan>)after every FortiGate apply; that command undoes it.forti-pihole historylists every write stage later (--jsonincludes the rollback plans).Turn on reservations, one network at a time
Until you set
"manage_reservations": trueon a slice network, forti-pihole only plans address changes there. Before you do, move one device by hand and watch it end to end:1forti-pihole migrate 5c:e9:31:aa:bb:cc --dry-run2forti-pihole migrate 5c:e9:31:aa:bb:ccMigrations walks through a complete move, including the administrator objects you may need to
adoptfirst. Withmanage_reservationson, everysyncadds reservations for devices already inside their slice and starts at most one new migration (--max-migrations N).Keep it running
Pick one:
- The timer (Linux):
systemctl --user enable --now forti-pihole.timerruns a sync every 15 minutes. - The service:
forti-piholedruns a sync promptly after every FortiGate configuration change and a full one every 15 minutes. Configuredaemon.json, start it (systemctl --user enable --now forti-piholed.service, orbrew services start forti-pihole), then let the FortiGate notify it:
1forti-pihole events install --url http://192.0.2.10:8735See Runtime.
forti-pihole pausestops both from writing at any time;forti-pihole resumelets them continue.- The timer (Linux):
When something looks wrong
- Nothing changes: the configuration is not enabled, or sync is paused (
forti-pihole status). - A Pi-hole mapping does not take effect: an operator client entry for the same address or a narrower
range decides instead.
planreports it as a note. - A device keeps its old address: it has not renewed its lease yet. See Troubleshooting.