Tenant Wildcard Hostnames
Operate Athena tenant hostnames in the canonical public shape tenant.v3.athena-cluster.com.
This page is the source of truth for Athena tenant wildcard hostnames in the
canonical public shape tenant.v3.athena-cluster.com.
What Athena owns
Athena owns two parts of this feature:
- HTTP wildcard host routing for gateway requests
- catalog metadata for the public PostgreSQL hostname that belongs to a tenant
Athena does not own:
- Cloudflare DNS changes
- certificate issuance or rotation
- raw PostgreSQL TCP/TLS proxying on the tenant hostname
If you want raw PostgreSQL traffic to terminate on
tenant.v3.athena-cluster.com, you still need external L4 infrastructure such
as Cloudflare Spectrum or another TCP/TLS proxy. Athena only stores the host
and port metadata that such a proxy can follow.
Canonical routing model
- Wildcard suffix:
*.v3.athena-cluster.com - Tenant token: one hostname label only
- Allowed tenant characters:
[a-z0-9-_] - Tenant labels are lowercased before storage or derivation
- Dots are rejected inside the tenant token
- Athena resolves wildcard HTTP hosts from
public_gateway_routesonly - Athena does not fall back from host label to
athena_clients.client_name - One Athena process uses one wildcard pattern at a time via
ATHENA_WILDCARD_HOST_PATTERN
That means tenant.v3.athena-cluster.com resolves only when an active
public_gateway_routes row exists with:
route_key = tenantis_active = true
If the route is missing or inactive, Athena does not resolve the hostname.
Prerequisites
Before onboarding tenant hostnames, make sure all of the following are true:
ATHENA_WILDCARD_HOST_PATTERN=*.v3.athena-cluster.comATHENA_WILDCARD_HOST_ROUTING_ENABLED=trueif your deployment gates wildcard routing behind the feature flag- the target Athena client already exists in
athena_clients - the target client is active and not frozen
- the request includes the static admin key in
X-Athena-Key - your DNS or edge layer already points
*.v3.athena-cluster.comat Athena for HTTP traffic
If you want Athena to derive public PostgreSQL hostname metadata, the client must also expose a source Postgres URI through either:
athena_clients.metadata.network.private_pg_uri- the configured top-level client
pg_uri
Onboarding API
Use PUT /admin/tenant-hostnames/{tenant} to create or update the tenant
hostname contract.
Path and auth
- Path:
/admin/tenant-hostnames/{tenant} - Method:
PUT - Auth header:
X-Athena-Key: <ATHENA_KEY_12>
Request body
All fields are optional.
| Field | Type | Default | Behavior |
|---|---|---|---|
client_name | string | {tenant} | Athena client bound to the route |
allowed_ops | string[] | ["delete","fetch","insert","query","update"] | Normalized, deduplicated, then sorted |
enable_http_route | boolean | true | Upserts the public_gateway_routes row |
enable_postgres_binding | boolean | true | Derives the PostgreSQL public-host binding |
public_host | string | derived from wildcard pattern | Normalized host only; scheme, path, and port are stripped |
public_port | u16 | source Postgres URI port, else 5432 | Used in the derived public_pg_uri |
route_metadata | object | none | Merged into public_gateway_routes.metadata when enable_http_route=true |
persist_in_catalog | boolean | true | Persists PG binding metadata into the client record |
Rules:
- at least one of
enable_http_routeorenable_postgres_bindingmust betrue route_metadatamust be a JSON object when providedallowed_opsmust contain onlyquery,fetch,insert,update, ordelete
Response body
The response contains:
tenantderived_hosthttp_routepostgres_bindingwildcard_pattern
http_route is null when enable_http_route=false.
postgres_binding is null when enable_postgres_binding=false.
When postgres_binding is present it includes:
public_pg_uribindingdnspersisted_in_catalog
The dns field is a live lookup result for the derived public host at request
time.
Request examples
Default onboarding
This uses the tenant label for both the route key and the client name, creates the HTTP route, and stores the PostgreSQL binding metadata.
curl -X PUT "http://localhost:4052/admin/tenant-hostnames/acme" \
-H "Content-Type: application/json" \
-H "X-Athena-Key: ${ATHENA_KEY_12}" \
-d "{}"Expected behavior:
public_gateway_routes.route_keybecomesacmepublic_gateway_routes.client_namebecomesacmederived_hostbecomesacme.v3.athena-cluster.com- Athena stores the PG binding at
athena_clients.metadata.network.pg_route_bindings.acme
Shared client name with extra metadata
Use this when the public tenant label should resolve to a different existing client record.
curl -X PUT "http://localhost:4052/admin/tenant-hostnames/acme" \
-H "Content-Type: application/json" \
-H "X-Athena-Key: ${ATHENA_KEY_12}" \
-d '{
"client_name": "shared-prod",
"public_port": 45432,
"route_metadata": {
"managed_by": "tenant-hostname-runbook",
"external_proxy": "cloudflare-spectrum"
}
}'HTTP only
Use this when Athena should resolve the hostname for HTTP traffic but should not derive or persist PostgreSQL hostname metadata.
curl -X PUT "http://localhost:4052/admin/tenant-hostnames/acme" \
-H "Content-Type: application/json" \
-H "X-Athena-Key: ${ATHENA_KEY_12}" \
-d '{
"enable_http_route": true,
"enable_postgres_binding": false
}'Preview a PostgreSQL binding without persisting it
Use this when you want Athena to derive the public PostgreSQL contract and DNS
status without writing it into athena_clients.metadata.
curl -X PUT "http://localhost:4052/admin/tenant-hostnames/acme" \
-H "Content-Type: application/json" \
-H "X-Athena-Key: ${ATHENA_KEY_12}" \
-d '{
"enable_http_route": false,
"enable_postgres_binding": true,
"persist_in_catalog": false
}'Idempotency and update semantics
The endpoint is intended to be idempotent:
- repeated requests with the same effective route values reuse the existing
public_gateway_routesrow - repeated binding derivation for the same source URI and host shape produces
the same
public_pg_uri route_metadatamerges into the existing route metadata rather than replacing the whole object
If a route already exists but points at a different client, operation set, or metadata, Athena updates it in place and marks it active.
PostgreSQL binding behavior
When enable_postgres_binding=true, Athena:
- loads the source Postgres URI from
metadata.network.private_pg_urifirst, then falls back to the configured top-level clientpg_uri - derives
public_hostfromATHENA_WILDCARD_HOST_PATTERNunlesspublic_hostis explicitly supplied - derives
public_portfrom the source URI port unlesspublic_portis explicitly supplied - builds a
public_pg_uri - stores the binding under
athena_clients.metadata.network.pg_route_bindings.{tenant}whenpersist_in_catalog=true
Athena also preserves the private source URI in
metadata.network.private_pg_uri.
When Athena promotes top-level pg_uri
Athena overwrites the top-level client pg_uri with the derived
public_pg_uri only when the existing source URI is local or loopback-like,
including:
localhost127.0.0.1::10.0.0.0- local socket-style authorities
If the existing client already points at a non-loopback endpoint, Athena keeps
that top-level pg_uri unchanged and stores only the public hostname metadata.
HTTP resolution flow
Once a tenant route exists and wildcard host routing is enabled, this request
shape works without an explicit X-Athena-Client header:
POST /gateway/query HTTP/1.1
Host: acme.v3.athena-cluster.com
X-Athena-Key: ...
Content-Type: application/jsonAthena extracts acme from the host, looks up
public_gateway_routes.route_key = acme, checks is_active, and uses that
row's client_name as the gateway target.
Cloudflare and TLS boundary
Athena expects any TLS or edge setup to be handled outside the process.
Typical split:
- Cloudflare DNS or another DNS provider publishes
*.v3.athena-cluster.com - Cloudflare or another reverse proxy terminates HTTPS and forwards HTTP traffic to Athena
- Athena resolves the HTTP host through
public_gateway_routes - a separate TCP/TLS layer handles PostgreSQL traffic if you want raw Postgres on the same hostname
Athena does not call the Cloudflare API, does not provision Spectrum, and does not manage certificates for this feature.
Troubleshooting
| Symptom | Typical cause | Fix |
|---|---|---|
400 Invalid route key | tenant contains dots, invalid characters, or exceeds the route-key limit | Use a single-label tenant token with only [a-z0-9-_] |
400 Unknown client or 400 Ineligible client | client_name does not exist, is inactive, or is frozen | Create or reactivate the target client first |
400 Invalid allowed_ops | unsupported or empty operation list | Restrict values to query, fetch, insert, update, delete |
400 Invalid public host | explicit public_host could not be normalized | Supply a bare host or omit the field |
400 Invalid wildcard public host | ATHENA_WILDCARD_HOST_PATTERN cannot derive a host from the tenant label | Fix the wildcard pattern or the tenant token |
500 Client URI unavailable | PG binding was requested but Athena could not find private_pg_uri or top-level pg_uri | Seed one of those URIs before enabling PG binding |
dns.resolves=false | the hostname contract exists in Athena but external DNS is missing or still propagating | Fix external DNS or wait for propagation |
dns.resolves=false does not block Athena from storing the contract. It only
reports the live DNS state at request time.