Skip to content

ADR-0002: Host ports — arbitrary services in 2001–2100, protocol ports pinned

  • Status: Accepted
  • Date: 2026-07-14

Context

Host-published ports had accreted ad-hoc (3001, 3552, 8080, 8083, 9010, 9200, 2283, …), some colliding conceptually with the external dev projects that grab 3000–3003. We wanted a tidy, predictable scheme — but most homelab ports are protocol-standard and cannot move without breaking the clients that expect them.

Decision

  • Most services publish no host port — they're reached only through Traefik via container traefik.* labels on the proxy network. Keep it that way; a direct host port is a bypass.
  • The few services routed by Traefik file-provider entries (dynamic/*.yaml → host IP:port) do need a published port; park those arbitrary ports in a 2001–2100 block (immich 2002, adguard-web 2003, peertube 2004, ocis 2005, trmnl 2001). Skip 2049 (NFS).
  • Never renumber protocol / client-facing ports: 53 (DNS), 80/443 (HTTP), 1883 (MQTT), Frigate/go2rtc RTSP/WebRTC (8554/8555/1984/8971/5000), Moonlight UDP 40000–40100, Wyoming 10200/10300, Postgres 5432, Forgejo SSH 2222.

Consequences

  • Moving a file-routed service's port means editing both its compose.yml ports: and its dynamic/<svc>.yaml URL, then recreating.
  • Removed two vestigial direct-access ports (arcane 3552, zigbee2mqtt 8080) — Traefik reaches both via labels, so the host ports were pure bypass.
  • Off-limits ranges stay off-limits: Sunshine/Moonlight gaming 47984–48010 / 1716.
  • Map of record: docs/host-port-map.md.