Submit an issue View all issues Source
MIR-745

Support multiple ports and non-HTTP services per app

Done public
phinze phinze Opened Mar 2, 2026 Updated Mar 3, 2026

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): Port is many: true, supports TCP/UDP protocol
  • Sandbox container spec (api/compute/schema.yml): Port[] array with node_port field
  • Sandbox firewall (controllers/sandbox/firewall.go): configurePort does iptables DNAT for each NodePort
  • Service controller (controllers/service/service.go): setupNodePort wires nftables host→container per port

The app config layer is the bottleneck:

  • App config schema (api/core/schema.yml): Single port: int per service — no array, no node_port, no protocol
  • Deployment launcher (controllers/deployment/launcher.go:445-490): Extracts one port per service, sets one PORT env var
  • HTTP ingress: Only looks for type: "http" port (this is fine — non-HTTP uses node_port directly)

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 each NodePort
  • 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.