Support multiple ports and non-HTTP services per app
Motivation
Users want to deploy non-HTTP services (e.g., an IRC server on ports 6667/6697) with multiple ports exposed. Today the app config layer only supports a single port per service, and there's no way to expose non-HTTP ports externally via node_port.
Prompted by Chad wanting to deploy his IRC server on Miren instead of managing it manually.
Current State
The lower layers already support multi-port:
- Network Service entity (
api/network/schema.yml):Portismany: true, supports TCP/UDP protocol - Sandbox container spec (
api/compute/schema.yml):Port[]array withnode_portfield - Sandbox firewall (
controllers/sandbox/firewall.go):configurePortdoes iptables DNAT for eachNodePort - Service controller (
controllers/service/service.go):setupNodePortwires nftables host→container per port
The app config layer is the bottleneck:
- App config schema (
api/core/schema.yml): Singleport: intper service — no array, nonode_port, no protocol - Deployment launcher (
controllers/deployment/launcher.go:445-490): Extracts one port per service, sets onePORTenv var - HTTP ingress: Only looks for
type: "http"port (this is fine — non-HTTP usesnode_portdirectly)
Proposed Changes
1. Extend app config schema (api/core/schema.yml)
Add a ports component array to services:
services:
attrs:
ports:
type: component
many: true
doc: TCP/UDP ports this service exposes
attrs:
port:
type: int
name:
type: string
protocol:
type: enum [tcp, udp]
type:
type: string # "http", "tcp"
node_port:
type: int
doc: Host port to expose externally (for non-HTTP services)
Keep the existing single port/port_name/port_type fields for backward compatibility — they become sugar for a single-element ports array.
2. Update deployment launcher (controllers/deployment/launcher.go)
Change port extraction (~line 445-490) from "find one port" to "collect all ports" and pass through to SandboxSpec.Container.Port[].
3. No changes needed for:
- Sandbox firewall — already iterates
Port[]and configures eachNodePort - Service controller — already handles multi-port services
- Network Service entity — already
many: true - HTTP ingress — correctly filters for
type: "http"only
Example: IRC server config
services:
- name: irc
ports:
- port: 6667
name: irc
protocol: tcp
type: tcp
node_port: 6667
- port: 6697
name: ircs
protocol: tcp
type: tcp
node_port: 6697
Scope
The core work is small — schema change + launcher update + tests. The infrastructure plumbing is already in place.