Ports and listeners#
A router's attack surface is the list of things listening on it, so this is that list, for a box that has just finished the interactive install with the firewall box left checked. Two of the rows need saying out loud: the agent binds every interface, including the WAN, and the router's own API is pinned to loopback where only the agent can reach it.
After an interactive install#
| Port | Service | Bound to | Reachable from |
|---|---|---|---|
| 8443/tcp | The Wheelhouse agent: web UI and HTTP API | 0.0.0.0 — every interface, including the WAN | whatever the firewall lets through |
| 443/tcp | The router's own HTTPS and REST API | 127.0.0.1 only | the agent, and root on the box |
| 53/udp, 53/tcp | The DNS forwarder | the LAN address | the LAN subnet only (allow-from) |
| 67/udp | The DHCP server | the LAN interface | the LAN |
| 123/udp | NTP, client and server | — | loopback, link-local and the RFC 1918 ranges (allow-client) |
| 22/tcp | SSH | not configured | nothing |
SSH is genuinely absent: neither the image's default configuration nor the installer
writes service ssh, so a freshly installed router has no SSH at all and the console is
the only shell. Every remote procedure in this documentation that uses ssh needs you
to turn it on first.
show configuration commands | match 'service ssh'8443, and what keeps it off the internet#
The shipped systemd unit passes --addr 0.0.0.0:8443 and --tls-self-signed.
Nothing but the firewall keeps the management UI off the internet. The installer's
firewall writes a default-drop input filter for both address families that accepts from
the LAN, from loopback, ICMP, the DHCP or DHCPv6 client port on the WAN, and from a
management prefix if you named one — and nothing else. It does not open 8443 from the
WAN.
An empty answer to this, on a box with a WAN, is an emergency rather than a preference:
show configuration commands | match firewallThe certificate is self-signed unless you supply one. The agent logs a warning at start
if it is serving on a non-loopback address with no certificate at all, naming the three
fixes: --tls-cert/--tls-key, --tls-self-signed, or a TLS proxy in front.
443, and why it is loopback#
wheelhouse-firstboot.service mints a random 40-character API key for the agent,
enables the REST endpoints, and commits set service https listen-address 127.0.0.1.
The router's own API stops being a network service; the agent is the management surface.
See What first boot does.
The developer install#
install/install.sh binds 127.0.0.1:8090 by default (BIND_ADDR, or --bind-addr),
with no TLS unless you configure a certificate. It is the lab path, not the product —
if a document's address does not answer, this is usually why. Appliance is 8443,
developer install is 8090.
The agent's own default#
With no flags at all, --addr is 127.0.0.1:8090. Only the shipped unit moves it to
0.0.0.0:8443. Running the binary by hand therefore listens on loopback until you say
otherwise, which is the right default for a program that can reconfigure a router.
What the agent connects out to#
| Destination | When | Why |
|---|---|---|
--api-url, https://127.0.0.1 by default | constantly | Every read and every commit. |
--license-server, https://license.rhymelikedi.me by default | 20 s after start, then daily; hourly after a failure | Licence refresh. --license-server '' disables it entirely and the agent runs on the offline path. |
--oidc-issuer | only when single sign-on is configured | Discovery, and the token exchange on each sign-on. |
| An app's address and port | when an installed app declares a health probe | A TCP connect, plus one HTTP GET if the catalogue entry gives a path. Never an app-specific API call. |
The routers in --fleet-config | when fleet mode is on | Concurrent health, version and configuration reads. |
Nothing else. The agent does not phone home, does not fetch an update index, and does not report telemetry — nothing in it reads the release channel.
Container image pulls go out from the router, not from the agent: POST /api/apps/pull
asks the router's API to pull, and the router's container runtime does the fetching.
App ports#
An installed app's ports come from its catalogue entry and from what you chose at
install. Container apps get an address on the container network — 10.99.0.0/24 by
default, declared as network: apps in the catalogue — and are reachable from the
router; a host_network app binds the router's own interfaces directly, which is why
the install plan warns about it in those words. Per-app ports are on
The catalogue.
Checking a running box#
# From the console:
sudo ss -tulpen | grep -v 127.0.0.1
# Or from the agent, which reports the same thing the router sees:
curl -sk "$R/api/services" -H "Authorization: Bearer $T"See also#
- What first boot does — where the loopback binding comes from.
- systemd units — the unit that passes
--addr. - Every flag —
--addr,--tls-*,--trust-proxy. - Files and directories — where the certificate and the API key live.
- The catalogue — per-app ports.
- Default drop — the ruleset that keeps 8443 off the WAN.
- Harden a router
Checked against#
packaging/wheelhouse-agent.service,
packaging/firstboot.sh,
packaging/wheelhouse-install,
packaging/iso/wheelhouse.toml,
agent/main.go (registerFlags, runDaemon, isLoopback),
agent/license.go (runLicenseRefresher),
agent/catalog.go (probeApp),
agent/catalog.json,
install/install.sh,
docs/security.md "The default posture",
docs/deploy.md.