Configuration
This page explains how Etherpad is configured and documents the reverse-proxy and subpath behaviour in detail. It is not an exhaustive list of every setting — for that, see the fully-commented settings.json.template, which is the authoritative reference.
Where settings live
Etherpad reads its configuration from settings.json in the installation root. A new install copies settings.json.template to settings.json on first run.
- Override the file location by passing the
-s/--settingsflag to the launcher, e.g.bin/run.sh -s /etc/etherpad/settings.json. This lets you run multiple instances from one installation. (bin/run.shforwards the flag topnpm run prod, which is the supported entrypoint — there is noserver.js; the runtime issrc/node/server.ts, loaded viatsx.) - Environment-variable substitution — any string value may reference an environment variable using the syntax
"${ENV_VAR}"or"${ENV_VAR:default}". The variable name must be quoted, even when the resolved value is a number or boolean. A few rules worth remembering:"${PORT:9001}"→ the value ofPORT, or9001if unset."${MINIFY:true}"→ the booleantrue/false, not the string."${UNSET_VAR:null}"→null;"${UNSET_VAR:}"→ the empty string.- Substitution happens at load time, in memory only — env vars never overwrite
settings.jsonon disk.
When running in Docker, almost every setting is wired to an environment variable in the shipped settings.json.docker. See the Docker page for the full env-var list.
Trusting a reverse proxy
If Etherpad runs behind NGINX, Traefik, HAProxy, a Kubernetes ingress, or any other reverse proxy, set:
"trustProxy": trueThis makes Etherpad trust the standard X-Forwarded-* headers, so it:
- uses the real client IP (from
X-Forwarded-For) in logs and rate limits instead of the proxy's IP; - respects the forwarded protocol and host, so the
secureflag is set on cookies when the proxy terminates TLS (required forSameSite=None).
Leave it at the default false when Etherpad is reachable directly on a public IP — otherwise any client could forge these headers.
Running under a subpath / ingress
Etherpad can be served under a URL-path prefix (for example https://example.com/etherpad/) without recompiling anything. The prefix is discovered per-request from upstream headers, so the same Etherpad process works whether it is mounted at the root or under a path.
Three headers are checked, in this order; the first non-empty value (after sanitization) wins:
| Order | Header | Origin | Requires trustProxy: true? |
|---|---|---|---|
| 1 | x-proxy-path | Etherpad's own convention | No — always honoured |
| 2 | X-Forwarded-Prefix | HAProxy / Traefik / Spring | Yes |
| 3 | X-Ingress-Path | Kubernetes / Home Assistant ingress | Yes |
x-proxy-path is always honoured because an operator must deliberately configure their proxy to send Etherpad's custom header. The two standard headers (X-Forwarded-Prefix, X-Ingress-Path) are honoured only when trustProxy is true, because otherwise a client on a public IP could forge them.
Once detected, the prefix is woven into the responses that would otherwise break under a subpath:
manifest.json(PWA install metadata);- the social-media meta tags (
og:url/og:image), unless an explicitpublicURLis configured; - the bootstrap script entrypoint and the asset / reconnect links in the pad, index, and timeslider pages.
Sanitization
The header value is treated as untrusted input even when read from a trusted header, because it ends up inside HTML, JS, CSS, and HTTP Location headers. The sanitizer (src/node/utils/sanitizeProxyPath.ts):
- strips every character outside
[A-Za-z0-9_./-]; - collapses a leading
//+to a single/, so the value can never be read as a protocol-relative URL; - prepends
/if the result doesn't already start with one; - rejects any value containing a
..path segment (returns empty).
The output is therefore always either empty, or a string that starts with exactly one / and contains only [A-Za-z0-9_./-].
Example: Traefik
http:
middlewares:
etherpad-prefix:
stripPrefix:
prefixes:
- "/etherpad"
etherpad-headers:
headers:
customRequestHeaders:
X-Forwarded-Prefix: "/etherpad"Apply both middlewares to the router and set trustProxy: true in settings.json.
Example: NGINX
location /etherpad/ {
proxy_pass http://127.0.0.1:9001/;
proxy_set_header X-Proxy-Path /etherpad;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Here X-Proxy-Path is used, which works regardless of trustProxy. Use X-Forwarded-Prefix instead if you prefer the standard header (and set trustProxy: true).
Self-update, email, database, and metrics
These areas have their own pages:
- Self-update and outbound email (
adminEmail,mail.*SMTP) — see Updates. The corresponding Docker env vars (MAIL_HOST,MAIL_FROM, …) are listed on the Docker page. - Database — choose a backend with
dbType/dbSettings. The supported drivers and example settings are documented insettings.json.template, and the Docker equivalents (DB_TYPE,DB_HOST, …) are listed on the Docker page. The on-disk keyspace layout is described indoc/database.adoc. - Metrics — Etherpad exposes Prometheus-compatible metrics; see Stats.