---
title: "Producción"
description: "Proxy inverso y cabeceras reenviadas, confianza en la IP del cliente, el invariante de instancia única y copias periódicas con el comando integrado."
---

# Producción

Esta página trata sobre llevar una instancia a producción: cómo colocarla detrás de un proxy inverso de la forma correcta, qué significa el invariante de instancia única y cómo respaldarla. Notarium se despliega como [un único contenedor](/docs/self-hosting/install/) — la configuración de producción se reduce a las tres cosas que siguen.

## Proxy inverso y cabeceras reenviadas

Delante de la aplicación colocas un proxy inverso (nginx, Caddy, Traefik) que termina el TLS y hace de proxy hacia el puerto de Notarium. El requisito clave: el proxy **debe** reenviar las cabeceras que describen la dirección externa.

> [!warning] El error de despliegue más frecuente
> El proxy inverso debe enviar `X-Forwarded-Host` (o dejar `Host` intacto) y `X-Forwarded-Proto: https`. De lo contrario, las mutaciones autenticadas por cookie desde la interfaz se rechazan como cross-origin — el síntoma es «lo veo, pero no puedo guardar». Reenviar `X-Forwarded-Proto` también hace falta para que la cookie de sesión reciba el flag `Secure`.

La razón es esta: la comprobación de Origin en las mutaciones contrasta el origen de la petición con la dirección que ve el navegador — y esa dirección llega en una cabecera reenviada. Las llamadas de agentes mediante un PAT de tipo Bearer están exentas de la comprobación (no llevan cookie, así que no hay superficie de CSRF). El proxy, por su parte, debe **sobrescribir** las cabeceras reenviadas con sus propios valores, en vez de dejar pasar tal cual las que manda el cliente.

Si activas la autorización OAuth para agentes, define `PUBLIC_BASE_URL` cuando la instancia se ejecute detrás del proxy (por ejemplo, `https://notes.example.com`) — una dirección externa estable para los metadatos de OAuth. Sin ella, la dirección se deriva de las cabeceras reenviadas. Consulta [Configuración](/docs/self-hosting/configuration/).

## Confianza en la IP del cliente

Un eje aparte del de la dirección es la **IP real del cliente**. Contra ella se cuentan dos límites: los intentos de inicio de sesión y la admisión de nuevos clientes OAuth. Detrás de un proxy todas las peticiones llegan desde la misma dirección, así que sin configuración explícita esos límites se contarían por proxy — es decir, contra todo el mundo a la vez.

El ajuste que lo gobierna es `TRUST_PROXY`: una lista separada por comas de las IP/CIDR de los proxies **inmediatos**.

```bash
# .env — pon la dirección de tu propio contenedor de proxy o de tu host
TRUST_PROXY=172.18.0.0/16
```

El valor por defecto seguro es dejar la variable sin definir: entonces `X-Forwarded-For` no influye en absoluto en los límites y ninguna cabecera puede falsificar la IP de otro. Defínela solo cuando conozcas con certeza la dirección de tu proxy, y mantén la lista lo más acotada posible.

> [!warning] No pongas aquí a «todo el mundo»
> Los valores booleanos, los recuentos de saltos, los rangos con nombre y los rangos que abarcan todas las direcciones (`/0`) se rechazan en el arranque. Confiar en todas las direcciones significaría que cualquier cliente podría asignarse una IP por cabecera y saltarse el límite de inicio de sesión.

Este ajuste no afecta al reenvío de `X-Forwarded-Host` ni de `X-Forwarded-Proto` — son ejes independientes, y el contrato de la sección anterior sigue igual.

## El invariante de instancia única

Notarium está construido para **un único proceso**. Dos piezas del estado de autenticación viven en la memoria del proceso:

- **límite de tasa de inicio de sesión** — los contadores de intentos;
- **el registro de sockets SSE** — el mecanismo mediante el cual revocar el acceso derriba al instante las conexiones activas.

Detrás de un balanceador de carga con varias instancias y sin almacenamiento compartido, estos mecanismos se rompen: un atacante multiplica el límite entre las instancias, y revocar el acceso en una instancia no cerrará una conexión SSE que se mantiene abierta en otra.

> [!note] Varias instancias detrás de un balanceador de carga
> Ambas piezas de estado viven en la memoria del proceso, así que detrás de un balanceador de carga con varias instancias y sin almacenamiento compartido estos mecanismos no funcionan. [Mover la base de datos de metadatos a Postgres](/docs/self-hosting/database/) te da estado compartido, pero eso por sí solo no basta para el escalado horizontal. Mantén una única instancia.

## Copias de seguridad

La copia de seguridad canónica es un **comando integrado de la imagen**, no una copia de los archivos hecha desde fuera: `notarium backup` arma un ZIP verificado y lo transmite (stream) mientras el servicio sigue en marcha.

```bash
docker compose exec -T notarium backup > notarium-$(date -u +%Y%m%dT%H%M%SZ).zip
docker compose exec -T notarium backup verify < notarium-20260731.zip
```

La verificación va dentro del trabajo periódico, no en un gesto puntual: no cambia nada y detecta la corrupción antes del día en que necesites el archivo de copia de seguridad. Para el trabajo en sí, una simple redirección no basta — toma la secuencia de publicación segura (archivo temporal → volcado a disco → enlace duro atómico) del runbook: [Copia de seguridad y restauración](/docs/self-hosting/backup/). Esa página cubre también la restauración en un volumen limpio y dónde el comando deja de ser aplicable.

> [!danger] No copies un `meta.db` en caliente
> `cp /data/meta.db`, o copiar el volumen con el servicio en marcha, no es una copia de seguridad: la base de datos de metadatos funciona en modo WAL, puede haber filas ya confirmadas esperando en `meta.db-wal`, y los archivos copiados uno a uno no son una instantánea de un mismo instante.

Qué entra en la copia de seguridad, y por qué:

| Qué | Función |
|---|---|
| `/data/spaces` | Tus archivos Markdown — la fuente de verdad. |
| `/data/meta.db` | La base de datos de metadatos (historial, usuarios, accesos) — **irrecuperable** a partir de los archivos. |
| `/data/jobs` | Artefactos y subidas de los trabajos de importación/exportación. |
| `/data/engine` | Los índices derivados del motor. No entran en el archivo de copia de seguridad: se reconstruyen a partir de los archivos. |

Si la base de datos de metadatos se ha movido a Postgres, o las notas viven fuera de la raíz de datos, el comando integrado termina con un error en lugar de producir un archivo parcial — respalda la base de datos y los directorios montados con las herramientas estándar de tu proveedor. Para saber exactamente qué guarda la base de datos de metadatos, consulta la página [Base de datos](/docs/self-hosting/database/).
