Building a FortiManager Lab on Proxmox — Part 5: Registering Managed FortiGates, ADOMs and Policy Package Installs

Parts 1 to 4 built the platform: sized host, FortiManager VM from a qcow2, four-segment Proxmox network, and a lab edge FortiGate as the security boundary. Part 5 is where it becomes a working integration lab — managed FortiGates registered into FortiManager, ADOMs separating them, a policy package built once and installed on both, and the verification rhythm that turns this from a screenshot lab into something you can actually learn from.

Step 1 — Build two managed FortiGate-VMs

Same recipe as the lab edge in Part 4, smaller, on different VMIDs:

for i in 1 2; do
  vmid=$((9100 + i))
  qm create $vmid \
     --name fgt-managed-0$i \
     --memory 4096 \
     --cores 2 \
     --sockets 1 \
     --cpu host \
     --machine q35 \
     --bios seabios \
     --ostype l26 \
     --scsihw virtio-scsi-single \
     --net0 virtio,bridge=vmbr-transit,firewall=0 \
     --net1 virtio,bridge=vmbr-cust,firewall=0 \
     --serial0 socket \
     --vga serial0
done

# Import the disks (same fortios.qcow2 / datadrive.qcow2 from Part 4)
for i in 1 2; do
  vmid=$((9100 + i))
  qm importdisk $vmid /root/fgt-7.6.2/fortios.qcow2  local-lvm --format qcow2
  qm importdisk $vmid /root/fgt-7.6.2/datadrive.qcow2 local-lvm --format qcow2
  qm set $vmid --scsi0 local-lvm:vm-${vmid}-disk-0,discard=on,iothread=1,ssd=1
  qm set $vmid --scsi1 local-lvm:vm-${vmid}-disk-1,discard=on,iothread=1,ssd=1
  qm set $vmid --boot order=scsi0
done

qm start 9101
qm start 9102

Each managed FGT has two NICs:

PortBridgeSubnetRole
port1vmbr-transit10.20.30.0/24 (DHCP from FGT-edge)“WAN” — reaches FMG via FGT-edge
port2vmbr-cust10.20.40.x/24 (configure statically)Customer LAN

Step 2 — Bare-minimum config on each managed FGT

Console into each (qm terminal 9101), set the password, and apply:

# fgt-managed-01
config system global
    set hostname "fgt-managed-01"
    set timezone 28                         ; Europe/London
end

config system interface
    edit "port1"
        set mode dhcp
        set role wan
        set allowaccess ping
        set defaultgw enable
    next
    edit "port2"
        set ip 10.20.40.10 255.255.255.0
        set role lan
        set allowaccess ping ssh https
    next
end

# DNS through the lab edge FGT
config system dns
    set primary 10.20.30.1
end

config central-management
    set type fortimanager
    set fmg "10.20.10.10"
end

Repeat on fgt-managed-02 with hostname fgt-managed-02 and port2 IP 10.20.40.11.

The line that actually triggers registration is config central-management → set fmg "10.20.10.10". As soon as that’s committed, the managed FGT initiates an FGFM session (TCP/541) to FMG. Rule 30 on the lab edge (Part 4) is what permits that traffic.

Step 3 — Approve the registrations on FMG

In the FortiManager GUI: Device Manager → Unregistered Devices. You should see both fgt-managed-01 and fgt-managed-02 waiting. From CLI on the FMG, the equivalent is:

diagnose dvm device list
diagnose dvm device list unreg

For each one: select → Add → confirm. FMG will:

  1. Pull the running config and store it as the initial revision.
  2. Discover the device’s interfaces, system objects, and existing policy.
  3. Place the device into the default ADOM (root) — we’ll move it shortly.

Verify on the FMG CLI:

diagnose dvm device list

You should see both devices in state: 0 (none) (idle, in sync) after a minute. If one stays in state: 5 (retrieving) for more than five minutes, FGFM probably isn’t reaching back — drop into the lab edge and check Log & Report → Forward Traffic for denies on TCP/541.

Step 4 — Create ADOMs

ADOMs are the FortiManager equivalent of multi-tenancy. For a lab, two ADOMs is enough to learn the model:

# Enable ADOMs (this is a one-time global setting)
config system global
    set adom-status enable
end

The CLI logs you out and back in. From the GUI now: System Settings → All ADOMs → Create New.

Create two:

ADOM nameVersionPurpose
lab-customer-a7.6Holds fgt-managed-01
lab-customer-b7.6Holds fgt-managed-02

Then Device Manager → root → fgt-managed-01 → Move ADOM to lab-customer-a, same for the second device into lab-customer-b.

This is the moment FMG stops being “a fancy SSH-jump-host with backups” and starts being a real management platform. Each ADOM gets its own policy package, address objects, services, schedules, profiles. Two ADOMs that look almost identical, one diff at a time, teach you more about FMG than any single-ADOM lab will.

Step 5 — Build a shared policy package

Switch to the lab-customer-a ADOM. Policy & Objects → Policy Packages → default → Edit. Build a small, realistic policy set:

#Source intfDest intfSource addrDest addrServiceActionNATUTM
1port2 (lan)port1 (wan)net-cust-a (10.20.40.0/24)allDNS, HTTPS, HTTP, NTP, PINGAcceptenablewebfilter:default, ssl:certificate-inspection
2port2port1net-cust-ablock-list-fqdnALLDeny
3 (implicit)anyanyallallALLDeny + Log

Address objects to pre-create:

# In FMG GUI under Policy & Objects → Object Configurations → Addresses:
# net-cust-a   : 10.20.40.0/24
# block-list-fqdn : FQDN object pointing to e.g. doubleclick.net (just to see UTM working)

block-list-fqdn is useful — it gives you a deterministic test target. Visit doubleclick.net from the customer LAN behind fgt-managed-01; the deny log lights up.

Save the package, then Install Wizard → Install Policy Package & Device Settings → Select fgt-managed-01. Click through the preview — FMG shows you the exact CLI it will push. Read it. This is the single most useful habit FortiManager teaches you: every install has a preview, and the preview is literal CLI. If anything looks wrong, cancel.

Once installed, on fgt-managed-01:

get system status         # check config-sync = synchronized
diagnose fdsm status      # FortiGuard sync status
show firewall policy

The policy you just installed should be there in CLI form, marked with the _PolicyBlock = "default" line that signals FMG ownership.

Step 6 — Repeat on lab-customer-b, then change one thing

Switch to lab-customer-b. Build the same policy package — easiest path is Policy Package → default → Clone from lab-customer-a, then update the address objects (net-cust-b for 10.20.40.0/24 from the fgt-managed-02 perspective — same subnet in this lab; in production you’d separate them).

Now make a single difference: in lab-customer-b, add a third allow rule for SSH outbound. Install. Diff the two packages: Policy & Objects → Policy Package Diff between lab-customer-a and lab-customer-b. The single-line diff is the proof FMG is doing what you want.

This is the operational reality of multi-tenant management: 95 % shared policy, 5 % per-customer divergence, every divergence visible and revisable.

Step 7 — Revision history and rollback

The other thing FMG does that no SSH-jump-host can: revision history. After the install on fgt-managed-01, go to Device Manager → fgt-managed-01 → Revision History. You’ll see two revisions:

  1. Initial discovery (taken at registration).
  2. Post-install (after the first FMG-pushed policy).

Right-click revision 1 → Revert. FMG previews the reversal CLI. Cancel — but understand what just happened. You can roll back any managed device to any previous revision, and the preview shows you exactly what reverts. This is the operational habit FortiManager exists to teach. Use it.

Step 8 — FortiGuard distribution from FMG (optional but worth it)

By default each managed FGT pulls FortiGuard updates direct from update.fortiguard.net. In production with limited internet bandwidth or strict egress, you instead make FMG the local FortiGuard mirror.

On FMG: System Settings → Advanced → Server Access Settings → Enable FortiGuard Server. This turns FMG into a local FDS (FortiGuard Distribution Server).

On each managed FGT (push from FMG via a CLI script, or set directly):

config system central-management
    set fmg "10.20.10.10"
    set include-default-servers disable
    config server-list
        edit 1
            set server-type update rating
            set server-address 10.20.10.10
        next
    end
end

Now fgt-managed-01 and -02 pull from FMG, FMG pulls from Fortinet, and your lab egress shows one device hitting update.fortiguard.net instead of three. Verify with:

# On a managed FGT
diagnose fdsm contract-controller-update
get system fortiguard

The “Override server” should now show 10.20.10.10. On the FMG:

diagnose fmupdate fds-get-statistics

Should show clients pulling.

Step 9 — Things that should not work, and verifying they don’t

The deny log is the most useful diagnostic in this lab. Try each of these and confirm the lab edge denies them with a logged event:

  • From the customer LAN behind fgt-managed-01, attempt https://10.20.10.10. Should fail — customer LAN has no path to mgmt VLAN.
  • From fgt-managed-02’s WAN-side console, attempt to ping the admin workstation on vmbr-mgmt. Should fail — transit-to-mgmt is permitted only for the FGFM service to host-fmg, not arbitrary hosts.
  • From the FMG itself, attempt ssh root@<lab-edge-wan-ip> on the WAN-side IP. Should fail — local-in policy on port1 denies management.
  • Disconnect vmbr-fgd from its physical NIC (Pattern A) and try to install policy. The install should still succeed (FGFM is on the management plane, not the FortiGuard plane); only FortiGuard updates should fail. This separation is what the two-NIC FMG design exists to prove.

If any of these do work, your boundary is wrong somewhere. The deny log on the lab edge is where you find it.

Step 10 — Snapshot the final state

qm snapshot 9001 fmg-multi-adom --description "FMG with two ADOMs and two managed FGTs, policies installed, revisions intact"
qm snapshot 9100 edge-with-managed --description "FGT-edge after managed FGT registration, deny log clean"
qm snapshot 9101 mgd01-policy-installed
qm snapshot 9102 mgd02-policy-installed

The four snapshots together are the “good baseline” of the lab. Any breakage from here on is recoverable in under a minute with qm rollback.

Suggested next experiments

The lab is now a platform. Things worth doing on it that are very hard to do safely in production:

  1. Forced policy install with an error. Add a policy referencing an undefined address object in FMG. The install will preview-fail. Watch how FMG reports the error and where in the GUI it surfaces.
  2. Out-of-band change on a managed FGT. SSH to fgt-managed-01 and change a firewall policy directly. FMG will detect drift on the next sync (Device Manager shows a “Modified” flag). Practise the “Retrieve Config” → “Re-import Policy” → “Re-install” cycle. This is how you handle the inevitable break-glass change in production.
  3. Script-based config push. Build a fmg-script (System Settings → Advanced → Scripts) that adds an address object to all managed FGTs in an ADOM. Run it. Look at the revision history afterwards.
  4. Firmware upgrade orchestration. Use FMG’s firmware management to upgrade fgt-managed-01 from 7.6.x to 7.6.y. The lab is the cheapest place on earth to learn how that goes wrong.
  5. Backup and disaster recovery. Take an FMG full backup (System Settings → Dashboard → System Information → Backup). Wreck the FMG VM (qm rollback 9001 fresh-build). Restore from backup. Verify the managed FGTs reconnect.
  6. HA between two FMGs. Build a second FortiManager VM (VMID 9002), pair it with the first as an HA peer. Failover. Watch what the managed FGTs do. This is the hardest one to test in production and the easiest in a lab.

Closing the series

Five posts. Start to finish:

  • Part 1 — design and sizing.
  • Part 2 — qcow2 build and first boot.
  • Part 3 — Proxmox networking.
  • Part 4 — lab edge FortiGate.
  • Part 5 — managed devices, ADOMs, policy packages.

The reason for going this deep on a “lab” is that the operational habits that matter most on FortiManager — read-the-preview, snapshot-before-install, revision-rollback as a normal workflow — only stick if you build them somewhere safe first. The lab is that place. The Proxmox host runs cold for £200 of refurbished hardware, the FortiManager runs on a 14-day trial, and the operational lessons are the same ones the £100k production deployment teaches you the hard way.

The single-line summary for Part 5: two managed FGTs in two ADOMs, one shared policy package with a one-line diff, policy installed via FMG preview, revision history exercised, deny-log clean. Snapshot it, break it, rebuild it, and the next FortiManager you touch in production will feel familiar instead of frightening.