doc/configuration.md
Rama develop · réplica de lectura del repositorio original.
# 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`](https://github.com/ether/etherpad/blob/develop/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` / `--settings` flag to
the launcher, e.g. `bin/run.sh -s /etc/etherpad/settings.json`. This lets
you run multiple instances from one installation. (`bin/run.sh` forwards the
flag to `pnpm run prod`, which is the supported entrypoint — there is no
`server.js`; the runtime is `src/node/server.ts`, loaded via `tsx`.)
* **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 of `PORT`, or `9001` if unset.
* `"${MINIFY:true}"` → the boolean `true`/`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.json` on disk.
When running in Docker, almost every setting is wired to an environment
variable in the shipped `settings.json.docker`. See the
[Docker page](/docker.md) 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:
```json
"trustProxy": true
```
This 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 `secure` flag is set on
cookies when the proxy terminates TLS (required for `SameSite=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 explicit
`publicURL` is 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
```yaml
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
```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](/admin/updates.md). The corresponding Docker env vars
(`MAIL_HOST`, `MAIL_FROM`, …) are listed on the [Docker page](/docker.md).
* **Database** — choose a backend with `dbType` / `dbSettings`. The
supported drivers and example settings are documented in
[`settings.json.template`](https://github.com/ether/etherpad-lite/blob/develop/settings.json.template),
and the Docker equivalents (`DB_TYPE`, `DB_HOST`, …) are listed on the
[Docker page](/docker.md). The on-disk keyspace layout is described in
[`doc/database.adoc`](https://github.com/ether/etherpad-lite/blob/develop/doc/database.adoc).
* **Metrics** — Etherpad exposes Prometheus-compatible metrics; see
[Stats](/stats.md).