Summary
Log timestamps are always UTC and can't be changed. Setting TZ on the container has no effect.
[vaultwarden-api] INFO: 2026/09/09 00:14:55 api_client.go:221: Authentication successful
Cause
pkg/logger/logger.go uses log.Ldate|log.Ltime|log.Lshortfile (no log.LUTC), so Go formats timestamps in time.Local — this part is fine.
But the runtime image (Dockerfile, FROM alpine:3.24) installs only ca-certificates wget. With no tzdata and no TZ, Go's time.Local resolves to UTC, and -e TZ=... can't work because there's no /usr/share/zoneinfo to load.
Fix
Embed the zoneinfo DB in the binary so TZ works with no image change and no extra layer (matters for the read_only: true compose setup):
// main package
import _ "time/tzdata"
Then TZ selects the zone:
environment:
- TZ=Pacific/Auckland
Adds ~450 KB to the binary. Alternative: RUN apk add --no-cache tzdata in the runtime stage.
Worth a line in the README documenting TZ once either is in.
Summary
Log timestamps are always UTC and can't be changed. Setting
TZon the container has no effect.Cause
pkg/logger/logger.gouseslog.Ldate|log.Ltime|log.Lshortfile(nolog.LUTC), so Go formats timestamps intime.Local— this part is fine.But the runtime image (
Dockerfile,FROM alpine:3.24) installs onlyca-certificates wget. With notzdataand noTZ, Go'stime.Localresolves to UTC, and-e TZ=...can't work because there's no/usr/share/zoneinfoto load.Fix
Embed the zoneinfo DB in the binary so
TZworks with no image change and no extra layer (matters for theread_only: truecompose setup):Then
TZselects the zone:Adds ~450 KB to the binary. Alternative:
RUN apk add --no-cache tzdatain the runtime stage.Worth a line in the README documenting
TZonce either is in.