Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions content/docs/configuration/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ All flags and their corresponding environment variables:
| `--webhook-private-network-allowlist` | `MEMOS_WEBHOOK_PRIVATE_NETWORK_ALLOWLIST` | empty | Allowed private destinations: exact hostnames, IP addresses, or CIDRs |
| `--allow-private-webhooks` | `MEMOS_ALLOW_PRIVATE_WEBHOOKS` | `false` | Deprecated blanket exception for private webhook destinations |
| `--log-level` | `MEMOS_LOG_LEVEL` | `info` | Log verbosity (`debug`, `info`, `warn`, `error`) |
| `--rate-limit` | `MEMOS_RATE_LIMIT` | `true` | Request rate limiting for sign-in, signup, link previews, uploads, and writes; `false` turns every limit off (0.31+) |
| `--trusted-proxies` | `MEMOS_TRUSTED_PROXIES` | `private` | Proxies whose forwarding headers identify the client address: IPs, CIDRs, `private` (loopback and private ranges), or `none`; comma-separated (0.31+). See [Reverse Proxy](/docs/deploy/reverse-proxy#client-addresses-and-rate-limiting) |
| `--config-dir` | `MEMOS_CONFIG_DIR` | `/etc/memos/config` | Directory of [declarative configuration](/docs/configuration/declarative-configuration) files (26.10+) |
| `--config-apply` | `MEMOS_CONFIG_APPLY` | `startup` | `startup` applies the configuration directory before serving; `off` leaves it to `memos config apply` (26.10+) |

Expand Down Expand Up @@ -62,6 +64,7 @@ An explicit flag always wins over the environment variable for the same setting.

- select private or public access explicitly in the `ACCESS` instance setting
- set `MEMOS_INSTANCE_URL` to the canonical external URL when the app sits behind a proxy
- if the proxy is not on a loopback or private address, list it in `MEMOS_TRUSTED_PROXIES` so rate limits apply per client
- prefer explicit `MEMOS_DRIVER` and `MEMOS_DSN` when you are not using SQLite defaults
- allow only required private webhook destinations with `MEMOS_WEBHOOK_PRIVATE_NETWORK_ALLOWLIST`; leave the deprecated blanket option disabled
- keep secrets such as database credentials outside committed compose files
Expand Down
10 changes: 10 additions & 0 deletions content/docs/deploy/reverse-proxy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ For production, run Memos behind a reverse proxy such as Nginx, Caddy, or Traefi

In Memos 0.31, `MEMOS_INSTANCE_URL` and access policy are independent. A private instance can have a canonical URL behind a publicly reachable proxy. Select private or public access through the `ACCESS` instance setting; changing the URL does not change an existing access policy. The URL must be absolute HTTP(S), without credentials, a query, or a fragment.

## Client addresses and rate limiting

Memos rate-limits sign-in, signup, link previews, uploads, and writes by default (`MEMOS_RATE_LIMIT`, 0.31+). Limits for anonymous requests are counted per client address. Memos only reads that address from `X-Forwarded-For` or `X-Real-Ip` when the request comes from a trusted proxy, set with `MEMOS_TRUSTED_PROXIES`:

- the default, `private`, trusts loopback and private network ranges, which covers a proxy on the same host or Docker network
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
- list every proxy in the chain that is not on a private address, for example `MEMOS_TRUSTED_PROXIES=private,203.0.113.10` or a CIDR. This includes a CDN or load balancer in front of a local proxy: Memos walks `X-Forwarded-For` from the right and stops at the first untrusted address, so an unlisted public proxy becomes the "client" and every user behind it shares one limit
- if other hosts on your private network are untrusted, or Memos is reached through a NAT hop that shows a private address without rewriting headers, list the real proxy addresses instead of `private`, or set `none`. Otherwise a client can forge `X-Forwarded-For` to get a fresh limit
- configure the outermost proxy to replace any `X-Forwarded-For` and `X-Real-Ip` headers sent by clients instead of appending to them
- when the proxy connects through a Unix socket (`MEMOS_UNIX_SOCK`), there is no peer IP address, so Memos ignores the forwarding headers and all clients share one limit. Connect over TCP if you need per-client limits

## Why this matters

A reverse proxy gives you:
Expand Down