The gateway host¶
You want to know what a site’s gateway runs, which Ansible role puts each part there, and which page to use
to deploy, rebuild or certify one. Everything here is fpgas.online-infra, main, read 2026-10-07
(ansible/site.yml, ansible/web.yml, ansible/inventory/hosts, the roles’ tasks/).
Each site has one x86 gateway, and it is everything at the site that is not a Pi: it serves the boot chain, exports the NFS root, is the firewall for the Pi network, and runs the web tier. fpgas.online-infra deploys welland’s (The welland gateway). The ps1 site operator runs ps1’s own install, which fpgas.online-infra does not deploy as it stands (The ps1 gateway and switch).
The tasks¶
Deploying to a gateway: the whole playbook, and checking it after.
Checking and reconnecting:
verify-server.yml,verify-pi.yml, a reinstalled host’s new key.
Tags: there are none any more. fpgas.online-infra issue #157 removed them on 2026-10-02; a recipe with
--tagsfrom before then runs nothing it names (Deploying to a gateway).
Testing without hardware: the VM test.
Services, one by one: what each role installs and which setting matters.
Sources: the files and records these pages come from.
Hosts¶
Ansible names the gateways after their public names: inventory host fpgas.online is tweed, and
ps1.fpgas.online is the ps1 gateway.
Group |
Members |
Play |
|---|---|---|
|
|
the server plays and the NFS root update, |
|
|
the web tier, |
|
none |
USB hub power control; its only member stopped resolving in 2026-08 and was retired on 2026-09-04 |
The inventory used to have an onpi group: a host pi, reached as the piroot account on the gateway, whose
login shell chrooted into the NFS root to provision it (ansible/inventory/hosts before commit 7765f67). It
was removed on 2026-09-03 by that commit (ansible/inventory/hosts, comment, read 2026-10-07). The
operators role deletes what was left on a gateway: the account’s sudoers file (a passwordless sudo chroot,
that is, root), its login shell /usr/local/bin/chroot-shell and the account itself
(roles/operators/defaults/main.yml, operators_retired_accounts and operators_retired_files; read
2026-10-07).
The group membership is what Ansible acts on. The infra README’s roles table still describes uhubctl as a server
role (README.md, main, read 2026-10-07), and CLAUDE.md describes site.yml as running nbp/uhubctl/pig
against “the server”; with the group empty, the uhubctl role never runs on any gateway.
Note
Open, in fpgas.online-infra: the README’s roles table calls uhubctl a server role though its inventory group is
empty. The README describes the NFS root as provisioned by systemd-nspawn and qemu-user-static (lines 14-32 and
144, read 2026-10-07). The nfsroot-build.yml workflow builds it instead, from ansible/ci-nfsroot.yml. The README’s host-groups table also
lists a pi group, “nspawn chroot” (line 192), and CLAUDE.md names pi among site.yml’s host groups
(line 84); the inventory has no pi group.
What runs on the gateway¶
In the order site.yml applies the roles.
Network and logins (nbp):
apt_client, thennetif: the two NICs namedeth-localandeth-uplinkby MAC-matched systemd.linkfiles (one reboot if a NIC still has its installer name).automation_user(where enabled),operators,jump,sshd: theansibleaccount, the operators’ accounts keyed from their GitHub keys, the restrictedpijump account, and key-only SSH (Accounts and logins).lldp:lldpd, so the cabling to the switches can be read rather than assumed.firewall:nftables.service, the whole Pi isolation policy, and IPv4 and IPv6 forwarding.vlan_portsandswitch_vlans, only whereswitches:is defined (welland): one VLAN interface per switch port, and the switches’ VLANs (Converging the switches).
Boot and storage (nbp):
nfs:nfs-kernel-server, exporting the root read-only to the Pi network.apt_cache: the site’s package cache, where enabled.pxe:dnsmasq(DHCP, DNS, TFTP, withbind-dynamicand the lease file at an absolute path) andchrony(its task “Install chrony (LAN NTP server)”) (NTP for the Pis, which have no route out) (Netboot and the NFS root).
Web tier (pig, web.yml):
server_user: the account the site runs as.site: nginx, the Django site (fpgas-online-site) under gunicorn, daphne and uvicorn, redis, certbot, and the PoE control’s switch settings (Power-cycling a board).wssh: the browser terminal.stream_server: nginx-rtmp, taking the Pis’ camera streams and serving them as HLS.mqtt(wherefleet_broker),webrtc(wherewebrtc_additional_hosts),ttsite(wherett_boards: the Tiny Tapeout site, The Tiny Tapeout stack).
The NFS root update (nbp, the last play): ssh_key_fetch (the operators’ GitHub keys for the root),
nfsroot_generation (the update lock), img (the CI-built root image), apt_cache, fixpi (the site layer),
then nfsroot_generation again (publish the new generation) (Updating the NFS
root).
The Django application is The web application.