Auto-héberger Paperless-ngx sur un VPS avec Docker Compose
Déployez Paperless-ngx sur un VPS avec Docker Compose, PostgreSQL et Redis. Configurez les langues et modes OCR, les règles de classement automatique, la consommation par e-mail et une stratégie de sauvegarde avec synchronisation distante.
Paperless-ngx transforme votre VPS en archive documentaire interrogeable. Vous numérisez ou téléversez des documents, Paperless-ngx les passe à l'OCR, les rend consultables en texte intégral et les classe avec des tags et des correspondants automatiques. L'application tourne sous forme de stack Docker Compose avec PostgreSQL, Redis et Gotenberg pour la conversion de documents.
Ce guide déploie Paperless-ngx sur un VPS qui dispose déjà de Docker et d'un reverse proxy. Si vous n'avez pas encore cette base, commencez par notre guide d'installation de la stack de base.
De quelles ressources Paperless-ngx a-t-il besoin sur un VPS ?
Paperless-ngx nécessite 2 Go de RAM au minimum, 4 Go recommandés. La stack fait tourner PostgreSQL, Redis, Gotenberg, Tika et le serveur web. Au repos, la consommation mémoire totale se situe autour de 800 Mo. Pendant l'ingestion OCR de PDF numérisés, le CPU grimpe à 100 % sur un cœur et la RAM monte à 1,5-2 Go. L'espace disque moyen est de 5 à 10 Mo par document (original + archive + miniature).
| Composant | RAM au repos | RAM max (OCR) | Disque pour 1 000 docs |
|---|---|---|---|
| Paperless-ngx webserver | ~300 Mo | ~900 Mo | 5-10 Go |
| PostgreSQL | ~50 Mo | ~100 Mo | ~500 Mo |
| Redis | ~10 Mo | ~10 Mo | négligeable |
| Gotenberg | ~150 Mo | ~300 Mo | — |
| Tika | ~250 Mo | ~400 Mo | — |
| Total | ~760 Mo | ~1 710 Mo | 5-10 Go |
Prévoyez l'espace disque en fonction de votre volume documentaire. Un foyer numérisant 50 documents par mois a besoin d'environ 6 Go par an. Une petite entreprise traitant 500 documents/mois devrait prévoir 50 à 60 Go par an.
Comment déployer Paperless-ngx avec Docker Compose sur un VPS ?
Créez un répertoire pour la stack, générez les secrets et rédigez le fichier Compose. Chaque service dispose d'un health check pour que Docker redémarre automatiquement les conteneurs défaillants.
Créer le répertoire du projet
mkdir -p /opt/paperless-ngx && cd /opt/paperless-ngx
Générer les secrets
N'utilisez jamais les mots de passe par défaut. Générez un mot de passe solide pour la base de données et une clé secrète Django :
openssl rand -base64 32 > .db_password
openssl rand -base64 48 > .secret_key
chmod 600 .db_password .secret_key
Ces fichiers restent sur le disque avec des permissions restreintes. Le fichier Compose les lit au démarrage des conteneurs.
Écrire le fichier d'environnement
cat > .env << 'EOF'
COMPOSE_PROJECT_NAME=paperless
EOF
Écrire le fichier Compose
# docker-compose.yml
services:
broker:
image: docker.io/library/redis:8
restart: unless-stopped
volumes:
- redisdata:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 5s
retries: 3
db:
image: docker.io/library/postgres:18
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U paperless"]
interval: 30s
timeout: 5s
retries: 3
gotenberg:
image: docker.io/gotenberg/gotenberg:8
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-javascript=true"
- "--chromium-allow-list=file:///tmp/.*"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
tika:
image: docker.io/apache/tika:latest
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9998/"]
interval: 30s
timeout: 5s
retries: 3
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
broker:
condition: service_healthy
gotenberg:
condition: service_healthy
tika:
condition: service_healthy
ports:
- "127.0.0.1:8000:8000"
volumes:
- data:/usr/src/paperless/data
- media:/usr/src/paperless/media
- ./export:/usr/src/paperless/export
- ./consume:/usr/src/paperless/consume
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBUSER: paperless
PAPERLESS_DBPASS_FILE: /run/secrets/db_password
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_SECRET_KEY_FILE: /run/secrets/secret_key
PAPERLESS_OCR_LANGUAGE: eng
PAPERLESS_OCR_MODE: skip
PAPERLESS_OCR_OUTPUT_TYPE: pdfa
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{title}"
PAPERLESS_URL: https://paperless.example.com
USERMAP_UID: 1000
USERMAP_GID: 1000
secrets:
- db_password
- secret_key
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
secrets:
db_password:
file: .db_password
secret_key:
file: .secret_key
volumes:
data:
media:
pgdata:
redisdata:
À propos de cette configuration :
- Les ports sont liés à 127.0.0.1 uniquement. Votre reverse proxy gère l'accès public en HTTPS. Exposer le port 8000 sur
0.0.0.0contournerait le TLS et votre pare-feu. - Les secrets utilisent Docker secrets (variables avec le suffixe
_FILE). Les mots de passe n'apparaissent jamais dans la sortie dedocker inspectni dans la liste des processus. USERMAP_UID/USERMAP_GIDfont correspondre l'utilisateur du conteneur à l'UID 1000 sur l'hôte. Les fichiers créés dans les répertoires consume et export appartiennent à cet utilisateur.PAPERLESS_URLdoit correspondre à votre domaine public. Paperless-ngx l'utilise pour générer les liens de partage et les URL dans les e-mails. Remplacezpaperless.example.compar votre domaine réel.
Démarrer la stack
docker compose up -d
Attendez environ 60 secondes le temps que tous les services s'initialisent. Vérifiez que chaque conteneur est sain :
docker compose ps
NAME SERVICE STATUS PORTS
paperless-broker-1 broker running (healthy)
paperless-db-1 db running (healthy)
paperless-gotenberg-1 gotenberg running (healthy)
paperless-tika-1 tika running (healthy)
paperless-webserver-1 webserver running (healthy) 127.0.0.1:8000->8000/tcp
Les cinq conteneurs doivent afficher (healthy). Si l'un d'eux affiche (health: starting), patientez 30 secondes de plus. Si un conteneur reste (unhealthy), consultez ses logs :
docker compose logs gotenberg --tail 20
Créer le superutilisateur
docker compose exec webserver createsuperuser
Suivez les invites pour le nom d'utilisateur, l'e-mail et le mot de passe. C'est votre compte administrateur pour l'interface web.
Accéder à l'interface web
Si votre reverse proxy est configuré, ouvrez https://paperless.example.com dans un navigateur. La page de connexion de Paperless-ngx s'affiche. Si vous êtes encore en train de configurer le reverse proxy, testez localement :
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000
200
Quels langues et modes OCR configurer ?
Paperless-ngx utilise Tesseract pour l'OCR. Vous configurez la langue et le mode de traitement via des variables d'environnement. Les valeurs par défaut conviennent aux documents en anglais, mais la plupart des utilisateurs doivent les ajuster.
Langue OCR
Réglez PAPERLESS_OCR_LANGUAGE sur le code de langue Tesseract à trois lettres correspondant à vos documents. Pour plusieurs langues, séparez-les par + :
# Langue unique
PAPERLESS_OCR_LANGUAGE: deu
# Plusieurs langues
PAPERLESS_OCR_LANGUAGE: deu+eng+fra
Codes de langues courants : eng (anglais), deu (allemand), fra (français), spa (espagnol), ita (italien), nld (néerlandais), por (portugais). La liste complète se trouve dans la documentation Tesseract.
L'image du conteneur inclut la plupart des packs linguistiques. Ajouter des langues à PAPERLESS_OCR_LANGUAGE augmente le temps de traitement OCR par page.
Modes OCR
Le paramètre PAPERLESS_OCR_MODE contrôle la façon dont Paperless-ngx traite les documents qui contiennent déjà une couche de texte (fréquent avec les PDF créés numériquement).
| Mode | Comportement | Quand l'utiliser |
|---|---|---|
skip |
OCR uniquement les pages sans texte. Crée toujours une copie d'archive. | Par défaut. Idéal pour les entrées mixtes : PDF numérisés + numériques. |
skip_noarchive |
Comme skip, mais sans créer d'archive pour les documents qui ont déjà du texte. |
Vous souhaitez économiser de l'espace disque sur les PDF d'origine numérique. |
redo |
Re-OCR toutes les pages, en remplaçant les couches de texte existantes. | Vous recevez des documents avec un OCR de mauvaise qualité. |
force |
Rastérise le document et OCR depuis zéro. Détruit le texte original. | Dernier recours. Produit des fichiers plus volumineux avec un texte moins net. |
Pour la plupart des installations, skip est le bon choix. Il gère à la fois les documents numérisés et numériques sans gaspiller du CPU à re-traiter des documents déjà consultables.
Si vous recevez des documents d'un scanner qui fait son propre OCR (de mauvaise qualité), passez en mode redo pour de meilleurs résultats. Notez que redo est incompatible avec PAPERLESS_OCR_CLEAN et PAPERLESS_OCR_DESKEW.
Type de sortie OCR
PAPERLESS_OCR_OUTPUT_TYPE: pdfa (la valeur par défaut) produit des fichiers PDF/A, le standard d'archivage. Ils sont autonomes et incluent les polices embarquées. Conservez ce réglage sauf raison particulière.
Après toute modification des paramètres OCR, redémarrez le conteneur webserver :
docker compose restart webserver
Les documents existants ne sont pas re-traités. Pour relancer l'OCR sur un document, utilisez l'action « Redo OCR » dans l'interface web.
Comment fonctionne le classement automatique dans Paperless-ngx ?
Paperless-ngx propose six algorithmes de correspondance pour les tags, les correspondants et les types de documents. Quand un document arrive, chaque tag compare le contenu au motif défini. Si le motif correspond, le tag est appliqué automatiquement.
| Algorithme | Fonctionnement | Quand l'utiliser | Exemple |
|---|---|---|---|
| Any | Correspond si un seul mot du champ de correspondance apparaît. | Catégories larges. | invoice receipt bill |
| All | Correspond si tous les mots apparaissent (ordre indifférent). | Correspondance plus précise sans dépendance de position. | electricity quarterly |
| Exact | Correspond à la phrase exacte dans l'ordre. | Noms d'entreprises, numéros de compte. | Acme Corp |
| Regular Expression | Correspondance par expression régulière. | Données structurées : dates, numéros de référence, montants. | Invoice\s+#?\d{4,} |
| Fuzzy | Correspondance approximative avec un seuil configurable. | OCR incohérent, légères fautes d'orthographe. | Stadtwerke (correspond à Stadtwenke) |
| Auto | Classificateur ML qui apprend à partir de vos assignations manuelles. | Après environ 50 documents classés manuellement. | (apprend de vos corrections) |
Créer des tags avec des règles de correspondance
Dans l'interface web, allez dans Manage > Tags et créez un tag. Définissez l'algorithme de correspondance et le champ Match. Quelques exemples pratiques :
- Tag : Invoice, Algorithme :
Any, Match :invoice rechnung facture(attrape les factures en plusieurs langues) - Tag : Bank, Algorithme :
Regular Expression, Match :IBAN\s*[A-Z]{2}\d{2}(correspond à tout numéro IBAN) - Tag : Medical, Algorithme :
All, Match :patient diagnosis(exige les deux mots) - Correspondant : Electric Company, Algorithme :
Exact, Match :Springfield Energy Inc
Entraîner le classificateur Auto
L'algorithme Auto utilise un classificateur par apprentissage automatique que Paperless-ngx réentraîne automatiquement. Pour l'entraîner :
- Classez manuellement au moins 50 documents dans vos catégories
- Assurez-vous que ces documents ne sont pas dans votre boîte de réception (le classificateur ignore les documents de la boîte de réception)
- Le classificateur se réentraîne selon un calendrier (par défaut : toutes les heures via
document_create_classifier) - Les nouveaux documents commencent à recevoir des assignations automatiques
Vous pouvez déclencher un réentraînement manuel :
docker compose exec webserver document_create_classifier
Le classificateur s'améliore au fil de vos corrections. Chaque correction alimente le cycle d'entraînement suivant.
Comment configurer l'ingestion de documents dans Paperless-ngx ?
Paperless-ngx ingère les documents par trois canaux : le téléversement manuel via l'interface web, un dossier surveillé sur le disque et la récupération d'e-mails via IMAP.
Téléversement via l'interface web
Glissez-déposez des fichiers dans l'interface web. Cela fonctionne immédiatement après l'installation. Formats pris en charge : PDF, PNG, JPEG, TIFF et (avec Tika activé) DOCX, XLSX, ODT et autres formats bureautiques.
Dossier surveillé (répertoire consume)
Le répertoire ./consume déclaré dans le fichier Compose est surveillé par un watcher inotify. Déposez un fichier et Paperless-ngx le récupère en quelques secondes.
cp /tmp/scan-001.pdf /opt/paperless-ngx/consume/
Le fichier disparaît du répertoire consume une fois le traitement terminé. Pour organiser l'ingestion par tag, activez le classement par sous-répertoire :
PAPERLESS_CONSUMER_RECURSIVE: true
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS: true
Avec ce paramètre, un fichier placé dans consume/invoices/scan.pdf reçoit automatiquement le tag invoices.
Consommation par e-mail (IMAP)
La consommation par e-mail se configure entièrement dans l'interface web sous Manage > Mail. Vous ajoutez des comptes mail et des règles.
Ajouter un compte mail :
- Allez dans Manage > Mail > Mail Accounts
- Renseignez le serveur IMAP, le port (993 pour TLS), le nom d'utilisateur et le mot de passe
- Indiquez le dossier à surveiller (par ex.
INBOX)
Ajouter une règle mail :
- Allez dans Manage > Mail > Mail Rules
- Sélectionnez le compte mail
- Choisissez quoi consommer : les pièces jointes uniquement ou l'e-mail complet en PDF
- Définissez une action pour les e-mails traités : marquer comme lu, déplacer dans un dossier ou supprimer
- Vous pouvez aussi assigner un tag, un correspondant ou un type de document aux documents consommés
Configuration typique : redirigez les documents vers une adresse e-mail dédiée (par ex. scan@votredomaine.com), configurez Paperless-ngx pour surveiller cette boîte et consommer les pièces jointes. Les originaux sont déplacés dans un dossier IMAP « Archived » après traitement.
Comment organiser les chemins de stockage et les noms de fichiers ?
Paperless-ngx stocke les documents à deux endroits : le volume media contient les fichiers sur le disque, tandis que PostgreSQL gère les métadonnées. La variable PAPERLESS_FILENAME_FORMAT contrôle le nommage des fichiers archivés dans le répertoire media.
Le fichier Compose ci-dessus utilise :
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{title}"
Cela crée une structure comme :
media/documents/archive/
2026/
Springfield Energy Inc/
Electricity Bill January 2026.pdf
Dr. Smith/
Lab Results March 2026.pdf
Les variables de modèle disponibles incluent {created_year}, {created_month}, {created_day}, {correspondent}, {document_type}, {title}, {tag_list} et {owner_username}. Si une variable est vide (pas de correspondant assigné), Paperless-ngx la remplace par none.
Après avoir modifié le format de nommage, appliquez-le aux documents existants :
docker compose exec webserver document_renamer
Quelle stratégie de sauvegarde adopter pour Paperless-ngx ?
Une sauvegarde fonctionnelle couvre la base de données PostgreSQL, les fichiers de documents (originaux + archives + miniatures) et les métadonnées Paperless-ngx (tags, correspondants, règles de correspondance). L'exporteur de documents capture tout cela dans un format portable. Associez-le à un dump de la base pour des restaurations plus rapides de la base seule.
Dump de la base de données
docker compose exec db pg_dump -U paperless paperless | gzip > /opt/paperless-ngx/backups/db-$(date +%Y%m%d).sql.gz
Exporteur de documents
L'exporteur crée un instantané complet : documents, métadonnées et manifeste. C'est la méthode de sauvegarde canonique.
docker compose exec webserver document_exporter ../export -c -d
Le flag -c compare les sommes de contrôle (n'exporte que les fichiers modifiés). Le flag -d supprime de l'export les fichiers qui n'existent plus dans Paperless-ngx. Ensemble, ils maintiennent le répertoire d'export comme un miroir de l'état actuel.
Automatiser avec cron
Créez un script de sauvegarde :
cat > /opt/paperless-ngx/backup.sh << 'SCRIPT'
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/opt/paperless-ngx/backups"
EXPORT_DIR="/opt/paperless-ngx/export"
mkdir -p "$BACKUP_DIR"
# Database dump
docker compose -f /opt/paperless-ngx/docker-compose.yml exec -T db \
pg_dump -U paperless paperless | gzip > "$BACKUP_DIR/db-$(date +%Y%m%d).sql.gz"
# Document exporter
docker compose -f /opt/paperless-ngx/docker-compose.yml exec -T webserver \
document_exporter ../export -c -d
# Remove database dumps older than 30 days
find "$BACKUP_DIR" -name "db-*.sql.gz" -mtime +30 -delete
echo "[$(date -Is)] Backup completed" >> "$BACKUP_DIR/backup.log"
SCRIPT
chmod 700 /opt/paperless-ngx/backup.sh
Planifiez-le avec cron (ceci préserve les entrées crontab existantes) :
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/paperless-ngx/backup.sh") | crontab -
Cela ajoute une tâche nocturne à 03h00.
Synchronisation distante
Le répertoire d'export et les dumps de la base doivent quitter le serveur. Utilisez rsync ou rclone pour les pousser vers un second emplacement. Pour une cible compatible S3 :
rclone sync /opt/paperless-ngx/export remote:paperless-backup/export
rclone sync /opt/paperless-ngx/backups remote:paperless-backup/db-dumps
Pour un autre serveur via SSH :
rsync -az --delete /opt/paperless-ngx/export/ backup-server:/backups/paperless/export/
rsync -az /opt/paperless-ngx/backups/ backup-server:/backups/paperless/db-dumps/
Pour approfondir les stratégies de sauvegarde de volumes Docker, consultez notre guide sur la sauvegarde de volumes Docker.
Comment restaurer une sauvegarde Paperless-ngx ?
La restauration nécessite une installation Paperless-ngx fraîche. Lancez la stack, puis importez.
Restauration de la base uniquement (plus rapide, pour corruption de base ou migration) :
gunzip < /opt/paperless-ngx/backups/db-20260320.sql.gz | \
docker compose exec -T db psql -U paperless paperless
Restauration complète depuis l'exporteur (documents, tags, correspondants, tout) :
docker compose exec webserver document_importer ../export
Lancez l'importeur sur une base vide. Il recrée toutes les métadonnées et lie les fichiers depuis le répertoire d'export.
Testez votre restauration régulièrement. Une sauvegarde que vous n'avez jamais restaurée n'est pas une sauvegarde.
Comment renforcer la sécurité des conteneurs Paperless-ngx ?
Le fichier Compose ci-dessus gère déjà les bases : fichiers de secrets au lieu de mots de passe en clair, port lié à localhost et mappage utilisateur. Voici des mesures de renforcement supplémentaires.
Supprimer les capacités inutiles
Ajoutez des options de sécurité au service webserver :
webserver:
# ... configuration existante ...
security_opt:
- no-new-privileges:true
Cela empêche le processus du conteneur d'acquérir des privilèges supplémentaires via des binaires setuid.
Définir des limites de ressources
Empêchez un processus OCR incontrôlé de consommer toutes les ressources du serveur :
webserver:
# ... configuration existante ...
deploy:
resources:
limits:
memory: 2g
cpus: "2.0"
reservations:
memory: 512m
Pour en savoir plus sur les limites de ressources, consultez notre guide sur les limites de ressources Docker Compose.
Masquer les informations de version
Configurez votre reverse proxy pour supprimer l'en-tête Server. Avec Nginx :
server_tokens off;
Paperless-ngx lui-même n'expose pas sa version dans les en-têtes HTTP, mais votre reverse proxy pourrait le faire.
Comment mettre à jour Paperless-ngx ?
Récupérez les dernières images et recréez les conteneurs. L'image Paperless-ngx exécute les migrations de base de données automatiquement au démarrage.
cd /opt/paperless-ngx
docker compose pull
docker compose up -d
Après la mise à jour, vérifiez les logs pour la sortie des migrations :
docker compose logs webserver --tail 30
Cherchez des lignes comme Applying documents.XXXX_migration_name... OK. Si les migrations échouent, le conteneur s'arrête. Consultez les notes de version avant les montées de version majeures.
Exécutez toujours votre script de sauvegarde avant de mettre à jour.
Quelque chose ne fonctionne pas ?
Le conteneur reste unhealthy : Consultez les logs avec docker compose logs <service> --tail 50. Causes fréquentes : mot de passe PostgreSQL incorrect (régénérez .db_password et recréez le volume de base de données), connexion Redis refusée (le broker n'a pas encore démarré).
L'OCR produit du texte incohérent : Mauvaise langue configurée. Vérifiez que PAPERLESS_OCR_LANGUAGE correspond à vos documents. Pour les documents multilingues, ajoutez tous les codes de langue séparés par +.
Les documents n'apparaissent pas après le téléversement : Consultez le log du consumer :
docker compose logs webserver --tail 50 | grep -i consumer
Cause fréquente : problème de permissions. Le répertoire consume doit être accessible en écriture par l'UID 1000 (ou la valeur de USERMAP_UID) :
chown -R 1000:1000 /opt/paperless-ngx/consume
Le classement automatique ne fonctionne pas : Le classificateur a besoin d'au moins ~50 documents classés manuellement pour produire des résultats. Vérifiez si le classificateur a été entraîné :
docker compose exec webserver document_create_classifier
L'espace disque croît rapidement : Vérifiez quels documents sont les plus volumineux :
docker compose exec webserver document_sanity_checker
Revoyez aussi votre mode OCR. Le mode force crée des fichiers d'archive nettement plus volumineux que skip.
La consommation par e-mail ne récupère rien : Vérifiez les identifiants IMAP dans l'interface web. Déclenchez une récupération manuelle pour voir les erreurs :
docker compose exec webserver mail_fetcher
Pour d'autres guides d'auto-hébergement, consultez notre guide Immich pour la gestion de photos sur la même stack.
Copyright 2026 Virtua.Cloud. Tous droits réservés. Ce contenu est une création originale de l'équipe Virtua.Cloud. Toute reproduction, republication ou redistribution sans autorisation écrite est interdite.
Prêt à essayer ?
Déployez votre serveur en quelques secondes. Linux, Windows ou FreeBSD.
Voir les offres VPS