Document the Traefik label loss and certificate refresh
This commit is contained in:
@@ -96,7 +96,12 @@ what we take vs. skip). Never vendor it into the build.
|
||||
*not* merge its generated Traefik labels for API-created apps: the full
|
||||
label set must live in `custom_labels` (mirror a working app's generated
|
||||
format — http/https routers with `certresolver=letsencrypt` — plus the TCP
|
||||
passthrough lines). Deployment JSON from the API can break `jq` (invalid
|
||||
passthrough lines). **On 2026-10-25 the TCP lines were found missing after a
|
||||
deploy** (custom_labels held only HTTP/Caddy labels), so Traefik terminated
|
||||
tunnel SNI with its default certificate. Restored with
|
||||
`PATCH /api/v1/applications/{uuid}` (`custom_labels` only, current HTTP
|
||||
labels preserved) and verified they survive a redeploy; check them after any
|
||||
app update. Deployment JSON from the API can break `jq` (invalid
|
||||
escapes in the logs field) — parse with python instead.
|
||||
- **Deployment**: the multi-stage `Dockerfile` builds a static non-root
|
||||
alpine image; verify `CGO_ENABLED=0 go build -trimpath -ldflags="-s -w"
|
||||
@@ -123,7 +128,13 @@ what we take vs. skip). Never vendor it into the build.
|
||||
`ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory`
|
||||
for tests; staging certs are untrusted. Local ACME E2E is Pebble +
|
||||
pebble-challtestsrv with `DNS_PROVIDER=challtestsrv` and
|
||||
`ACME_CA_BUNDLE=.../test/certs/pebble.minica.pem`.
|
||||
`ACME_CA_BUNDLE=.../test/certs/pebble.minica.pem`. The official CLI caches
|
||||
its certificate and polls `GET /api/tunnel/{id}/certificate` every 12 hours
|
||||
(every minute within 30 days of expiry), applying a renewed certificate to
|
||||
new connections without disconnecting; after switching the issuer, restart
|
||||
the service (`opentunnel down` / `up`) to fetch it immediately. An issuance
|
||||
killed mid-flight can leave `_acme-challenge` TXT records behind; delete them
|
||||
with `dns/deleteByNameType` (production and test tunnels share the zone).
|
||||
- **macOS system curl (LibreSSL) does not send SNI for `*.localhost` names**,
|
||||
so `curl https://api.<id>.localhost:8443/` gets closed (the relay requires
|
||||
SNI). Test with `openssl s_client -servername ...` or Homebrew curl.
|
||||
|
||||
@@ -107,6 +107,11 @@ For testing against Let's Encrypt staging (untrusted certificates, separate
|
||||
rate limits), set
|
||||
`ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory`.
|
||||
|
||||
The official CLI checks the certificate every 12 hours (every minute within
|
||||
30 days of expiry) and applies a renewed certificate to new connections; after
|
||||
switching the server's issuer, restart the CLI service (`opentunnel down` /
|
||||
`opentunnel up`) to fetch the new certificate immediately.
|
||||
|
||||
## Admin dashboard
|
||||
|
||||
With `ADMIN_TOKEN` set, `https://<domain>/` (and `/admin`) serves the admin
|
||||
@@ -148,6 +153,9 @@ untouched by SNI, because visitor TLS is terminated by the clients:
|
||||
`...rule=HostSNIRegexp(`^.+\.tunnel\.example\.com$`)`,
|
||||
`...tls.passthrough=true`,
|
||||
`traefik.tcp.services.tunnel-data.loadbalancer.server.port=8443`.
|
||||
After any app update or recreation, confirm the TCP labels are still in
|
||||
`custom_labels`: Coolify has dropped them when regenerating labels, leaving
|
||||
Traefik to terminate tunnel SNI with its default certificate.
|
||||
- Persistent volume on `/app/data`; healthcheck on `/health`.
|
||||
|
||||
**B. Plain Docker host.** tunneld owns the public ports itself: map host
|
||||
|
||||
Reference in New Issue
Block a user