Files
webmail-client/docker/.env.prod.example
T
lukasandClaude Opus 5 2f03bee45b Deploy: drop cpus: limits and stop assuming docker compose exists
Two NAS realities, both hit on a real Synology box.

- "NanoCPUs" error part-way through the project build: `cpus:` maps to the
  NanoCPUs field, which DSM's Docker daemon rejects. Removed from all three
  services (and from .env.prod.example). mem_limit uses the much older Memory
  field and works, so memory caps remain the throttle. Noted in the header
  next to the other DSM constraints.
- `docker compose build` on DSM: "'compose' is not a docker command". DSM and
  QTS ship the standalone `docker-compose` binary with no plugin subcommand,
  so every one of the script's 21 compose invocations was wrong for the target
  platform. The script now detects which is present, and only passes `--wait`
  when it finds v2 — on v1 it falls back to the health_gate it already had,
  which is also now run after `up` on both paths.

That the build reached container creation before failing says their compose
parses the rest of the file (anchors, profiles, service_completed_successfully,
top-level name), so this was a daemon-level rejection, not a schema one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nux3LCu4zP9nih4BRhPyHw
2026-09-14 20:09:32 +02:00

112 lines
4.3 KiB
Bash

# ============================================================================
# Webmail production configuration.
#
# Copy to docker/.env.prod, fill in the three REQUIRED values, keep it safe:
# cp docker/.env.prod.example docker/.env.prod && chmod 600 docker/.env.prod
#
# THIS FILE IS A BACKUP ARTEFACT. MASTER_KEY is not stored anywhere else: lose
# it and every saved mail-account password becomes permanently undecryptable,
# even from a perfect database backup. Keep a copy in a password manager.
# ============================================================================
# --- REQUIRED ---------------------------------------------------------------
# Where all persistent data lives on the host. Use a real shared folder your NAS
# backup tool can see — not a Docker named volume.
# Synology: /volume1/docker/webmail/data
# QNAP: /share/Container/webmail/data
DATA_ROOT=/volume1/docker/webmail/data
# 32 random bytes, base64. Generate ONCE, then never change it:
# openssl rand -base64 32
MASTER_KEY=
# Database password. Generate once:
# openssl rand -base64 24 | tr -d '/+=' | cut -c1-24
POSTGRES_PASSWORD=
# --- Identity ---------------------------------------------------------------
# The domain your user handles are minted under (user@APP_DOMAIN) and the issuer
# shown in 2FA authenticator apps. It does NOT have to be publicly resolvable.
APP_DOMAIN=mail.home.lan
# --- Network ----------------------------------------------------------------
# The single published port. Avoid 5000/5001 (Synology DSM) and 8080 (QNAP QTS).
WEB_PORT=8088
# Bind to one NAS interface instead of every network, e.g. WEB_BIND=192.168.1.185
WEB_BIND=0.0.0.0
TZ=Europe/Warsaw
# --- Search -----------------------------------------------------------------
# pg = Postgres full-text. No extra container, no extra RAM. Default.
# meili = Meilisearch: typo tolerance, better ranking, faster on large mailboxes.
# Costs a container and ~0.7-1 GB RAM. Start it with:
# ./deploy/webmail.sh up --meili
# and after switching an existing install, rebuild the index:
# ./deploy/webmail.sh reindex
SEARCH_BACKEND=pg
# Required if SEARCH_BACKEND=meili — generate with: openssl rand -base64 32
MEILI_MASTER_KEY=
# --- Images -----------------------------------------------------------------
# `local` = built on this host from the repo. To deploy prebuilt images from
# your Gitea registry instead, set both of these (see deploy/build-push.sh):
# REGISTRY_PREFIX=192.168.1.185:8418/claude/webmail
# IMAGE_TAG=v1.0.0
REGISTRY_PREFIX=webmail
IMAGE_TAG=local
# --- Application ------------------------------------------------------------
LOG_LEVEL=INFO
UNDO_SECONDS=10
SESSION_TTL_DAYS=30
MAX_ATTACHMENT_MB=25
# Auto-purge Trash/Spam older than N days (0 disables).
TRASH_RETENTION_DAYS=30
# Server-side sender avatars (Gravatar + favicon), fetched by the server so
# senders never see your IP. Set false to make zero outbound web requests.
SENDER_AVATARS_ENABLED=true
GOOGLE_OAUTH_ENABLED=false
OAUTH_GOOGLE_CLIENT_ID=
OAUTH_GOOGLE_CLIENT_SECRET=
OAUTH_MS_CLIENT_ID=
OAUTH_MS_CLIENT_SECRET=
# Plugins whose schema is migrated on every start. Remove one to stop shipping
# its tables; `hello` is the SDK demo and is intentionally not listed.
ENABLED_PLUGINS="calendar contacts labels filters"
# --- Backups ----------------------------------------------------------------
BACKUP_AT=03:30
BACKUP_KEEP_DAYS=14
# --- Sizing (defaults suit a personal install on a shared NAS) --------------
# Peak worker RAM is roughly PARSE_CONCURRENCY x STREAM_PARSE_MB plus overhead.
INTERACTIVE_CONCURRENCY=8
BULK_CONCURRENCY=1
PARSE_CONCURRENCY=2
STREAM_PARSE_MB=8
PER_HOST_CONN_CAP=10
HOT_BUDGET_PER_WORKER=50
# Container caps. Memory only: CPU limits (`cpus:`) are deliberately absent
# because Synology's Docker daemon rejects them (NanoCPUs).
# Container caps. Total without Meilisearch: ~2.2 GB of *limits*; real steady
# usage for one or two mail accounts is around 700 MB-1 GB.
PG_MEM_LIMIT=768m
PG_SHARED_BUFFERS=256MB
PG_MAX_CONNECTIONS=100
PG_WORK_MEM=8MB
PG_MAINTENANCE_WORK_MEM=128MB
PG_EFFECTIVE_CACHE_SIZE=768MB
REDIS_MEM_LIMIT=160m
REDIS_MAXMEMORY=96mb
API_MEM_LIMIT=512m
WORKER_SYNC_MEM_LIMIT=512m
WORKER_JOBS_MEM_LIMIT=640m
WEB_MEM_LIMIT=96m
BACKUP_MEM_LIMIT=256m
MEILI_MEM_LIMIT=1g