0054. Apps get TCP and UDP ports through the agent, closed until an allow list opens them
Status: accepted, 2026-10-30. Refines 0015: containers still publish nothing.
Context
apps served HTTP only. A game server, a message broker or a database that people need from outside its node's team
network ran outside xvii with a port Docker published, or behind a forward someone made by hand. ADR 0015 forbids
containers publishing host ports, which keeps one team's container from taking a port on a shared node or reaching
past the platform. The owner decided TCP and UDP ports for apps, and private connections to databases from a laptop or
a phone, through the node and with allow lists.
Decision
- An app declares ports — protocol, its container's port, a public port, an allow list — and the agent on its node
listens on the node's addresses and passes connections and datagrams to the container in its team network.
Containers still publish nothing.
- Closed until allowed: a port with no allow entry in force isn't listened on. Entries may end — an opening for a
person's current address lasts from 15 minutes to 8 hours — and the agent ends them on time without the control
plane.
- Where: public ports come from the node's range (20000–29999 by default) unless its manager allows any port from
1024; never one below 1024 or one the platform uses. A node appsd can't reach has its TCP ports taken by the control
plane and relayed over its own connection (0051);
UDP needs a node that can be reached.
- Databases have no public port by default. A person reaches one from a laptop through the API, a connection over
their own sign-in (0052), and from a phone
through an opening for the phone's address, with TLS ended by the agent; or runs the engine's client in a terminal.
- An app may learn its clients' addresses through the PROXY protocol when it asks for it.
Consequences
- A node's address and port range become part of some apps' addresses; firewalls on nodes stay their managers', and
xvii says which ports to open.
- While a port is open, scanners see it: the agent closes connections from other addresses without a byte; kernel
filtering may come later.
- Relayed TCP costs the control plane's bandwidth: it is meant for small things.
- Self-signed TLS on ports stops eavesdropping; pinning its fingerprint, or a public certificate later, stops more.
- Teams' ports count against
apps.ports.
- Design:
superpowers/specs/2026-10-30-apps-operations-design.md in this repository.