Files
tanabata/.env.example
T
H1K0 a6a46af12e feat(backend): graceful shutdown on SIGTERM/SIGINT
Run the HTTP server in a goroutine and, on SIGINT/SIGTERM, call
srv.Shutdown so it stops accepting connections and lets in-flight
requests finish before exiting (ErrServerClosed is a clean exit). This
stops uploads/streams being cut when the container is stopped or
recreated on deploy.

The drain deadline is configurable via SHUTDOWN_TIMEOUT (default 15s).
docker-compose.yml feeds the same variable into the app's
stop_grace_period, so Docker won't SIGKILL mid-drain and the two values
can't drift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 08:12:10 +03:00

159 lines
7.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# Tanabata File Manager — environment variables
#
# Copy to .env and fill in the secrets:
# cp .env.example .env
# docker compose up -d --build
# =============================================================================
# ---------------------------------------------------------------------------
# Docker Compose (read by the compose CLI, ignored by the app)
# ---------------------------------------------------------------------------
# Profiles to enable. "with-db" runs the bundled Postgres container. Leave
# EMPTY to skip it and use a Postgres running on the host instead — then point
# DATABASE_URL at host.docker.internal (see the Database section below).
COMPOSE_PROFILES=with-db
# Host port the app is published on, bound to 127.0.0.1 (loopback) — a reverse
# proxy on the host fronts it (see README → Reverse proxy). The container always
# listens on 42776. To expose the app directly without a proxy, drop the
# "127.0.0.1:" prefix on the ports line in docker-compose.yml.
APP_PORT=42776
# ---------------------------------------------------------------------------
# Volume mounts (Docker Compose; ignored by the app)
# ---------------------------------------------------------------------------
# By default the app's data and the database live in named Docker volumes
# (app_files, app_thumbs, app_import, db_data). To keep them in specific folders
# on the host instead, point any of these at a host path — absolute, or relative
# to this file (e.g. ./data/files). Unset = named volume.
# FILES_DIR=/var/lib/tanabata/files
# THUMBS_DIR=/var/lib/tanabata/thumbs
# IMPORT_DIR=/var/lib/tanabata/import
# DB_DIR=/var/lib/tanabata/db
# When bind-mounting the app folders above, the container must be able to write
# to them. Set PUID/PGID to the owner of those folders and create them with
# matching ownership first, e.g.:
# sudo mkdir -p /var/lib/tanabata/{files,thumbs,import}
# sudo chown -R 1000:1000 /var/lib/tanabata
# PUID=1000
# PGID=1000
# Defaults match the image's tanabata user (42776), which owns the named volumes. The
# DB folder is handled by Postgres itself and needs no PUID/PGID.
# PUID=42776
# PGID=42776
# ---------------------------------------------------------------------------
# Server
# ---------------------------------------------------------------------------
# 42776 is the project's default port: the sum of the Unicode code points of
# 七夕 (七 U+4E03 = 19971, 夕 U+5915 = 22805).
LISTEN_ADDR=:42776
JWT_SECRET=change-me-to-a-random-32-byte-secret
JWT_ACCESS_TTL=15m
JWT_REFRESH_TTL=720h
# How long a content token is valid. It's a single-file capability the client
# puts in a media URL to open/stream an original by link (e.g. a long video in a
# new tab), so playback survives the short access-token expiry and session
# rotation. Longer = fewer interruptions but a wider window in which a leaked URL
# can read that one file; it can't be revoked before expiry. Keep it roughly as
# long as a viewing session lasts.
CONTENT_TOKEN_TTL=6h
# How long a graceful shutdown waits for in-flight requests to finish after the
# app receives SIGTERM/SIGINT (e.g. on `docker compose up --build`, which
# recreates the container). This SAME value is fed to the container's
# `stop_grace_period` in docker-compose.yml, so Docker won't SIGKILL the app
# mid-drain — set it in one place here and both stay in sync. A single upload or
# video stream that outlasts this window is still cut; raise it if you routinely
# move very large files. Accepts Go/Compose durations (s, m, h).
SHUTDOWN_TIMEOUT=15s
# Reverse-proxy hops (comma-separated CIDRs/IPs) whose X-Forwarded-For is trusted,
# so the auth rate limiter sees real client IPs instead of the proxy's. The default
# covers loopback and the Docker bridge ranges a host nginx reaches the container
# through; widen/narrow it to match your proxy. Leave at the default for the
# standard "host nginx → 127.0.0.1" setup.
TRUSTED_PROXIES=127.0.0.1/32,::1/128,172.16.0.0/12
# Initial administrator, created on first startup if it does not yet exist.
# Changing the password later (via the API) is preserved across restarts.
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-me-before-first-run
# ---------------------------------------------------------------------------
# Database
# ---------------------------------------------------------------------------
# Credentials for the bundled Postgres container (the "with-db" profile).
# Keep these in sync with DATABASE_URL below.
POSTGRES_DB=tanabata
POSTGRES_USER=tanabata
POSTGRES_PASSWORD=password
# Connection string the app uses. Pick ONE to match your database mode:
#
# • Bundled container DB (COMPOSE_PROFILES=with-db) — host is the "db" service:
DATABASE_URL=postgres://tanabata:password@db:5432/tanabata?sslmode=disable
#
# • Postgres on the host (COMPOSE_PROFILES empty):
# DATABASE_URL=postgres://tanabata:password@host.docker.internal:5432/tanabata?sslmode=disable
#
# • Bare-metal `go run` (no Docker):
# DATABASE_URL=postgres://tanabata:password@localhost:5432/tanabata?sslmode=disable
# ---------------------------------------------------------------------------
# Storage (paths inside the container; backed by named volumes in compose)
# ---------------------------------------------------------------------------
FILES_PATH=/data/files
THUMBS_CACHE_PATH=/data/thumbs
# Maximum accepted upload size in bytes (default 500 MiB).
MAX_UPLOAD_BYTES=524288000
# ---------------------------------------------------------------------------
# Thumbnails
# ---------------------------------------------------------------------------
THUMB_WIDTH=160
THUMB_HEIGHT=160
PREVIEW_WIDTH=1920
PREVIEW_HEIGHT=1080
# Pixel cap (width×height) for the pure-Go fallback decoder, used only when
# vipsthumbnail is NOT installed; larger images then get a placeholder. With vips
# present (the default image) thumbnails shrink on load, so this limit — and its
# RAM cost — don't apply. Also bounds a decompression bomb. Default ~300 Mpx.
THUMB_MAX_PIXELS=300000000
# How many thumbnails/previews may be generated at once. Each resize already uses
# every core, so a burst of large images otherwise pegs the CPU and RAM. 0 = auto
# (half the available CPUs).
THUMB_CONCURRENCY=0
# ---------------------------------------------------------------------------
# Import
# ---------------------------------------------------------------------------
IMPORT_PATH=/data/import
# ---------------------------------------------------------------------------
# Duplicate detection
# ---------------------------------------------------------------------------
# Maximum perceptual-hash distance (Hamming, out of 64 bits) for two files to be
# treated as duplicate candidates. Lower = stricter (fewer, more confident
# matches); higher = looser (catches more re-encodes/resizes but risks false
# positives). On real libraries the distance histogram climbs steeply in the 810
# band — coincidental "vaguely similar" pairs, not duplicates — so 4 keeps the
# genuine-duplicate signal without that noise (and far fewer pairs to cluster).
# Used only by the dedup tool's pairs rebuild — see the dedup CLI /
# `docker compose run --rm dedup`. Code default is 10.
DUPLICATE_HASH_THRESHOLD=4
# ---------------------------------------------------------------------------
# Static SPA
# ---------------------------------------------------------------------------
# Leave UNSET here. The Docker image already serves the built SPA from
# /app/static and compose pins STATIC_DIR for the container — an empty value in
# .env would be injected into the container and disable SPA serving. Set this
# only for a bare-metal deploy where the Go server serves a built SPA; leave it
# unset in local dev, where the Vite dev server serves the UI.
# STATIC_DIR=/path/to/frontend/build