docs(docker): document settings.json writable-layer + env-var-vs-file semantics (#7819) (#7827)

Two related operator-facing docs gaps, both surfaced by #7819:

1. settings.json on disk is a *template*; env-var substitution happens
   at load time in memory only. Operators repeatedly mistake the
   templated file for a stale config because the docs never spell out
   that the on-disk file is intentionally unchanged by env vars.

2. The default docker-compose.yml puts settings.json in the container's
   writable layer with no host mount, which means admin /settings edits
   are silently lost on `docker compose down && up`, `pull`, or
   watchtower — but preserved across plain `restart`. Operators don't
   reliably know which compose verbs recreate the container.

Adds two prose sections to doc/docker.md (explaining both gotchas, with
a recreate-vs-restart table) and a commented-out `./settings.json:…`
bind mount in both docker-compose.yml and the README compose example.
Bind mount is opt-in so existing setups behave identically.

No runtime change.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
John McLear 2026-05-25 09:39:25 +01:00 committed by GitHub
parent 689dd9d434
commit 4ff3363b9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 0 deletions

View file

@ -29,6 +29,37 @@ Edit `<BASEDIR>/settings.json.docker` at your will. When rebuilding the image, t
**Each configuration parameter can also be set via an environment variable**, using the syntax `"${ENV_VAR}"` or `"${ENV_VAR:default_value}"`. For details, refer to `settings.json.template`.
### How `settings.json` and environment variables interact
This trips people up often enough that it's worth calling out explicitly (see [#7819](https://github.com/ether/etherpad/issues/7819)):
* `settings.json` inside the container is a **template** containing `${VAR:default}` placeholders.
* Environment variable substitution happens at **load time, in memory only** — env vars never overwrite `settings.json` on disk.
* `docker exec <container> cat /opt/etherpad-lite/settings.json` will therefore always show the *templated* file (e.g. `"port": "${PORT:9001}"`), regardless of what `PORT` is set to in your environment. The resolved value is what Etherpad uses at runtime; the file is unchanged.
* The admin /settings page also reads this file directly, so the raw view shows placeholders too. The page now surfaces a banner and an "Effective" tab that displays the in-memory resolved values when placeholders are present.
### Persisting admin /settings edits across container recreates
`settings.json` lives in the container's writable layer by default. That means:
| Operation | Effect on `settings.json` |
|------------------------------------------|------------------------------------------|
| `docker restart` | Preserved (writable layer is reused) |
| `docker compose restart` | Preserved |
| `docker compose down && docker compose up` | **Reset** to the image template |
| `docker compose pull && docker compose up` | **Reset** to the new image template |
| Watchtower / image auto-update | **Reset** to the new image template |
| `docker rm` + `docker run` | **Reset** to the image template |
If you intend to edit `settings.json` through the admin UI (rather than relying solely on env vars), mount the file from the host so edits survive container recreate:
```yaml
volumes:
- ./settings.json:/opt/etherpad-lite/settings.json
```
(Bootstrap by copying `settings.json.docker` to `./settings.json` on the host before the first `up`.) The default compose example below ships this line commented out — uncomment it if you need persistent on-disk edits.
### Rebuilding including some plugins
If you want to install some plugins in your container, it is sufficient to list them in the ETHERPAD_PLUGINS build variable.
The variable value has to be a space separated, double quoted list of plugin names (see examples).
@ -282,6 +313,13 @@ services:
volumes:
- plugins:/opt/etherpad-lite/src/plugin_packages
- etherpad-var:/opt/etherpad-lite/var
# OPTIONAL: persist admin /settings edits across container recreates.
# Without this mount, settings.json lives in the image's writable
# layer — `docker compose restart` preserves it, but `docker compose
# down && up`, `pull`, or watchtower reverts it to the image
# template. Uncomment if you intend to edit settings.json through
# the /admin UI. See https://github.com/ether/etherpad/issues/7819.
# - ./settings.json:/opt/etherpad-lite/settings.json
depends_on:
- postgres
environment:

View file

@ -7,6 +7,14 @@ services:
volumes:
- plugins:/opt/etherpad-lite/src/plugin_packages
- etherpad-var:/opt/etherpad-lite/var
# OPTIONAL: persist admin /settings edits across container recreates.
# Without this mount, settings.json lives in the image's writable
# layer — `docker compose restart` preserves it, but `docker compose
# down && up`, `pull`, or watchtower reverts it to the image
# template. Uncomment if you intend to edit settings.json through
# the /admin UI instead of (or in addition to) env vars. See
# https://github.com/ether/etherpad/issues/7819.
# - ./settings.json:/opt/etherpad-lite/settings.json
depends_on:
- postgres
environment: