Chapter 9
Networking & the Perimeter
See every device on your LAN, read your router's live state, and reach a service from the outside world — with or without opening a single port.
A Mac that runs services lives inside a network, and that network is where most real-world trouble starts: a router whose WAN link flapped, a forgotten device on the wrong subnet, a port you opened months ago and never closed. FrontierStack treats the network and its perimeter — the boundary between your LAN and the internet — as first-class objects. It reads your router directly, scans the LAN to build an inventory, draws a data-flow map, and gives you several disciplined ways to expose a service to the outside.
This chapter covers the network around your servers. For linking the servers themselves over SSH see Chapter 8; for the host firewall, fail2ban and the security audit see Chapter 10; and for Cloudflare DNS and TLS see Chapter 7.
9.1Routers & firewalls you can read and drive
FrontierStack talks to network gear through its own management API where one exists, and over SSH where it does not. The two tightest integrations are OPNsense (its full REST API) and Cloudflare (covered in Chapter 7); a wider set of routers and firewalls report live status. Add a device in the Router & Network pane with its address, vendor and API key, and the AI Administrator's router_info tool can then read its version and model, uptime, CPU and memory, WAN links and gateways (up or down), interfaces and client count — plus the raw API JSON for any field FrontierStack does not map. It is read-only: it queries the device's own API, never SSH.
| Device | How FrontierStack reaches it |
|---|---|
| OPNsense | Full REST API — live status, firewall rules, port-forward (rdr) for the perimeter |
| pfSense | REST via the API package |
| MikroTik RouterOS | REST API (RouterOS v7+) |
| Ubiquiti UniFi / EdgeOS | Controller / gateway API key |
| OpenWrt | LuCI / ubus API |
| DD-WRT | Web admin / SSH |
| ASUSWRT | Router web API / SSH |
| FRITZ!Box | TR-064 / web admin |
| TP-Link Omada | Controller API |
router_info still reports that it is pinned, where, and whether it is reachable — and tells you to add its API key in Router & Network to read version, gateways, WAN and interfaces live.For OPNsense and pfSense, an API key unlocks a continuous firewall monitor (the toggle in the pinned device's pane): every Alerts sweep polls the firewall itself for gateway state, interface carrier and service liveness — so a WAN line that dies while a multi-WAN router silently fails over (servers browse fine, inbound to your sites is dead) raises an alert naming the gateway and the port that lost carrier, instead of an unexplained sea of red site dots. Nothing is installed on the router: OPNsense's REST API is built in, and pfSense needs only its REST API v2 package. The same pane can also join an OPNsense router to your tailnet: sign in to Tailscale on your Mac (Google accounts work), mint a pre-auth key, paste it in the device pane's Tailscale section — FrontierStack installs the os-tailscale plugin if needed, saves the key and login server (Headscale too), and restarts the service over the API, no browser login on the router required. The tailnet address is then remembered as a fallback: when the LAN address stops answering (off-site, VPN route down, LAN leg dead), Check Status, the monitor and certificate renewal retry over Tailscale automatically and say so, and the monitor raises a separate "LAN address" alert so a routing fault is not mistaken for a dead router.
Attack and failure signals. The same sweep that watches gateways also watches for trouble on the router itself, and a router in distress turns orange with a warning triangle in the sidebar — hover for the reason. On OPNsense with the Intrusion Detection plugin enabled, FrontierStack reads its recent Suricata alerts over the same API and shows the count and top signature (an attempted attack surfaced without opening the firewall UI; pfSense's REST API does not expose IDS uniformly, so this is OPNsense-only for now). Across every monitored router — OPNsense, pfSense, OpenWrt and the rest — each sweep also flags an unexpected reboot (uptime dropped sharply: a crash, a power event, or an attack), a brute-force spike on the router's admin/SSH (repeated failed logins, with the busiest source IP named from the router's own log), resource stress (memory or load dangerously high — a DoS, a runaway or compromised process), and an available firmware update (outdated firmware means known holes). Each raises an alert; signals a given platform cannot report are simply skipped, never a false all-clear. OPNsense and OpenWrt report the most; pfSense's API is more limited.
Certificate expiry. The same sweep reads the firewall's trust store — every CA and certificate a service uses — and raises an alert a month before one expires, and again once it has. This is the failure nobody plans for: an OpenVPN server certificate issued on OPNsense's 397-day default quietly locks every remote user out a year later, and the Web GUI's own HTTPS certificate lapsing turns the admin page into a browser warning. The device pane lists them soonest-first with a coloured dot, and a Renew… button reissues a certificate in place through the router's API: same private key, subject and CA, a lifetime you choose (up to ten years), and optional restarts of the OpenVPN servers and the Web GUI so they load it. Because the key and subject are unchanged, existing VPN client profiles keep working — nothing to re-export. On pfSense the REST API's renew action does the equivalent and restarts dependent services itself, and because its API reports no expiry for certificate authorities FrontierStack reads that date out of the CA certificate itself, so a pfSense CA warns like any other. CAs cannot be renewed through either API; an expiring CA is announced early precisely because replacing it means re-signing certificates and redistributing client profiles. The OpenVPN service pane shows the same router certificates next to the CA and client certificate embedded in every .ovpn profile on the Mac (OpenVPN Connect, Tunnelblick, the last file used), so client and server expiry sit side by side; its Plan & Cost card also notes that OpenVPN itself is free and what Access Server and CloudConnexa charge.
Driving and diagnosing a router. The AI Administrator can now do more than read: reboot_router restarts an appliance the same way it reboots a server (OPNsense/pfSense via API, OpenWrt over SSH), gated behind "Allow changes"; and when a task is genuinely better done in the router's own console, the assistant offers to open its Web UI with open_web_ui, resolving the address from the device pane rather than guessing. FrontierStack itself deliberately does not edit these appliances' firewall rules — OPNsense/pfSense/OpenWrt manage rules through their own config system, so the pane and the assistant point you at the native firewall page instead (right-click a router ▸ Open firewall rules… deep-links it). Two pane conveniences round this out: a Diagnostics button runs an API-free reachability check (ping, the common admin ports 80/443/8443/53, reverse DNS, gateway) so you can triage a router even without an API key; and for a router or firewall, Discover Services offers to open the Web UI rather than port-scanning it (a scan of your own perimeter device is rarely what you want). If SSH to an OPNsense or pfSense box is refused, SSH is either disabled or — more often — only allowed on certain interfaces (commonly the LAN, not the WAN): reaching it over the LAN, e.g. through a VPN, usually works, while from outside it is typically blocked. Enable SSH and its listening interfaces in the web UI (System ▸ Settings ▸ Administration ▸ Secure Shell on OPNsense). The SSH button itself is only hidden for consumer gateways that have no admin shell at all (NTT, some TP-Link/FRITZ!Box), where the Web UI is the only way in.
9.2Firewall vitals, graphs and power
A pinned OPNsense, pfSense or OpenWrt firewall with monitoring switched on reports its own vitals through its API, and its pane now graphs them: CPU and memory on one 0–100 chart, load average, and temperature. The samples come from the monitoring poll that was already running, so the graphs cost no extra API calls and fill in as the Alerts sweep proceeds, covering roughly the last six hours of the session.
What each platform gives differs, and the pane shows only what is real: pfSense reports an instantaneous CPU percentage, while OPNsense reports load average instead. Temperature depends on the hardware exposing a sensor FreeBSD can read — many virtualised and ARM installs have none, so a missing figure means "no sensor", not a fault.
Any pinned device can also have a smart plug linked to it, exactly as servers do: On, Off, Power-cycle, and a live wattage reading where the plug meters it. This matters most for a firewall, because it is the one box you can never reach over SSH when it wedges — the network you would reach it over is the one it serves. Neither OPNsense nor pfSense reports its own power draw (FreeBSD exposes thermal sensors, not watts), so a metered plug is the only real power figure available for one. Power-cycling asks for confirmation and warns that every connection through the firewall drops; try the API reboot first.
9.3Device Discovery: an inventory of your LAN
Open Device Discovery and press Find Monitors (or pick a subnet first). FrontierStack sweeps the chosen /24 using every method available at once, so routers, access points, switches, NAS boxes (Synology, QNAP, ZimaCube/ZimaOS…), printers, cameras and other servers all surface:
- Ping / ARP — an ICMP sweep, with ARP/MAC giving each host's vendor; turn on TCP Probe to find hosts that filter ICMP.
- Bonjour (mDNS) and SSDP / UPnP — advertised services and their friendly names.
- SNMP and LLDP / CDP — add model, port and neighbour details when
net-snmpandlldpdare installed (buttons in the pane install them). - Windows service ports — a machine that filters ICMP is still found by probing its distinctive ports (RDP, WinRM, SMB and friends), so Windows PCs no longer hide from the sweep.
The scan also notes how each host can be reached. An AnyDesk badge appears when AnyDesk is running locally or answering on its default port 7070, and a Tailscale badge — green when the peer is online — is built from this Mac's own tailscale status, matching mesh peers to discovered devices (only endpoints, hostnames and OS are kept; login names are never retained). On a directly-connected LAN, the Macs and devices macOS already knows through Bonjour appear before the slower IP sweep, so the list fills in quickly. A device's detail view carries matching AnyDesk and Tailscale rows with an Open app shortcut.
The AI Administrator's discover_devices tool runs the same scan and auto-pins the devices whose type it can identify confidently. Anything ambiguous is listed back rather than guessed at, so the assistant can ask you what it is and then pin it with pin_device. A pinned (monitored) device appears in its type's sidebar section; double-click it to open its pane, or use Open Web UI, Discover Services, Reclassify or Remove from its row. If you already know an address, the Add a device by IP field probes and pins it directly — no full scan needed.
9.4Cameras from every maker
The Cameras pane is one status board for every camera FrontierStack knows about, whether or not it can show a picture. It gathers cameras found by Device Discovery (pinned, and found but not yet pinned), AV Feeds streams, SwitchBot cameras, Smart Life cameras and UniFi Protect cameras. With dozens of cameras, the counts at the top and the Offline filter are the quick answer: offline cameras sort first, and a stream whose address matches a pinned camera is shown on that camera's tile rather than twice. A Protect camera with the same MAC address as a pinned camera is shown on that camera's tile. The bell on each tile switches its offline alert, and Alert on All covers every camera that can be checked at once. Alerts go through the Alerts pane, so a contacts preset can page the technician for the site.
A camera counts as alive if it answers on RTSP (port 554), its web port (80) or ONVIF (2020). Cloud-only cameras such as Ring, Nest, Blink and Arlo show no status, because only their own app can reach them.
Tapo cameras from anywhere (unofficial). In Services ▸ Cameras ▸ Tapo Cameras, sign in with your TP-Link ID to see each Tapo camera's online / offline state even when the Mac is away from home, with offline alerts through Alerts. FrontierStack signs in the way the Tapo Android app does, because TP-Link offers no official API — so it can break when TP-Link changes its app, and using it may be against TP-Link's terms. Only status is read. Your password is never stored, a camera counts as offline only after two checks in a row, and if TP-Link's cloud can't be reached the camera shows Status unavailable, never offline. Pinned Tapo cameras keep a green dot off-LAN while the cloud says they are online; other Tapo devices and, with a second sign-in, Kasa devices can be watched too.
SD cards. For Tapo, Hikvision/Annke, Dahua/Amcrest/Lorex, Reolink and Axis cameras, each tile also shows the memory card as the camera itself reports it: SD ✓ 42% used, No SD card, Unformatted, SD card error, or SD — when it isn't known (hover for the reason). FrontierStack asks the camera's own local API, never a cloud, and only while the Mac is on the camera's network; away from it, the last result stays with its time. Checks run every 30 minutes, one camera at a time and at most once per 10 minutes per camera. Non-Tapo cameras use the login from their AV Feeds stream or one you enter in the camera's device pane. Tapo cameras need admin and your TP-Link account password, entered once under Tapo Cameras ▸ Local camera access; it stays in the Keychain and is never sent to TP-Link's cloud. If a camera refuses a login, FrontierStack stops asking it until you fix the login or press Retry, because cameras lock accounts after repeated failures. A camera that can't be reached or signed in to is never reported as having no card. SD alerts are opt-in; nearly full alerts are off by default because most cameras loop-record and are always close to full. eufy, WTW and Eseecloud cameras have no local storage API.
What each make needs:
| Make | What works | How to set it up |
|---|---|---|
| Anker eufy | RTSP on many models; no ONVIF and no public API | In the eufy Security app: camera ▸ Settings ▸ Storage ▸ NAS (RTSP). Set the username and password there (they are random by default) and copy the link, usually rtsp://user:pass@ip:554/live0. Choose Continuous recording: in Event mode, and on battery cameras, the stream exists only during an event, so an offline alert would be false. At most four viewers at once. |
| WTW (塚本無線) | RTSP and ONVIF on the PoE/IP line; nothing on the EAGLE Wi-Fi line | See below. |
| Eseecloud (EseeCloud / IP Pro apps) | RTSP on recorders, on the web port 80 | Turn on the RTSP server in the recorder's own Network menu, then use rtsp://user:pass@nvr-ip:80/ch0_0.264. Channels count from zero (ch0 is camera 1), and _1 is the sub stream. Many stand-alone Eseecloud Wi-Fi cameras have no RTSP at all. The default login is admin with a blank password. |
9.14.1WTW cameras and recorders
Older IP cameras. WTW's own 2018 IP camera manual gives rtsp://ip:554/live/0/main for the main stream and /live/0/sub for the sub stream. Port 554 is the default and can be changed. RTSP is turned on in the camera's web network settings. Current PoE/IP models and NV4-series recorders list RTSP and ONVIF in their specifications. If the path above doesn't connect, add the camera over ONVIF in an NVR app to find its URL.
EAGLE Wi-Fi line. These have no RTSP and no ONVIF. WTW's support site says so for one camera, and the recorder specification lists only TCP/IP, DHCP and P2P. For these, the most you can do is check that the recorder answers on its web port: pin it in Device Discovery as WTW Camera / NVR and turn on its offline alert.
Default passwords. NV4 recorders use 00000000, which becomes wtwjapan after a factory reset. Older cameras use admin with a blank password, or admin/admin. Change them before the device goes on your network.
9.14.2Smart-home clouds
Smart Life (Tuya) devices are read through Tuya's official Cloud API. Create a Cloud project at iot.tuya.com in your account's data center (Japanese accounts use Western America), link your Smart Life account with Devices ▸ Link Tuya App Account, and paste the project's Access ID and Secret into the Smart Life pane. You then see every device's online state and plug power, can switch plugs and lights, and can have any device alert when it goes offline. The free trial allows about 26,000 calls a month and must be extended every few months, so FrontierStack checks every 10 minutes.
Minut sensors report noise, occupancy, temperature and humidity in rentals. The Minut pane alerts when a sensor goes offline, when its battery runs low, and when a home has a noise disturbance in progress. Minut opens its API only to accounts it has approved; its help article ties this to the Enterprise plan.
SmartThings, Govee, LIFX, Sensibo and Nuki each have their own pane that lists the account's devices with a status dot: green online, red offline, grey when the cloud didn't say. Turn on the bell next to a device, or Alert on all, to get an alert when it goes offline. Govee, LIFX, Sensibo and Nuki need only an API key or token from the vendor's app or website. For SmartThings, create your own OAuth app once with the SmartThings CLI so sign-in keeps working. A personal access token also works, but it expires after 24 hours. If a key is rejected or a sign-in expires, you get one account alert. If a cloud can't be reached, its devices are left unknown. Neither case is reported as devices going offline. Nuki locks are worth watching in rentals: a lock that has lost its connection can't be opened remotely for guests.
9.5The Data Map
The Data Map pane draws a per-location data-flow diagram: where your data lives and how it moves across the devices and services at one site. FrontierStack serialises the location's inventory — the discovered devices, their roles, and (optionally) scanned ports — scrubs it of secrets, and hands it to your subscription Claude through the local claude CLI (not the metered API the in-app harness uses). The reply comes back as a Mermaid flowchart plus a short narrative, rendered offline in the pane; the last diagram for each location is kept, and you can save it to your Obsidian vault as a runbook. Locations themselves are explained in Chapter 8.
9.6Opening a port: UPnP and NAT-PMP/PCP
To reach a service from the internet the classic way, a port on the router has to forward to your Mac. Rather than make you log into the router by hand, FrontierStack can ask the router for a mapping using the standard protocols it advertises:
- UPnP IGD (via
miniupnpc) — the common consumer-router method. - NAT-PMP / PCP (via
libnatpmp) — Apple's and the modern equivalent. - OPNsense — a perimeter rule and port-forward through its API directly.
These tools are installed on demand the first time you use them. A mapping made for a temporary session (see Debug Share) is torn down automatically when the session ends.
9.7Dynamic DNS: following a changing IP
Home and small-office connections rarely have a static IP, so a hostname you point at today's address goes stale tomorrow. The Dynamic DNS pane keeps a hostname tracking your current public IP. Add an entry with a Name, a Hostname (for example myhost.duckdns.org) and the account data for your provider; press Update Now to publish immediately, or turn on Update automatically. You choose whether the updater runs only while FrontierStack is running or permanently as a system service, so the record stays current even when the app is closed. Cloudflare users get a tighter path: a Cloudflare DDNS A record that follows your public IP, driven by the same Cloudflare integration as Chapter 7; a generic interval-based updater covers other providers via an update URL.
9.8Tunnels and mesh: reaching in without opening up
The better way to reach a service from outside is to skip inbound ports entirely. A tunnel makes an outbound connection that an outside endpoint rides back in on, traversing NAT with nothing forwarded:
- Cloudflare Tunnel — a Quick Tunnel gives you a public
*.trycloudflare.comURL with no account, or a named tunnel for a permanent hostname. - Tailscale — Serve keeps a service private inside your tailnet; Funnel publishes it to the internet through your Tailscale node.
For ongoing connectivity between machines, a mesh or VPN network gives every node a stable private address wherever it roams. FrontierStack manages the common ones — by API on a router that supports it (OPNsense), or over SSH on a server:
| Network | What it is |
|---|---|
| WireGuard | Modern, fast kernel VPN tunnels — the base layer most of the rest build on |
| Tailscale | WireGuard mesh with exit nodes and subnet routers, set up over SSH or the OPNsense API; the VPN pane can also bring Tailscale up automatically at every FrontierStack launch, so router fallback addresses and tailnet monitors work from the first sweep |
| Headscale | Self-hosted, open-source Tailscale control server |
| NetBird | Open-source zero-trust networking, self-hostable |
| Nebula | Lightweight overlay mesh (Slack / Defined Networking) |
| ZeroTier | Zero-trust SD-WAN / virtual networks — agent plus API |
9.14.3Tailnet: the whole-network view of Tailscale
The per-server Tailscale controls live inside each server's own pane and work over SSH: they answer “is the daemon up on this box”. The Tailnet pane answers the questions that span the whole network, which only Tailscale's own API can: paste an API access token (device read is enough — the pane never writes) and it lists every device with its addresses, OS, client version, owner, tags and last-seen time.
What earns the pane its place is the Needs attention list. It surfaces node keys that are about to expire — a scheduled outage, because when a key lapses the device silently drops off the tailnet until somebody re-authenticates it — devices waiting for approval, devices advertising routes nobody approved (the usual reason a subnet is unreachable even though the node is plainly up), and devices that stopped checking in weeks ago. Key expiry and pending approvals also raise Alerts.
9.14.4Running your own ZeroTier controller
ZeroTier's client is only the member side; networks are normally administered at my.zerotier.com. But every zerotier-one install can also be the controller for its own networks — fully self-hosted, no third party holding your membership list — and that path ships with no local administration UI at all. The ZeroTier Controller pane is that missing interface.
It shows the controller's identity and the networks it owns, and works the member-authorisation queue with one-click authorise/deauthorise. Members authorised but unseen for a fortnight are flagged, because an unused grant is a standing hole in the network. You can edit a network's name, privacy, routes and IP assignment pool, and write flow rules in ZeroTier's own rules language — compiled locally as you type, with templates for the common cases and a warning before you save a rule set that would lock everybody out.
Everything runs over SSH against the controller's own loopback API. The controller listens on 127.0.0.1:9993 and authenticates from a root-readable token, so FrontierStack never needs — and actively discourages — a publicly reachable controller API; the built-in audit flags it if one has been exposed anyway, along with loose file permissions and a missing backup. There is also a Prometheus export, a warm-standby backup/restore, and an assistant for migrating networks out of ZeroTier Central.
identity.secret irreplaceable: lose it and every network ID it owns is orphaned. Back it up encrypted, off the box.9.9UniFi: Cloud Gateways, Dream Machines and Superlink
Ubiquiti's consoles get their own pane, because a UniFi gateway is doing more than a generic router probe can see. It covers the console families alike — a Dream Machine (UDM, UDM Pro, UDM SE), a Cloud Gateway (UCG-Ultra, UCG-Max, UXG), a Superlink gateway, a Cloud Key or a self-hosted controller. The UniFi pane speaks both of Ubiquiti's APIs, and they answer different questions. A Site Manager key — one key, created at unifi.ui.com — lists every console on your account with its model, firmware and online state. That is the only way to learn a remote site has lost power or its internet connection, because a console that is off the network cannot tell you anything locally. A local console key, created on the console itself under Settings ▸ Admins & Users, unlocks what the gateway is doing right now.
Locally the pane shows WAN links with their ISP, latency and throughput, and marks which link is actually carrying traffic. That last detail matters: when a primary line drops, UniFi fails over silently to the backup, which is usually slower and often metered, and the normal way people discover this is the following month's bill. It also lists adopted devices and their firmware, firewall rules in the order the gateway evaluates them, the client list, and every port forward. Each enabled forward is a deliberate hole through the firewall, so the pane flags the ones that accept connections from any source address — correct for a public web server, worth a second look for anything else.
Alerts cover a console dropping offline, a WAN link going down, running on the backup link, a device leaving the network, and internet-exposed port forwards. The pane is deliberately read-only: rule and network changes stay in the UniFi console, where their validation lives. PoE switch ports are handled in the next section, and plain console reachability still appears in Router & Network alongside the other vendors.
The Site Manager key also lists UniFi Protect cameras and doorbells, read at most every five minutes. Tick Alert on a camera, or Alert on all Protect cameras, for offline alerts. A camera that is updating, or whose console is itself offline, is shown as unknown rather than down.
9.10Power over Ethernet: the power button for devices that have none
Access points, cameras, door controllers and desk phones have no power switch. Their only supply is the switch port they are plugged into, which means the recovery move for a wedged one — power-cycle it — normally involves a vendor web UI, or a walk to the cabinet.
The Power over Ethernet pane makes the port the button. Add a managed switch by IP and you get, per port: its PoE state (delivering power, searching, fault), powered-device class, priority and wattage where the switch reports it — plus power off/on and a proper power cycle. It also shows the switch's power budget: total watts, watts in use, and a warning when you cross the switch's own usage threshold, past which it starts shedding low priority ports — so port priority is editable here too.
This works broadly because PoE is standardised: RFC 3621's POWER-ETHERNET-MIB is implemented by essentially every managed PoE switch — Cisco, Aruba/HPE, Netgear, TP-Link/Omada, Ubiquiti, MikroTik, D-Link, Zyxel. Reading uses the SNMPv2c or SNMPv3 profile from Device Discovery. With SNMPv2c, switching a port needs a separate read-write community, added per switch and kept in your Keychain. With SNMPv3, it uses the authenticated profile only when that user has write permission on the switch. Cutting power deserves deliberate access and confirmation; FrontierStack does not expose arbitrary OID writes. With Monitor on, a port in fault state or a switch over its power budget raises an Alert — both otherwise stay invisible until someone notices a camera has gone dark.
9.11Internet Health and speed tests
The Internet Health pane is your view of the link itself. It continuously pings a list of Targets — Cloudflare's 1.1.1.1, Google and Quad9 DNS, two AWS regions and Tailscale's coordination server by default — showing latency and packet loss and re-testing every 30 seconds; hosts that block ICMP fall back to a TCP-connect latency on :443. The gear button in the Internet section's header opens the target-editing dialog — set the list up once and it stays out of the way. The same section carries an IPv6 verdict: each sweep checks whether a global IPv6 address is assigned, whether IPv6 traffic actually works (ping to Cloudflare/Google v6 anycast), and whether the network's advertised IPv6 DNS servers answer. The state it warns about loudest is advertised-but-broken IPv6 — the router hands out an address and an IPv6 DNS server, connections try IPv6 first, and everything stalls until IPv4 fallback; the pane says so in plain words, names the dead DNS server, and points at the router. The AI Administrator can run the same diagnosis with internet_speed (check=ipv6) and dig deeper with ping6/dig/scutil through its diagnose tool. The sidebar's Internet Health row carries a status dot fed by a light background sweep (at launch, then every 5 minutes): green when healthy, orange for broken IPv6 or heavy packet loss, red when every target is unreachable. Live Traffic graphs real-time throughput across every active interface; Addresses & Networks lists each interface, its subnet (a network you can reach directly) and the gateway. A built-in traceroute shows the ISP and transit providers your traffic crosses. Press Test Now in the Speed Test section — or ask the AI with internet_speed — to measure download, upload, latency and responsiveness, using the Ookla speedtest CLI if installed and Apple's networkQuality otherwise. While it runs, two speedtest.net-style dials show the download and upload live — needle, phase and the current Mbps — fed by Ookla's streaming output (the built-in networkQuality reports only at the end, so its dials wait), and the pane names the test server it connected to (provider and city), during the run and in the result. A test that fails now says why instead of ending silently. A Mac on Wi-Fi, though, measures its Wi-Fi as much as its ISP — so the same section can run the test from your router or a wired server instead: pick it under From Router / Server and FrontierStack runs the probe on that device over SSH (key authentication; routers as root), preferring an installed Ookla/speedtest-cli and falling back to a curl single-stream estimate. If the router measures much faster than the Mac, your bottleneck is the wireless hop, not the line — and the AI can do the same comparison via internet_speed with a source.
9.12Network Path: switches, hubs and hop-by-hop latency
The Network Path pane answers the physical question the IP tools cannot: which boxes does this connection actually cross, and which one slows it down? LAN Path reads your managed switches' bridge tables and LLDP neighbours over SNMP and draws the chain between this Mac and any LAN device — each link labelled with its port and speed, the slowest link flagged, and a dashed inferred box drawn where several devices share one switch port (the classic hidden unmanaged switch or hub, which cannot be queried directly). Locate a Device tracks one machine down: IP, MAC, maker (from the MAC prefix), type — and the exact switch port it is plugged into. Visual Traceroute charts each hop's round-trip time and highlights the hop that adds the most latency, so “is it my Wi-Fi, the ISP's first mile, or further out?” becomes a picture. Reading the switches uses the SNMPv2c or SNMPv3 profile set in Device Discovery; unmanaged gear stays invisible by nature, which is exactly what the inference is for. The pane fills itself in: on open it automatically maps the devices between this Mac and the router (and Map Mac → Router re-runs it). Device Link Speeds goes wider still — it surveys the negotiated Ethernet port speed of every known device from its switch port (both ends of a link negotiate the same rate), slowest and half-duplex links first: a NAS stuck at 100 Mbps on a gigabit network is usually a bad cable, an old unmanaged switch, or a mis-negotiating NIC, and this is where it shows up. Locate a Device also asks the device itself over SNMP what its ports negotiate, when it runs an agent.
9.13Debug Share: expose a localhost server, briefly
When you need to show a colleague or a phone a dev server running on localhost, the Debug Share pane exposes it for a session and then closes itself. Enter the port (or press Scan localhost to find a running server), choose how to Expose via, set an Auto-close time, and press Open debug session. Every share also closes automatically when FrontierStack quits.
| Method | Reach |
|---|---|
| Cloudflare Quick Tunnel | Public *.trycloudflare.com URL, no account — ideal for a quick client or phone preview |
| Tailscale Serve | Private — reachable only inside your tailnet |
| Tailscale Funnel | Public, through your Tailscale node (Funnel must be enabled in the tailnet) |
| LAN forwarder | A 0.0.0.0:<auto> → 127.0.0.1:port bridge so other machines on this LAN can reach a loopback-only server |
The LAN forwarder has two extras. If the host firewall is on, the pane shows Open port in firewall to allow that port in the pf rules just for the session. And an Outside access picker can map a WAN port via UPnP, NAT-PMP or the OPNsense API and pair it with a DDNS host, so a LAN share becomes reachable from the public internet — the mapping is removed when the share closes. The AI Administrator can open, list and close sessions too (debug_share_open / _list / _close), including over MCP when "Allow changes" is on.
A Debug Share session is meant to be brief. To keep your own dev server reachable from your tailnet with no timer, turn on Also serve on Tailscale for it in the Localhost pane (Chapter 4): it answers on this Mac’s Tailscale address on the same port, stays off the LAN, and closes when the server stops. The AI Administrator can start a folder that way with debug_share action serve and report the address to open.
9.14Named tunnels: a permanent public hostname
A Quick Tunnel is deliberately throwaway. When you want a service on this Mac to be reachable permanently at a real address — a self-hosted app, an internal dashboard, a webhook receiver — use a named tunnel instead. It gives the service a stable hostname on one of your own Cloudflare zones (say app.example.com), survives reboots, and — like every tunnel — opens no inbound port: the Mac dials out to Cloudflare's edge, so there is nothing to forward and nothing for a port scan to find.
Create one in the Cloudflare pane's Named Tunnels section: New Tunnel…, then a hostname under one of your zones and the local port it fronts. FrontierStack drives the whole setup through the Cloudflare API using the token you already hold — it creates the tunnel, writes its ingress rule (hostname → http://localhost:PORT), adds a proxied CNAME pointing the hostname at <id>.cfargotunnel.com, and then installs the persistent daemon with cloudflared service install. That last step needs a one-time admin prompt (it writes a LaunchDaemon under /Library); cloudflared itself is fetched from Homebrew on first use. Untick Run on this Mac now if you only want the tunnel and DNS created, to run cloudflared on some other host. Delete unwinds all of it — daemon, DNS record and the account-side tunnel. The AI Administrator has the same three verbs (tunnel_create / tunnel_list / tunnel_delete), with creating one gated behind a red confirmation because it publishes a service to the internet.
cloudflared service install runs a single system daemon per Mac, so one named tunnel runs locally at a time. You can still create and route additional named tunnels through the app and run their cloudflared connectors on other machines — the account, the hostname and the DNS are all set up either way.FrontierStack User Manual · Version 1.0.0 · Chapter 9