traefik: uncap download duration (writeTimeout 60s->0), upload window 3600s [ci skip]

Large Immich video downloads and uploads failed at a hard ~60s wall. The
websecure entrypoint set respondingTimeouts.{read,write}Timeout=60s; unlike
nginx proxy_*_timeout (per-read idle), Traefik respondingTimeouts are hard caps
on total request/response duration, so every transfer slower than 60s was cut
mid-stream. Reproduced: a 6 MB/s throttled 650MB download died at 386MB / 62s
with an HTTP/2 stream reset.

- writeTimeout=0 (Traefik's default, which Immich's reverse-proxy guidance
  assumes): unlimited download size/duration.
- readTimeout=3600s: passes multi-GB uploads while keeping a slow-loris backstop
  (Immich has no resumable upload, so the window must exceed real upload times).

Verified: the same 650MB download now completes fully (650MB / 102s, exit 0).
IPv6 path needs no change - the pfSense bridge HAProxy 1h timeouts are
inactivity-based, not total caps. Applied via tg (Tier 1 / PG-authoritative
state); this commit syncs source + docs only, hence [ci skip].

Docs: networking.md (Entrypoint Transport Timeouts + troubleshooting),
.claude/CLAUDE.md networking note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-05-30 17:46:59 +00:00
parent 89561c7779
commit 5bcb4525a4
3 changed files with 34 additions and 3 deletions

View file

@ -234,9 +234,17 @@ resource "helm_release" "traefik" {
"--serversTransport.forwardingTimeouts.idleConnTimeout=90s",
# Increase backend connection pool (default maxIdleConnsPerHost=2 is too low)
"--serversTransport.maxIdleConnsPerHost=100",
# Explicit entrypoint timeouts to bound tail latency from slow clients
"--entryPoints.websecure.transport.respondingTimeouts.readTimeout=60s",
"--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=60s",
# Entrypoint transport timeouts. NOTE: Traefik respondingTimeouts are HARD caps on
# total request/response duration (unlike nginx proxy_*_timeout, which reset per read).
# A finite writeTimeout therefore caps total *download* time regardless of progress
# a prior writeTimeout=60s silently truncated large downloads at 60s (HTTP/2 reset).
# writeTimeout=0 -> unlimited download size/duration (Traefik's own default; Immich's
# reverse-proxy guidance assumes it it never sets writeTimeout).
# readTimeout=3600s -> one upload may take up to 1h. NOT 0: an unbounded request read
# is the slow-loris vector (hence Traefik's 60s default). Immich has
# no resumable upload, so the window must exceed real upload times.
"--entryPoints.websecure.transport.respondingTimeouts.readTimeout=3600s",
"--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=0s",
"--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=600s",
# Use forwarded headers from trusted proxies
"--entryPoints.websecure.forwardedHeaders.insecure=false",