TCP and UDP services
Forward anything that isn’t TLS-with-SNI. The agent declares the listen port; the edge picks it up automatically.
TOWONEL_AGENT_TCP_SERVICES='[ {"name":"forgejo-ssh", "origin":"forgejo:22", "listen_port":2222}, {"name":"prom-write", "origin":"vm:8428", "listen_port":9090}]'TOWONEL_AGENT_UDP_SERVICES='[ {"name":"dns", "origin":"127.0.0.1:5353", "listen_port":5353}, {"name":"wireguard", "origin":"10.0.0.1:51820", "listen_port":51820, "idle_timeout_secs":120}]'Datagrams are framed onto the agent↔edge QUIC tunnel (length-prefixed,
up to 64 KiB). The edge reaps a session after 60s of inactivity;
set idle_timeout_secs per service (1–3600) for flows whose keepalives
are further apart.
UDP port ranges
Section titled “UDP port ranges”Use listen_port_range ([start, end], inclusive) instead of
listen_port to claim a contiguous block. A datagram on any port in the
range is forwarded to the origin host at the same port, so origin
is host-only (no :port):
TOWONEL_AGENT_UDP_SERVICES='[ {"name":"relay", "origin":"10.0.0.5", "listen_port_range":[49160,49660], "idle_timeout_secs":600}]'The hub caps one range at TOWONEL_HUB_MAX_UDP_PORT_RANGE ports
(default 512). Ranges aren’t available when
TOWONEL_HUB_PORTS_REQUIRE_RESERVATION is on.
TURN behind towonel (coturn)
Section titled “TURN behind towonel (coturn)”Expose the control port as a single service and the relay range as a port range:
TOWONEL_AGENT_UDP_SERVICES='[ {"name":"turn", "origin":"10.0.0.5:3478", "listen_port":3478, "idle_timeout_secs":300}, {"name":"turn-relay", "origin":"10.0.0.5", "listen_port_range":[49160,49660], "idle_timeout_secs":600}]'coturn advertises the edge’s public IP (it sits behind the tunnel) and pins its relay range to what you exposed:
listening-port=3478min-port=49160max-port=49660external-ip=<edge public IP>realm=turn.example.eu- coturn sees the agent as the client source (NAT-like) — fine for credential auth, but IP-based allow/deny won’t work.
- STUN/
XOR-MAPPED-ADDRESSanswers reflect the agent’s socket, so server-reflexive (srflx) candidates are wrong — point clients at a separate STUN server. TURN relay candidates work correctly. - Keep
idle_timeout_secsat or above coturn’s allocation lifetime (~300s+) so a quiet allocation isn’t reaped between refreshes. - TCP TURN (
3478/tcp) rides the regular TCP service support.
Reconciliation
Section titled “Reconciliation”Each agent boot reconciles the hub against the agent’s env: added entries are upserted, removed entries are deleted. The env is the source of truth — run at most one agent per tenant.
Port rules
Section titled “Port rules”- Each port is unique across all tenants. Claiming a port already bound to a different service is rejected at submission time.
- TCP and UDP live in independent port namespaces —
2222/tcpand2222/udpcan coexist. - Privileged ports (
< 1024) are blocked by default. SetTOWONEL_HUB_ALLOW_PRIVILEGED_PORTS=trueon the hub to allow them. - A
listen_port_rangeclaims every port in the block; the privileged gate applies to the start and the whole range must be free.