Endpoints configuration¶
Paths in the tables are relative to [endpoints]. Check parsing and
cross-field rules with gdsgate doctor --config <PATH> --json. See the
multi-node cluster guide.
Listener ports¶
| Port | Key | Listener | Purpose | Who dials | Exposed |
|---|---|---|---|---|---|
| 50050 | authority_enroll |
Authority | node registration with a one-time token; cleartext in dev, TLS from [authority].enroll_cert_file required in pilot/production |
nodes enrolling directly (the Proxy's own bootstrap, direct connectors, agent hosts); the Proxy forwarding public_join or the join relay |
internal network only |
| 50051 | authority |
Authority | control plane, mutual TLS | the Proxy; connectors, per route; agent hosts, always direct | internal network only |
| 50061 | proxy_public |
Proxy | clients; with public_join (written by setup prepare) also connector registration and renewal |
users, tunneled connectors |
yes |
| 50062 | proxy_internal |
Proxy | connector reverse tunnels | all connectors; agent hosts | yes |
| 50063 | proxy_ws |
Proxy | reverse tunnels over WebSocket; a connector tries this only after a gRPC attempt on proxy_internal fails, such as behind a corporate proxy that blocks it |
connectors, agent hosts | yes |
| 50064 | proxy_join |
Proxy, off unless set | join relay: registration and renewal for a tunneled connector with no reverse tunnel yet, typically a gateway with no DNS name |
connectors of an IP-only gateway | only when on |
| 9090/9091 | [telemetry].metrics_listen |
each role | /metrics, /healthz, /readyz; off by default |
monitoring | loopback by convention, not enforced |
[endpoints]¶
Used by: Authority, Proxy, Connector, Client. Each reads only the fields it
needs: Client only proxy_public, Authority only its own listeners.
Each value is host:port: the bind address on the service that owns the
listener and the dial address on its peers. Bind 0.0.0.0 in containers; dial
by service name or DNS.
| Key | Type | Default | Purpose |
|---|---|---|---|
authority |
optional string | 127.0.0.1:50051 when unset |
Authority gRPC control plane (mutual TLS once the cluster is registered). The Proxy dials this; a connector dials it for two-layer SSH-forward decisions and for downstream-cert issuance; an agent host dials it directly, with no route choice. |
authority_failover |
array of strings | [] |
Additional Authority endpoints for HA. The Proxy's connection pool follows the audit write-leader across these. |
authority_enroll_failover |
array of strings | [] |
Other private registration listeners, tried before dispatch by Proxy join and initial Proxy enrollment. Each uses the same TLS trust and verification name. |
authority_enroll |
string | 127.0.0.1:50050 |
Authority's registration listener. New nodes register here with a one-time token; cleartext in dev, TLS from [authority].enroll_cert_file required in pilot/production. |
proxy_public |
string | 127.0.0.1:50061 |
Public, client-facing Proxy listener. |
proxy_internal |
string | 127.0.0.1:50062 |
Connector-facing reverse-tunnel listener. |
proxy_ws |
string | 127.0.0.1:50063 |
Connector-facing WebSocket fallback listener. |
proxy_join |
string | empty, listener off | Proxy listener that relays node registration and token-less renewal to Authority. |
[endpoints]
authority = "auth:50051"
authority_failover = ["auth-2:50051", "auth-3:50051"]
authority_enroll = "auth:50050"
proxy_public = "0.0.0.0:50061"
proxy_internal = "0.0.0.0:50062"
proxy_ws = "0.0.0.0:50063"
proxy_join = "0.0.0.0:50064"
With authority unset, a connector running
authority_transport = "fronted" derives the Authority
address from proxy_internal and needs only one address.
proxy_join: the join relay¶
A connector with authority_transport = "tunneled"
never dials Authority, and it registers and renews before it has a tunnel.
proxy_join is a Proxy listener that relays both to Authority. It is the bind
address on the Proxy and the dial address on the node. The alternative is
[proxy].public_join on the client-facing port; both
can run together. gdsgate setup prepare writes public_join by default and
binds this relay in its place with --join-relay, for a gateway reached by IP
address alone.
The relay routes on the first bytes of each connection:
| First bytes | Server name | Destination |
|---|---|---|
| TLS handshake (renewal, administration) | gdsgate.internal or another *.gdsgate.internal name |
authority |
| TLS handshake (registration) | enroll.gdsgate.internal, sent by a node registering at an IP address |
authority_enroll |
| TLS handshake (registration) | any other name | authority_enroll |
| TLS handshake | none | authority |
| HTTP/2 cleartext preface (registration) | - | authority_enroll |
| anything else | - | connection closed |
TLS is not terminated; Authority checks the node's certificate as on a direct
connection. Whether a relayed registration is encrypted depends on Authority's
registration listener (see [authority]). Without a
certificate there, provision tokens cross this address in cleartext.
gdsgate doctor reports the relay, its limits, and whether registration is
encrypted.
Join relay and HA
Every Authority instance serves registration and renewal, the audit write
leader or not. A connection for authority goes to the next
authority_failover address when the previous one refuses it.
Registration tries authority_enroll and authority_enroll_failover before
sending a request. A dispatched RPC is never replayed on another instance:
a lost response can mean the one-time token was already spent.
See Authority HA routing.
Join relay exposure
The listener accepts connections without mutual TLS or a token. Expose it only where nodes join. Destinations come only from the Proxy configuration. Built-in limits:
| Limit | Default | Key |
|---|---|---|
| accepts per second per source IP | 5 | join_accept_rate_per_ip |
| accept burst | 10 | join_accept_burst |
| concurrent joins | 64 | join_max_connections |
| silence before the first bytes | 5 s | join_peek_timeout_secs |
| idle relay | 30 s | join_idle_timeout_secs |
The keys are in [proxy]. An omitted key keeps the
default; 0 means unlimited. [proxy].single_port does
not include this listener.
What Authority tells a joining node¶
Authority answers a registration and each token-less renewal with the node's identity and these settings:
| Advertised | From |
|---|---|
| the reverse-tunnel address a connector serves through | proxy_internal |
| the WebSocket fallback address | proxy_ws |
the route to Authority this cluster runs (direct / fronted / tunneled) |
[connector].authority_transport on Authority's file |
| Authority's control-plane address, on the two routes that dial it | authority |
| where to renew, as a URL with its scheme | authority, proxy_join, or proxy_public, by route; see below |
| the name this cluster answers to on a shared front, where it stands behind one | [transport].front_sni |
This information is sent only after a provision token is spent. The node's own
[enroll] and [endpoints] still apply. The single installation command uses
these values to configure the node.
A wildcard bind address such as 0.0.0.0:50062 is not advertised; the node
reports that it received no address. The renewal address is advertised as a URL
with its scheme, and the scheme decides whether renewal uses mutual TLS. A node
that cannot use the URL it receives refuses it and logs the value.
The renewal address by route:
| Route | Renewal address |
|---|---|
direct, fronted |
authority |
tunneled with proxy_join set |
proxy_join |
tunneled with [proxy].public_join and no proxy_join |
single_port if set, else proxy_public |
Authority logs at start-up what it will advertise, and warns when its
[endpoints] give nothing to advertise.
Split deployments must declare the Proxy's addresses
When Authority and the Proxy use separate files, put the Proxy's addresses,
[proxy].public_join and [connector].authority_transport in Authority's
file too. Authority does not bind the Proxy addresses. Without them a
joining node receives only its identity.