Deploy: make a missing .env name its own fix
With no .env found, compose fell back to a sentinel path and the daemon reported: Bind mount failed: 'DATA_ROOT-is-unset/postgres' does not exist — accurate, but it tells the operator nothing about what to do, and this is the most common way the install goes wrong (the file is generated by `init`, not shipped in the repo, so any re-copy of the folder loses it). The sentinel is now /NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST, so the daemon's own error states the fix. doctor also checks for a missing or empty .env before anything else and says the same thing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nux3LCu4zP9nih4BRhPyHw
This commit is contained in:
@@ -234,6 +234,10 @@ cmd_doctor() {
|
|||||||
require_env
|
require_env
|
||||||
local ok=0
|
local ok=0
|
||||||
|
|
||||||
|
if [ ! -s "$ENV_FILE" ]; then
|
||||||
|
red " $ENV_FILE is missing or empty — nothing will start. Run: webmail.sh init" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
echo "config:"
|
echo "config:"
|
||||||
echo " DATA_ROOT ${DATA_ROOT}"
|
echo " DATA_ROOT ${DATA_ROOT}"
|
||||||
echo " APP_DOMAIN ${APP_DOMAIN:-<unset>}"
|
echo " APP_DOMAIN ${APP_DOMAIN:-<unset>}"
|
||||||
|
|||||||
+16
-12
@@ -21,6 +21,10 @@
|
|||||||
# Start: ./deploy/webmail.sh up
|
# Start: ./deploy/webmail.sh up
|
||||||
# Manual: docker compose up -d (reads .env from this directory)
|
# Manual: docker compose up -d (reads .env from this directory)
|
||||||
#
|
#
|
||||||
|
# The odd-looking DATA_ROOT default is deliberate: if no .env is found, the
|
||||||
|
# daemon's "Bind mount failed: '<path>' does not exist" error then names the
|
||||||
|
# fix instead of pointing at a directory nobody meant to create.
|
||||||
|
#
|
||||||
# Likewise, no `cpus:` limits: that maps to NanoCPUs, which DSM's Docker
|
# Likewise, no `cpus:` limits: that maps to NanoCPUs, which DSM's Docker
|
||||||
# daemon rejects ("NanoCPUs can not be set"). mem_limit uses the much older
|
# daemon rejects ("NanoCPUs can not be set"). mem_limit uses the much older
|
||||||
# Memory field and works fine, so memory caps are the throttle here.
|
# Memory field and works fine, so memory caps are the throttle here.
|
||||||
@@ -99,10 +103,10 @@ services:
|
|||||||
chmod 700 /mnt/backups
|
chmod 700 /mnt/backups
|
||||||
echo "[init] data directories ready"
|
echo "[init] data directories ready"
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/blobs:/mnt/blobs
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/mnt/blobs
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/backups:/mnt/backups
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/backups:/mnt/backups
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/redis:/mnt/redis
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/redis:/mnt/redis
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/meili:/mnt/meili
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/meili:/mnt/meili
|
||||||
restart: "no"
|
restart: "no"
|
||||||
logging: *logging
|
logging: *logging
|
||||||
|
|
||||||
@@ -130,7 +134,7 @@ services:
|
|||||||
- effective_cache_size=${PG_EFFECTIVE_CACHE_SIZE:-768MB}
|
- effective_cache_size=${PG_EFFECTIVE_CACHE_SIZE:-768MB}
|
||||||
# Full page writes stay ON: NAS filesystems (btrfs/ext4) are not 8k-atomic.
|
# Full page writes stay ON: NAS filesystems (btrfs/ext4) are not 8k-atomic.
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/postgres:/var/lib/postgresql/data
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/postgres:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-webmail} -d ${POSTGRES_DB:-webmail}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-webmail} -d ${POSTGRES_DB:-webmail}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -157,7 +161,7 @@ services:
|
|||||||
- --maxmemory-policy
|
- --maxmemory-policy
|
||||||
- noeviction
|
- noeviction
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/redis:/data
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/redis:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -180,7 +184,7 @@ services:
|
|||||||
MEILI_NO_ANALYTICS: "true"
|
MEILI_NO_ANALYTICS: "true"
|
||||||
TZ: ${TZ:-UTC}
|
TZ: ${TZ:-UTC}
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/meili:/meili_data
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/meili:/meili_data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:7700/health | grep -q available"]
|
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:7700/health | grep -q available"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -203,7 +207,7 @@ services:
|
|||||||
<<: *backend-env
|
<<: *backend-env
|
||||||
ENABLED_PLUGINS: ${ENABLED_PLUGINS:-calendar contacts labels filters}
|
ENABLED_PLUGINS: ${ENABLED_PLUGINS:-calendar contacts labels filters}
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/blobs:/data/blobs
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/data/blobs
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres: { condition: service_healthy }
|
postgres: { condition: service_healthy }
|
||||||
init: { condition: service_completed_successfully }
|
init: { condition: service_completed_successfully }
|
||||||
@@ -215,7 +219,7 @@ services:
|
|||||||
command: ["api"]
|
command: ["api"]
|
||||||
environment: *backend-env
|
environment: *backend-env
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/blobs:/data/blobs
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/data/blobs
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/api/healthz', timeout=5).status==200 else 1)\""]
|
test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/api/healthz', timeout=5).status==200 else 1)\""]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@@ -235,7 +239,7 @@ services:
|
|||||||
command: ["worker-sync"]
|
command: ["worker-sync"]
|
||||||
environment: *backend-env
|
environment: *backend-env
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/blobs:/data/blobs
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/data/blobs
|
||||||
# Persistent IMAP IDLE connections; the default 1024 is fine for a personal
|
# Persistent IMAP IDLE connections; the default 1024 is fine for a personal
|
||||||
# install but this costs nothing and matches the sync-engine v2 sizing.
|
# install but this costs nothing and matches the sync-engine v2 sizing.
|
||||||
ulimits:
|
ulimits:
|
||||||
@@ -255,7 +259,7 @@ services:
|
|||||||
command: ["worker-jobs"]
|
command: ["worker-jobs"]
|
||||||
environment: *backend-env
|
environment: *backend-env
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/blobs:/data/blobs
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/data/blobs
|
||||||
ulimits:
|
ulimits:
|
||||||
nofile: { soft: 8192, hard: 8192 }
|
nofile: { soft: 8192, hard: 8192 }
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -310,7 +314,7 @@ services:
|
|||||||
BACKUP_KEEP_DAYS: ${BACKUP_KEEP_DAYS:-14}
|
BACKUP_KEEP_DAYS: ${BACKUP_KEEP_DAYS:-14}
|
||||||
TZ: ${TZ:-UTC}
|
TZ: ${TZ:-UTC}
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/DATA_ROOT-is-unset}/backups:/backups
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/backups:/backups
|
||||||
- ./docker/backup.sh:/usr/local/bin/backup.sh:ro
|
- ./docker/backup.sh:/usr/local/bin/backup.sh:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres: { condition: service_healthy }
|
postgres: { condition: service_healthy }
|
||||||
|
|||||||
Reference in New Issue
Block a user