Paperless-ngx
![logo](../img/ppl-logo.png)
👋 Présentation
Paperless-ngx est une application libre, gratuite et auto-hébergeable qui permet de numériser et classer ses papiers sans prise de tête afin de pouvoir les retrouver facilement. Ce logiciel GED propose de nombreuses fonctionnalités comme l'apprentissage automatique lui permettant de classer les documents avec le bon correspondant par exemple.
Liste complète des fonctionnalités
Les briques logicielles suivantes seront utilisées pour l'installation de l'application :
- Docker pour faire tourner la stack (installé dans une VM GNU/Linux Debian 12 sur Proxmox VE).
- Nginx comme reverse-proxy.
- Cerbot avec le challenge DNS pour obtenir un certificat Let's Encrypt.
Configuration de Paperless-ngx
olivier@srv-docker:~$ sudo mkdir -p /srv/paperless-ngx/{redis,db,data,media,export,consume}
olivier@srv-docker:~$ sudo mkdir -p /srv/paperless-ngx/secrets/{paperless-ngx,postgresql}
olivier@srv-docker:~$ sudo chown -R /srv/paperless-ngx
olivier@srv-docker:~$ cd /srv/paperless-ngx
networks:
frontend:
backend:
secrets:
pgsql_password:
file: "./secrets/postgresql/POSTGRES_PASSWORD"
paperless_secret_key:
file: "./secrets/paperless-ngx/PAPERLESS_SECRET_KEY"
paperless_admin_password:
file: "./secrets/paperless-ngx/PAPERLESS_ADMIN_PASSWORD"
paperless_email_host_password:
file: "./secrets/paperless-ngx/PAPERLESS_EMAIL_HOST_PASSWORD"
services:
broker:
image: docker.io/library/redis:7
restart: unless-stopped
networks:
- backend
security_opt:
- no-new-privileges:true
volumes:
- /srv/paperless-ngx/redis:/data:rw
user: 1000:1000
db:
image: docker.io/library/postgres:16
restart: unless-stopped
networks:
- backend
security_opt:
- no-new-privileges:true
volumes:
- /srv/paperless-ngx/db:/var/lib/postgresql/data
secrets:
- "pgsql_password"
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD_FILE: /run/secrets/pgsql_password
user: 1000:1000
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on:
- db
- broker
- gotenberg
- tika
networks:
- backend
- frontend
ports:
- 8777:8000
security_opt:
- no-new-privileges:true
volumes:
# Données du conteneurs Docker
- /srv/paperless-ngx/data:/usr/src/paperless/data
# Dossier où seront stockés les fichiers
- /srv/paperless-ngx/media:/usr/src/paperless/media
# Dossier de destination des sauvegardes
- /srv/paperless-ngx/export:/usr/src/paperless/export
# Dossier banette où nous pouvons déposer des fichiers qui seront traités automatiquement par Paperless
- /srv/paperless-ngx/consume:/usr/src/paperless/consume
secrets:
- "pgsql_password"
- "paperless_secret_key"
- "paperless_admin_password"
- "paperless_socialaccount_providers"
- "paperless_email_host_password"
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
USERMAP_UID: 1000
USERMAP_GID: 1000
PAPERLESS_DBPASS_FILE: /run/secrets/pgsql_password
PAPERLESS_SECRET_KEY_FILE: /run/secrets/paperless_secret_key
PAPERLESS_TIME_ZONE: Europe/Paris
PAPERLESS_ADMIN_USER: ppladmin01
PAPERLESS_ADMIN_PASSWORD_FILE: /run/secrets/paperless_admin_password
PAPERLESS_URL: https://ged.mondomaine.tld
PAPERLESS_CSRF_TRUSTED_ORIGINS: https://ged.mondomaine.tld
PAPERLESS_ALLOWED_HOSTS: "localhost,ged.mondomaine.tld"
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{created}"
# Déclaration de la langue française pour la reconnaissance OCR
PAPERLESS_OCR_LANGUAGE: fra
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
# Options mail
PAPERLESS_EMAIL_HOST: mail.mondomaine.tld
PAPERLESS_EMAIL_PORT: 587
PAPERLESS_EMAIL_HOST_USER: paperless@mondomaine.tld
PAPERLESS_EMAIL_FROM: paperless@mondomaine.tld
PAPERLESS_EMAIL_HOST_PASSWORD_FILE: /run/secrets/paperless_email_host_password
PAPERLESS_EMAIL_USE_TLS: true
# Gotenberg est orienté vers la conversion et la génération de fichiers PDF
# à partir de divers formats de documents via une API REST.
gotenberg:
image: docker.io/gotenberg/gotenberg:7.10
restart: unless-stopped
networks:
- backend
security_opt:
- no-new-privileges:true
command:
- "gotenberg"
- "--chromium-disable-javascript=true"
- "--chromium-allow-list=file:///tmp/.*"
# Tika est principalement utilisé pour l'extraction de contenu et
# de métadonnées de divers types de fichiers (PDF, docx, HTML,...).
tika:
image: docker.io/apache/tika:latest
restart: unless-stopped
networks:
- backend
security_opt:
- no-new-privileges:true
On ne met aucun mot de passe dans ce fichier mais dans des fichiers séparés afin de les exploiter avec la fonctionnalité "secrets" de Docker.
Docker secrets
Un secret est toute donnée, telle qu'un mot de passe, un certificat ou une clé API, qui ne doit pas être transmise sur un réseau ou stockée en clair dans un Dockerfile ou dans le code source de votre application.
Docker Compose vous permet d'utiliser des secrets sans avoir à utiliser de variables d'environnement pour stocker des informations. Si vous injectez des mots de passe et des clés API en tant que variables d’environnement, vous risquez une exposition involontaire d’informations. Les services ne peuvent accéder aux secrets que lorsqu'ils sont explicitement accordés par un attribut secrets dans l'élément de niveau supérieur des services.
Les variables d'environnement sont souvent disponibles pour tous les processus et il peut être difficile d'en suivre l'accès. Ils peuvent également être imprimés dans des journaux lors du débogage d’erreurs à votre insu. L'utilisation de secrets atténue ces risques.
Nous allons créer dans un premier temps les secrets suivants :
- pgsql_password : mot de passe de l'utilisateur "paperless" pour PostgreSQL
- paperless_secret_key : Paperless l'utilise pour créer des jetons de session. Si vous exposez l'application sur Internet, vous devez changer cela, puisque le secret par défaut est connu.
- paperless_admin_password : mot de passe du compte admin (ppladmin01 dans cet exemple) créé lors de la première initialisation du conteneur.
- paperless_email_host_password : mot de passe du compte mail utilisé pour recevoir des notifications.
olivier@srv-docker:/srv/paperless-ngx$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > secrets/postgresql/POSTGRES_PASSWORD
olivier@srv-docker:/srv/paperless-ngx$ tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 > secrets/paperless-ngx/PAPERLESS_SECRET_KEY
Il vous reste ensuite à renseigner les mots de passe pour secrets/paperless-ngx/PAPERLESS_ADMIN_PASSWORD et secrets/paperless-ngx/PAPERLESS_EMAIL_HOST_PASSWORD. Personnellement j'utilise mon coffre-fort Vaultwarden pour générer et stocker ces mots de passe.
Configuration de Nginx
server {
listen 80;
server_name ged.mondomaine.tld;
if ($host = ged.mondomaine.tld) {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name ged.mondomaine.tld;
access_log /var/log/nginx/ged.access.log;
error_log /var/log/nginx/ged.error.log;
ssl_certificate /etc/letsencrypt/live/ged.mondomaine.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ged.mondomaine.tld/privkey.pem;
include /etc/nginx/ssl/options-ssl-nginx.conf;
ssl_dhparam /etc/nginx/ssl/ssl-dhparams.pem;
location / {
# Optionnel / Permet de limiter l'accès au réseau local
# allow 127.0.0.1;
# allow 192.168.1.0/24;
# deny all;
# Important pour uploader des documents
# Ici la taille des fichiers est limitée à 20 Mo
client_max_body_size 20M;
proxy_pass http://<IP_DU_SERVEUR_DOCKER>:8777/;
# These configuration options are required for WebSockets to work.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
add_header Referrer-Policy "strict-origin-when-cross-origin";
}
}
Vous pouvez lancer la stack applicative et relancer Nginx.
Utilisation basique de Paperless-ngx
Connectez-vous sur l'application "https://ged.mondomaine.tld" et authentifiez-vous avec le compte admin que vous avez défini plus haut et créé lors de l'instanciation de l'application (dans cet exemple ppladmin01).
![Authentification](../img/ppl-01.png)
Une fois authentifié, vous arrivez sur le dashboard vous proposant une visite. Ce dashboard permet d'afficher des vues personnelles filtrées sur des correspondants, des étiquettes, des types de document ou bien des dates.
Dans la partie administration, vous pouvez créer des utilisateurs et des groupes avec différents niveaux d'habiliation (accès complet, vue seulement...).
Avant d'uploader des documents, je vous conseille de créer en amont des correspondants (EDF, Trésor public,...), des étiquettes (État, Fournisseur...) et des types de documents (Facture, Bulletin de paie, Attestation...). Cependant vous pouvez tout de même créer tout cela à la volée lors du traitement d'un document.
Pour uploader un fichier, il vous suffit de vous rendre sur le tableau de bord et de cliquer sur le bouton "Parcourir les fichiers". Vous pouvez également déposer des fichiers dans /srv/paperless-ngx/consume et ils seront automatiquement détectés et traités par Paperless-ngx. Personnellement, j'ai poussé mes fichiers avec la commande "scp", mais on peut très bien créer un partage NFS, SFTP ou encore SMB si vous avez des clients Windows.
Lors des premiers upload de documents, vous allez devoir les classer manuellement. Mais assez rapidement, Paperless-ngx va apprendre et les classer automatiquement sans devoir préciser le correspondant par exemple. Et cela fonctionne aussi bien avec des fichiers générés au format PDF que des fichiers scannés.
Vous retrouverez l'ensemble de vos documents dans la partie Documents. À partir de là, vous pouvez filtrer les fichiers sur les options proposées (étiquettes, correspondant,...). Ces filtres peuvent être ensuite enregistrés dans des vues. Une fois le filtre défini, il suffit de cliquer sur "Vues" en haut à droite puis de l'enregistrer et choisir de l'afficher sur le dashboard par exemple.
![vue](../img/ppl-02.png)
On peut définir également des workflows. Pour le moment, j'ai créé un workflow d'assignation des documents au groupe dont ma femme et moi-même faisons parti.
Utilisation de l'option courriel
En plus de pouvoir envoyer directement les fichiers depuis le site web ou en passant par la banette, vous pouvez configurer un collecteur mail (comme sur GLPI pour ceux qui l'utilisent). Pour cela, il vous suffit de vous rendre sur l'option Courriel.
Ajoutez un compte de messagerie sur lequel Paperless-ngx ira chercher des documents par le biais du protocole IMAP. Une fois le compte paramétré et testé, nous allons définir une règle de courriel comme ci-dessous :
![Règle courriel](../img/ppl-03.png)
Le compte "Mail perso" est le nom du compte de messagerie créé juste avant. J'ai créé sur ma boite mail le dossier "Paperless" dans lequel je glisse les mails que je souhaite faire traiter par Paperless-ngx.
Le dossier "Paperless" utilisé étant dédié à Paperless-ngx, je n'ai pas précisé d'âge. Cette option peut cependant être utile si vous utilisez par défaut votre boite INBOX.
On peut créer différents filtres notamment sur l'adresse de l'expéditeur avec des règles d'affectation associées, ce qui impliquera de créer plusieurs règles mais vous évitera les erreurs de classement le temps de l'apprentissage.
Dans la partie Action, j'ai choisi l'option de déplacer vers le dossier spécifié "Paperless-archives" que j'ai créé sur ma boite mail et précisé dans la case "Paramètre d'action".
Une fois la règle déterminée, il vous suffit de patienter sachant que Paperless-ngx va consulter la boite mail toutes les 10 minutes.
Utilisation des applications mobiles
Sur iOS, j'utilise l'application gratuite Swift Paperless sous licence MIT qui permet d'accéder aux documents mais aussi de les scanner. L'application est "francisée" et fonctionne très bien. Lors du scan avec l'iphone, il est possible d'attribuer manuellement le correspondant, l'étiquette... avant l'envoi.
Sur Android, j'utilise l'application gratuite Paperless Mobile. Elle présente les mêmes fonctionnalités que Swift Paperless.
Authentification unique avec le protocole OIDC
Il est possible de configurer le SSO. Pour ma part, j'ai fait avec Authelia mais non documenté ici pour éviter d'alourdir cette doc. Cela fonctionne bien malgré un petit bug lors de la première connexion impliquant de se connecter en admin pour finaliser le profil de l'utilisateur connecté en SSO. Il faut dire que la fonctionnalité OIDC est récente. Il manque par exemple l'authentification d'application, ce qui est bloquant pour les applications sur smartphone.
Renforcement de la sécurité avec Crowdsec
Il existe une collection Crowdsec disponible sur le hub de ce dernier : Collection Crowdsec Paperless.
J'ai installé l'agent Crowdsec et la collection sur la machine hébergeant Paperless-ngx qui se connecte à mon serveur Crowdsec. Il suffit ensuite de configurer le fichier /etc/crowdsec/acquis.yaml pour lui indiquer le chemin du fichier de logs de Paperless-ngx.
Dans mon cas, j'ai préféré rendre accessible mon application uniquement à mon réseau local et VPN étant donné que je n'ai aucune raison d'exposer cette application sur Internet.
🏁 Conclusion
Cela faisait longtemps que je voulais me frotter à cette application mais j'avais quelques appréhensions. Elles ont vite été levées. Le logiciel est légé, intuitif et permet une rapide prise en main dans le cadre d'un usage personnel. Elle remplace dorénavant Nextcloud pour la gestion des papiers administratifs.
Elle peut être déployée dans un environnement professionnel mais demandera tout de même de définir en amont quelques règles de gestion et une matrice des droits. Cele demandera également quelques réglages plus fin en cas de traitement de volume important de documents.