Endpoints configuration¶
The flat configuration hub remains the compatibility route. This page is the canonical source-checked field reference for its family, including nested tables and list rows.
Paths in the tables are relative to [endpoints]. Each row gives the serde
type and source default or unset meaning, and says whether the value is a bind
or dial address. Check parsing and endpoint cross-field rules with
gdsgate doctor --config <PATH> --json, then follow the multi-node cluster
guide.
[endpoints]¶
Used by: Authority, Proxy, Connector, Client. Each reads only the fields it
needs: Client only proxy_public, Authority only its own listeners.
Bind targets (for the service that owns the listener) and dial targets (for
peers that consume it), as host:port. 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. |
authority_failover |
array of strings | [] |
Additional Authority endpoints for HA. The Proxy's connection pool follows the audit write-leader across these. |
authority_enroll |
string | 127.0.0.1:50050 |
Authority's plaintext bootstrap listener. New nodes register here with a one-time token. |
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"
authority may be omitted: unset, it is 127.0.0.1:50051 wherever it is bound
or dialled. Omitting it matters on a connector running
authority_transport = "fronted", which then derives the Authority
control plane from proxy_internal and needs only one address.
proxy_join: the join relay¶
A node obtains its transport identity before it has a reverse tunnel, so neither
registration nor renewal can travel one. A connector that must never address
Authority (authority_transport = "tunneled") therefore needs a
listener on the Proxy that stands in for both Authority listeners. proxy_join
is that address, both the bind address on the Proxy and the dial address on the
node.
It is one of two ways to serve that. The other is the gateway's own
client-facing port ([proxy].public_join), which spares a node a
second address entirely. proxy_join is the one to use where the join belongs on
an address of its own; the two can run side by side.
The relay reads the first bytes of each connection and routes on their shape: a
TLS handshake goes to authority (renewal), the HTTP/2 cleartext preface goes to
authority_enroll (first registration), anything else is refused and the connection
closed. TLS is not terminated, so a renewal presents the node's own certificate
to Authority and Authority's checks work as on a direct dial.
Join relay HA behavior
Both destinations are the primary ones, authority and authority_enroll, never
an authority_failover address. Registration and renewal both write the audit
chain, so only the write-leader serves them; while the leader is some other
instance, a join or a token-less renewal through the Proxy is refused with
"unavailable".
Nothing else breaks: nodes already holding a valid identity keep working, and the tunnelled control plane (below) does follow the leader. A node retries its renewal, starting an hour before expiry against a 24-hour leaf, and each attempt is bounded, so the retries keep coming for as long as the leader is elsewhere. It does not fall back to a registration token: that path exists only at start-up, and only while the token is unspent. A first registration is an operator action and can be repeated, or aimed straight at Authority.
Where a deployment cannot live with that, register nodes against Authority's own addresses instead of through the relay.
Join relay authentication
Every other Proxy listener demands mutual TLS or a token; a node joining has neither yet. Expose the address deliberately. What protects it:
- The destination is not the client's to choose. Both addresses come from the Proxy's own configuration. Nothing on the wire can name, redirect, or add one: the first bytes select a branch, not a host.
- A per-source-IP accept rate limit, 5/s with a burst of 10, the same budget Authority applies to direct registrations. It has to live here, because relayed joins all reach Authority from the Proxy's address, so Authority's own limit could not tell one flooding node from a fleet.
- A ceiling of 64 concurrent joins, a 5-second limit on how long a connection may stay silent, and a 30-second idle limit on an established relay. A join is a short exchange, and none of these bite a real one.
Those five figures are what the relay runs on when nothing says otherwise,
and a site whose rollout is larger than they allow states its own; see the
join_* keys in [proxy]. Unlike every other limit there,
leaving a key out keeps the figure above, and a stated 0 means unlimited.
[proxy].single_port does not multiplex this listener; it stays
on its own address.
Join relay TLS behavior
It terminates neither side, because a renewal's mutual TLS has to reach
Authority intact. Whether a registration crossing it is encrypted is decided
at the far end, by Authority's registration listener; see
[authority]. With no certificate there, every provision
token relayed through this address travels in cleartext. gdsgate doctor
reports the relay, the limits in force, and which of the two cases this
deployment is in.
What Authority tells a joining node¶
Authority answers a registration, and every token-less renewal after it, with the node's identity and with the settings that identity is used alongside:
| 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 |
Nothing here is a secret, and nothing here is anonymous either: it rides a
grant, so its reader has already spent a one-time provision token. It does not
replace [enroll] or [endpoints] on the node, which still runs the file it was
started with, and it is what a single installation command reads instead of
deriving addresses from a domain by convention.
Two rules make it worth depending on:
- A bind target is not an advertised address. Every key in this section is a
bind address, and a container deployment writes
0.0.0.0in all of them. A wildcard bind is advertised as nothing at all, because a node handed0.0.0.0:50062would have no other address for its own gateway; told nothing, it says so. - The scheme is Authority's to name. Whether a renewal runs mutual TLS is decided by the URL scheme and nothing else, so the renewal address is advertised with the scheme this cluster speaks; the node does not assemble it. A node that is handed one it cannot use refuses and quotes what arrived.
On the tunnelled route the renewal address is proxy_join where a relay is
bound, and the gateway's own client-facing address where the Proxy carries the
join there instead ([proxy].public_join): single_port when
the deployment multiplexes onto one port, proxy_public otherwise. A relay of
its own wins where both are configured. On direct and fronted it is
authority.
Both of those are Proxy settings that Authority has to know, for the same reason
it has to know [connector].authority_transport: Authority is what tells the fleet.
In a split deployment, public_join = true goes in Authority's file as well as
in the Proxy's.
Authority says at start-up what it will advertise, and warns when its own
[endpoints] name nothing worth handing out.
Split deployments must declare the Proxy's addresses
Authority advertises the [endpoints] it holds. In a deployment where
Authority and the Proxy run from separate files, the Proxy's addresses have
to appear in Authority's file too: they are dial targets there, not bind
targets, and Authority binds nothing from them. Without them a joining node
is told only its identity.