Guía de despliegue

Alojar Paperless-ngx en un VPS: guía completa 2026

Desplegar en un VPS Cloud →

Alojar Paperless-ngx en un VPS: guía completa 2026

Autoalojamiento17 min de lectura

Paperless-ngx transforma tus documentos escaneados en un archivo con búsqueda. Esta guía cubre la instalación, la configuración de OCR, los problemas habituales de fechas y tiempos de espera, y el procedimiento de migración de la rama 2.x a la serie 3.x con sus incompatibilidades conocidas.

Contenido· Por qué Paperless-ngx para tu GED self-hosted1/9
  1. 01Por qué Paperless-ngx para tu GED self-hosted
  2. 02Requisitos previos y elección del VPS
  3. 03Instalación con Docker Compose
  4. 04Configuración de OCR multilingüe
  5. 05Gestión de fechas de documentos: el problema y la solución
  6. 06Resolución de tiempos de espera en VPS de entrada
  7. 07Actualizar de 2.x a 3.x
  8. 08Copia de seguridad automática de Paperless-ngx
  9. 09Actualizaciones y mantenimiento

Por qué Paperless-ngx para tu GED self-hosted

Paperless-ngx es la bifurcación comunitaria más activa de Paperless — un sistema de gestión electrónica de documentos (GED) que indexa tus PDF e imágenes escaneadas, extrae el texto mediante OCR y te permite encontrarlos por palabra clave, fecha, corresponsal o etiqueta.

Frente a las alternativas (Mayan EDMS, OpenDocMan), Paperless-ngx destaca por su facilidad de instalación (Docker Compose en menos de 10 minutos), su interfaz web reactiva escrita en Angular y el soporte de OCR multilingüe mediante Tesseract.

El proyecto lo mantiene su comunidad y publica versiones con regularidad — comprueba la versión actual en la página de releases de GitHub antes de instalar.

Casos de uso típicos:
- Archivo de facturas de proveedores para una microempresa o una pyme
- Expediente médico personal o familiar (recetas, analíticas, informes)
- Gestión de los documentos de una asociación o de una comunidad de propietarios
- Archivo de contratos y arrendamientos para una agencia inmobiliaria

Requisitos previos y elección del VPS

Paperless-ngx consume más recursos de lo que parece, sobre todo al importar. El procesamiento OCR de un PDF de varias páginas carga intensamente la CPU — es la principal fuente de tiempos de espera agotados en las configuraciones pequeñas.

Configuración mínima recomendada:
- CPU: 2 vCPU (el OCR es monohilo por tarea, pero varias tareas pueden ejecutarse en paralelo)
- RAM: 2 GB mínimo; 4 GB para un uso cómodo
- Almacenamiento: SSD, 20 GB mínimo para la aplicación + prevé el espacio de tus documentos
- SO: Debian 12 o Ubuntu 22.04/24.04

Lo que provoca timeouts en los VPS pequeños: los PDF escaneados a alta resolución (300+ DPI) o con muchas páginas (50+) pueden superar el PAPERLESS_WORKER_TIMEOUT predeterminado (1.800 segundos). La sección dedicada más abajo cubre la resolución.

Instalación con Docker Compose

La instalación oficial recomendada usa Docker Compose con tres servicios: webserver (la aplicación), broker (la cola de tareas) y db (la base de datos PostgreSQL).

⚠️ Descarga los tres archivos, no solo el docker-compose.yml. El compose oficial declara env_file: docker-compose.env: los ajustes del contenedor se leen de ese archivo. El .env del directorio solo fija COMPOSE_PROJECT_NAME=paperless — es lo que da a los volúmenes su prefijo paperless_, y Docker Compose lo usa para sustituir variables, no lo inyecta en los contenedores. Escribir ahí tus PAPERLESS_* es el error silencioso más caro de esta página: el contenedor arranca, la interfaz responde, y ninguno de tus ajustes se aplica.

# Directorio de trabajo
mkdir -p /opt/paperless && cd /opt/paperless

# Los TRES archivos oficiales
BASE=https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose
curl -fsSL $BASE/docker-compose.postgres.yml -o docker-compose.yml
curl -fsSL $BASE/docker-compose.env          -o docker-compose.env
curl -fsSL $BASE/.env                        -o .env

# Genera la clave ANTES de escribir nada: un heredoc ENTRECOMILLADO (<<'EOF') no
# sustituye nada, la línea se escribiría literalmente y el «secreto» sería público.
SECRET_KEY=$(openssl rand -hex 32)

# La plantilla trae PAPERLESS_SECRET_KEY=change-me: se reemplaza, no se duplica.
sed -i "s|^PAPERLESS_SECRET_KEY=.*|PAPERLESS_SECRET_KEY=$SECRET_KEY|" docker-compose.env

# El resto de los ajustes van al MISMO archivo (heredoc sin comillas: $VAR se sustituye)
cat >> docker-compose.env <<EOF
PAPERLESS_URL=https://paperless.your-domain.com
PAPERLESS_TIME_ZONE=Europe/Madrid
PAPERLESS_OCR_LANGUAGE=fra+eng+ara
PAPERLESS_OCR_LANGUAGES=fra ara
EOF

docker compose pull
docker compose up -d

# Cuenta de administrador
docker compose exec webserver createsuperuser

PAPERLESS_DBENGINE, PAPERLESS_DBHOST y PAPERLESS_REDIS ya vienen en el bloque environment: del compose oficial: no los repitas en docker-compose.env. Si escribes tu propio compose, PAPERLESS_DBENGINE=postgresql es obligatorio desde la versión 3 (ver la sección de migración).

La interfaz es accesible en el puerto 8000 tras unos 60 segundos de arranque. Configura luego tu reverse proxy (nginx o Traefik) para exponer el servicio con TLS.

Configuración de OCR multilingüe

El OCR es el núcleo de Paperless-ngx. Su configuración determina la calidad de la indexación y la capacidad de volver a encontrar tus documentos.

Idiomas Tesseract disponibles: el parámetro PAPERLESS_OCR_LANGUAGE acepta códigos de idioma Tesseract separados por +. Para un fondo documental francés, árabe e inglés:

PAPERLESS_OCR_LANGUAGE=fra+ara+eng   # idiomas usados en el OCR
PAPERLESS_OCR_LANGUAGES=fra ara      # paquetes Tesseract a INSTALAR (separados por espacios)

⚠️ Ambas variables son necesarias, y es la trampa más cara de esta página. PAPERLESS_OCR_LANGUAGE vale eng por defecto y solo *elige* el idioma; para cualquier idioma que no venga en la imagen, la documentación obliga a rellenar también PAPERLESS_OCR_LANGUAGES (lista separada por espacios, no por +) en los despliegues Docker. Sin ella, el OCR vuelve silenciosamente al inglés: tus documentos quedan indexados, pero el texto francés y árabe es ilegible — y nada en la interfaz lo señala.

La imagen trae ya inglés, alemán, italiano, español y francés; solo lo demás hay que instalarlo. Ten presente además que Tesseract consume bastante más CPU con varios idiomas activados: declara únicamente lo que realmente escaneas.

Modo OCR: PAPERLESS_OCR_MODE controla cuándo se aplica el OCR. Existen cuatro valores — y skip, que se lee a menudo, no es uno de ellos:
- auto (predeterminado): Paperless mira con pdftotext si el PDF ya lleva texto; si hay suficiente, se salta el OCR para ese documento, y si no, se ejecuta con normalidad. Es la opción más segura sobre un fondo mixto
- redo: vuelve a pasar el OCR por todas las páginas e intenta sustituir las capas de texto existentes — útil cuando el escáner produjo un OCR mediocre. Puede fallar en algunos documentos (formularios); en ese caso se conserva el texto de origen
- force: rasteriza el documento, convierte el texto en imagen y coloca el OCR encima. Funciona en todas partes, pero el archivo engorda y el texto se ve menos nítido al ampliar
- off: nunca invoca el OCR; en los PDF el texto se extrae solo con pdftotext, y las imágenes salen sin texto

Para la mayoría de los usos, deja auto: evita reprocesar los PDF nativos (contratos, facturas generadas por un programa) sin que tengas que ajustar nada.

Gestión de fechas de documentos: el problema y la solución

La detección automática de fechas es una de las funciones más potentes de Paperless-ngx — y de las más frustrantes cuando no funciona. Por defecto, Paperless-ngx intenta detectar la fecha del documento en su contenido textual y en su nombre de archivo. Varias razones pueden llevar a una fecha incorrecta o ausente.

Problema 1: la fecha tiene un formato no reconocido. Paperless-ngx detecta los formatos habituales (DD/MM/YYYY, YYYY-MM-DD, etc.) pero puede fallar con formatos ambiguos (08/09/2025: ¿8 de septiembre o 9 de agosto?).

Solución: comprobar — y no «configurar» — el orden de lectura. PAPERLESS_DATE_ORDER ya vale DMY por defecto, es decir día, mes, año: ponerlo explícitamente no cambia nada y no resuelve ninguna ambigüedad. Este ajuste solo sirve para apartarse de él, por ejemplo con un fondo de documentos estadounidenses:

PAPERLESS_DATE_ORDER=MDY  # MM/DD/YYYY — ponlo SOLO si tus documentos están fechados así

Con un fondo mixto ningún orden global puede ser correcto: es el nombrado de los archivos (problema 3) lo que decide.

Problema 2: el documento tiene varias fechas y se elige la incorrecta. Por ejemplo, una factura que menciona la fecha del servicio Y la fecha de emisión — Paperless-ngx toma la primera que encuentra.

Solución: usar el campo de fecha manual de la interfaz web para corregir los documentos mal fechados, o configurar reglas de coincidencia (Matching rules) que asignen una fecha a partir del nombre del archivo.

Problema 3: se usa la fecha de creación del archivo en su lugar. Cuando no se encuentra ninguna fecha en el contenido, Paperless-ngx recurre a la fecha de modificación del archivo — algo que puede ser muy engañoso con documentos antiguos escaneados hace poco.

Solución: nombrar los archivos de importación con la fecha del documento (YYYY-MM-DD_nombre-documento.pdf) — Paperless-ngx detecta ese formato en el nombre del archivo antes de analizar el contenido.

Resolución de tiempos de espera en VPS de entrada

En un VPS con 1 o 2 vCPU, el procesamiento OCR de documentos voluminosos puede superar el tiempo de espera predeterminado y dejar el documento en estado «pendiente de procesar» indefinidamente.

Diagnóstico: revisa los logs del worker:

docker compose logs celery --tail=50

Las líneas SoftTimeLimitExceeded confirman un timeout.

Resolución — cuatro palancas:

1. Aumentar el tiempo de espera de las tareas:

PAPERLESS_WORKER_TIMEOUT=3600  # 1 hora (predeterminado: 1800 s)

⚠️ El nombre exacto importa: PAPERLESS_WORKER_TIMEOUT. Un ajuste mal escrito no lo rechaza Paperless — se ignora en silencio, y los timeouts continúan exactamente igual que antes, lo que se lee erróneamente como «el arreglo no funcionó».

2. Reducir la resolución de importación. Si escaneas tú mismo los documentos, 200 DPI bastan para un OCR de calidad — 300 DPI duplican el tiempo de procesamiento sin mejora perceptible en texto estándar.

3. Limitar el procesamiento paralelo:

PAPERLESS_TASK_WORKERS=1        # tareas en paralelo (predeterminado: 1)
PAPERLESS_THREADS_PER_WORKER=1  # páginas procesadas en paralelo dentro de UN documento

Si no se define, PAPERLESS_THREADS_PER_WORKER vale max(floor(n_núcleos / PAPERLESS_TASK_WORKERS), 1). La regla upstream que no hay que cruzar: el producto TASK_WORKERS × THREADS_PER_WORKER no debe superar el número de núcleos, o la instancia se vuelve extremadamente lenta. Muchos workers = muchos documentos en paralelo; muchos hilos = un documento grande procesado más rápido.
En un VPS de 2 vCPU, procesar dos documentos a la vez puede provocar timeouts que el mismo volumen tratado en secuencia evitaría.

4. Optimizar el preprocesado de PDF:

PAPERLESS_OCR_USER_ARGS={"optimize": 1, "pdfa-image-compression": "jpeg"}

Esto comprime las imágenes de los PDF antes del procesamiento, reduciendo la carga de memoria y de CPU.

Actualizar de 2.x a 3.x

La serie 3.x de Paperless-ngx introduce cambios estructurales que hacen obligatoria la migración en el lugar, y añade condiciones previas que no existían en la rama 2.x.

Requisito previo que se olvida: la actualización a la v3 solo está admitida desde la 2.20.15. Si corres una versión anterior, actualiza primero a 2.20.15 y solo después salta a la 3.x. Cambiar directamente la etiqueta de la imagen de una 2.14 a una 3.x no es un camino soportado.

La exportación/importación entre versiones (document_exporter seguido de document_importer en una instancia nueva) no está soportada: un export contiene una imagen exacta de la base de datos y no se importa en otra versión. En la práctica, document_importer avisa (Version mismatch: Currently 3.1.x, importing 2.20.15. Continuing, but import may fail.) y luego falla con KeyError: 'show_on_dashboard', un campo renombrado en la serie 3.x. La única vía segura es dejar que las migraciones se apliquen sobre la base existente.

Procedimiento recomendado:

1. Haz una copia de seguridad completa antes de nada (ver la sección dedicada más abajo).
2. Detén los servicios: docker compose down.
3. Revisa en docker-compose.env y en tu docker-compose.yml los tres ajustes que la v3 vuelve obligatorios o cambia (abajo).
4. Apunta la imagen del docker-compose.yml a la versión 3.x objetivo y relanza: docker compose up -d — las migraciones de Django se aplican solas al arrancar el webserver.
5. Monitoriza los logs: docker compose logs webserver --tail=100 — una migración que falla muestra el error y bloquea el arranque.

PAPERLESS_SECRET_KEY pasa a ser obligatoria. Antes existía una clave interna por defecto; en la v3 hay que declararla. Reutilizar el valor anterior conserva las sesiones y los tokens firmados; poner uno nuevo los invalida todos.

PAPERLESS_DBENGINE pasa a ser obligatoria con PostgreSQL o MariaDB. En la v2 el motor se deducía de la presencia de PAPERLESS_DBHOST; en la v3 hay que declararlo, y el valor por defecto es sqlite. Los valores aceptados son sqlite, postgresql y mariadb — nada más:

# v2 (PostgreSQL deducido de PAPERLESS_DBHOST)
PAPERLESS_DBHOST: db
# v3 (el motor debe ser explícito)
PAPERLESS_DBENGINE: postgresql
PAPERLESS_DBHOST: db

PAPERLESS_OCR_MODE=skip desaparece. Los valores skip y skip_noarchive se han eliminado, y una variable eliminada no se honra en silencio: se registra un aviso al arrancar. Conservar el comportamiento de la v2 exige repartir la intención entre dos ajustes ahora independientes:

# v2: saltar el OCR si ya hay texto, pero archivar siempre
PAPERLESS_OCR_MODE=skip
# v3: equivalente
PAPERLESS_OCR_MODE=auto
PAPERLESS_ARCHIVE_FILE_GENERATION=always

Incompatibilidad Redis → Valkey. Desde la v3 el compose oficial trae Valkey como broker (valkey/valkey:9-alpine), no Redis: no es una elección tuya, es lo que te llevas si reemplazas tu compose por la plantilla del proyecto. Si tu volumen de broker lo creó una versión reciente de Redis, Valkey se niega a cargarlo y el contenedor entra en bucle de reinicio con Can't handle RDB format version 15 (o 13, según el origen), mientras el webserver se queda esperando al broker. La solución es eliminar el volumen del broker antes de cambiar: solo contiene tareas en cola, ningún dato persistente crítico.

docker compose down
docker volume rm paperless_redisdata   # el prefijo viene de COMPOSE_PROJECT_NAME
docker compose up -d

El índice de búsqueda se reconstruye solo. La v3 sustituye Whoosh por Tantivy y el formato es incompatible: el índice se regenera desde cero en el primer arranque (el contenedor ejecuta document_index reindex --if-needed en cada inicio), lo que explica un primer arranque más lento. Si tras la actualización la consumición falla con Schema error: 'An index exists but the schema does not match.', fuerza una reconstrucción limpia con docker compose exec webserver document_index reindex --recreate. Ojo también con la sintaxis de búsqueda: note: pasa a notes.note: y custom_field: a custom_fields.value: — las vistas guardadas con prefijo explícito se migran solas, pero una búsqueda sin prefijo que antes encontraba una nota ya no lo hará.

Dos cambios de comportamiento que sorprenden. El historial de tareas se borra durante la actualización, y la v3 ya no rechaza los duplicados por defecto: si dependías de ese rechazo, reactívalo con PAPERLESS_CONSUMER_DELETE_DUPLICATES=true. Y detrás de un reverse proxy, el control de tasa del login cambió de forma de determinar la IP del cliente: si el inicio de sesión devuelve 403 Forbidden tras la actualización, declara la cadena con PAPERLESS_TRUSTED_PROXIES y, si hace falta, PAPERLESS_ALLAUTH_TRUSTED_PROXY_COUNT.

Sobre MariaDB. Sigue soportada (PAPERLESS_DBENGINE=mariadb), aunque el proyecto recomienda PostgreSQL. Los fallos de migración en Debian 12 que circulan por los foros venían de instalaciones bare-metal donde se descomprimió la nueva versión encima de la anterior: los archivos de migración obsoletos que quedan en disco provocan un NodeNotFoundError en manage.py migrate. El remedio es borrar el árbol de fuentes anterior (src/, static/) antes de desplegar, no tocar el motor de base de datos — y en un despliegue Docker como el de esta guía, ese escenario no se da.

Correo tras la actualización. El comando para forzar la recogida de correo es mail_fetcher, sin argumentos; procesa todas las cuentas y reglas configuradas:

docker compose exec webserver mail_fetcher

Si un flujo de correo deja de producir documentos después de actualizar, mira primero el error de la tarea en la interfaz: los casos reportados apuntaban al índice de búsqueda (Schema error, arriba), no a las credenciales. Comprueba después que la cuenta conserva sus permisos IMAP; si usas un token OAuth, marca la casilla que indica que la contraseña es en realidad un token.

Antes de cualquier actualización importante, prueba el procedimiento en una copia de tu entorno. Con Docker Compose, basta con copiar tu directorio /opt/paperless a un segundo VPS, apuntar un subdominio de prueba y aplicar allí la actualización. Después puedes validar que tus documentos, etiquetas y corresponsales están intactos antes de intervenir en producción.

Copia de seguridad automática de Paperless-ngx

Paperless-ngx gestiona dos tipos de datos críticos: la base de datos PostgreSQL (metadatos, etiquetas, corresponsales, reglas) y los archivos de documentos. Hay que respaldar los dos — uno sin el otro no restaura nada útil.

Script de copia de seguridad diaria:

#!/bin/bash
BACKUP_DIR="/backups/paperless/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Volcado PostgreSQL
docker compose exec -T db pg_dump -U paperless paperless \
  | gzip > "$BACKUP_DIR/db.sql.gz"

# Exportación nativa de Paperless (incluye configuración y documentos)
docker compose exec -T webserver document_exporter ../export
tar -czf "$BACKUP_DIR/export.tar.gz" /opt/paperless/export/

# Rotación — conservar 14 días
find /backups/paperless -maxdepth 1 -type d -mtime +14 -exec rm -rf {} +

echo "Copia de seguridad terminada: $BACKUP_DIR"

Programa este script en cron (0 3 * * * para las 3 de la madrugada) y verifica que las copias llegan a un almacenamiento externo al VPS (rsync hacia un bucket S3 o hacia otro servidor). El -T detrás de exec evita el error «the input device is not a TTY» cuando el script corre sin terminal.

Actualizaciones y mantenimiento

Paperless-ngx publica versiones con regularidad. La actualización es sencilla con Docker Compose:

# Traer la nueva imagen
docker compose pull

# Reiniciar los servicios (las migraciones de base de datos se aplican automáticamente)
docker compose up -d

# Comprobar que todo está bien
docker compose logs webserver --tail=20

Antes de cada actualización importante: lee el CHANGELOG en GitHub — las versiones mayores (v2.x → v3.x) pueden exigir pasos de migración adicionales, y a veces una versión intermedia obligatoria. La sección anterior detalla las incompatibilidades conocidas de la serie 3.x.

Monitorización: Paperless-ngx no expone un endpoint /metrics propio. Lo que existe es Flower, el monitor de tareas de Celery, que se activa definiendo PAPERLESS_ENABLE_FLOWER; es Flower quien exporta métricas aprovechables por Prometheus, además de mostrar las tareas en curso, en cola y terminadas. Es el sitio correcto para detectar un procesamiento que se detiene en silencio — el síntoma exacto de un timeout de OCR.

Digitaliza e indexa todos tus documentos

El VPS Cloud de ServOrbit ofrece la CPU, el almacenamiento y el entorno Docker listos para Paperless-ngx, su OCR Tesseract, PostgreSQL y Redis. Convierte tus pilas de papel en un archivo con búsqueda, con copia de seguridad y bajo tu control.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva