Self-hosting di Paperless-ngx su un VPS con Docker Compose
Distribuisci Paperless-ngx su un VPS con Docker Compose, PostgreSQL e Redis. Configura lingue e modalità OCR, regole di etichettatura automatica, consumo via email e una strategia di backup con sincronizzazione remota.
Paperless-ngx trasforma il tuo VPS in un archivio documentale con ricerca full-text. Scansioni o carichi documenti, Paperless-ngx li sottopone a OCR, li rende ricercabili e li classifica con tag e corrispondenti automatici. Funziona come stack Docker Compose con PostgreSQL, Redis e Gotenberg per la conversione dei documenti.
Questa guida distribuisce Paperless-ngx su un VPS che ha già Docker e un reverse proxy funzionanti. Se ti manca questa base, inizia con la nostra guida all'installazione dello stack base.
Di quali risorse ha bisogno Paperless-ngx su un VPS?
Paperless-ngx richiede un minimo di 2 GB di RAM, 4 GB consigliati. Lo stack esegue PostgreSQL, Redis, Gotenberg, Tika e il web server. A riposo, il consumo totale di memoria si aggira attorno agli 800 MB. Durante l'elaborazione OCR di PDF scansionati, l'utilizzo della CPU sale al 100% su un core e la RAM arriva a 1,5-2 GB. Lo spazio su disco è in media 5-10 MB per documento (originale + archivio + miniatura).
| Componente | RAM a riposo | RAM max (OCR) | Disco per 1.000 doc |
|---|---|---|---|
| Paperless-ngx webserver | ~300 MB | ~900 MB | 5-10 GB |
| PostgreSQL | ~50 MB | ~100 MB | ~500 MB |
| Redis | ~10 MB | ~10 MB | trascurabile |
| Gotenberg | ~150 MB | ~300 MB | — |
| Tika | ~250 MB | ~400 MB | — |
| Totale | ~760 MB | ~1.710 MB | 5-10 GB |
Pianifica lo spazio su disco in base al volume documentale. Una famiglia che scansiona 50 documenti al mese ha bisogno di circa 6 GB all'anno. Una piccola azienda con 500 documenti/mese dovrebbe prevedere 50-60 GB all'anno.
Come distribuisco Paperless-ngx con Docker Compose su un VPS?
Crea una directory per lo stack, genera i segreti e scrivi il file Compose. Ogni servizio ha un health check in modo che Docker riavvii automaticamente i container non funzionanti.
Creare la directory del progetto
mkdir -p /opt/paperless-ngx && cd /opt/paperless-ngx
Generare i segreti
Non usare mai password predefinite. Genera una password forte per il database e una chiave segreta Django:
openssl rand -base64 32 > .db_password
openssl rand -base64 48 > .secret_key
chmod 600 .db_password .secret_key
Questi file rimangono su disco con permessi ristretti. Il file Compose li legge all'avvio dei container.
Scrivere il file di ambiente
cat > .env << 'EOF'
COMPOSE_PROJECT_NAME=paperless
EOF
Scrivere il file 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:
Informazioni su questa configurazione:
- Le porte sono associate solo a 127.0.0.1. Il reverse proxy gestisce l'accesso pubblico via HTTPS. Esporre la porta 8000 su
0.0.0.0aggirerebbe TLS e il firewall. - I segreti usano Docker secrets (variabili con suffisso
_FILE). Le password non compaiono mai nell'output didocker inspecto nelle liste dei processi. USERMAP_UID/USERMAP_GIDmappano l'utente del container all'UID 1000 sull'host. I file creati nelle directory consume ed export appartengono a questo utente.PAPERLESS_URLdeve corrispondere al tuo dominio pubblico. Paperless-ngx lo usa per generare link di condivisione e URL nelle email. Sostituiscipaperless.example.comcon il tuo dominio reale.
Avviare lo stack
docker compose up -d
Attendi circa 60 secondi perché tutti i servizi si inizializzino. Controlla che ogni container sia sano:
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
Tutti e cinque i container devono mostrare (healthy). Se qualcuno mostra (health: starting), attendi altri 30 secondi. Se un container rimane (unhealthy), controlla i suoi log:
docker compose logs gotenberg --tail 20
Creare il superutente
docker compose exec webserver createsuperuser
Segui le richieste per nome utente, email e password. Questo è il tuo account amministratore per l'interfaccia web.
Accedere all'interfaccia web
Se il reverse proxy è configurato, apri https://paperless.example.com nel browser. Si carica la pagina di login di Paperless-ngx. Se stai ancora configurando il reverse proxy, testa localmente:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000
200
Quali lingue e modalità OCR devo configurare?
Paperless-ngx usa Tesseract per l'OCR. Lingua e modalità di elaborazione si configurano tramite variabili d'ambiente. I valori predefiniti funzionano per documenti in inglese, ma la maggior parte degli utenti deve modificarli.
Lingua OCR
Imposta PAPERLESS_OCR_LANGUAGE sul codice lingua Tesseract a tre lettere dei tuoi documenti. Per più lingue, uniscile con +:
# Lingua singola
PAPERLESS_OCR_LANGUAGE: ita
# Più lingue
PAPERLESS_OCR_LANGUAGE: ita+eng+deu
Codici lingua comuni: eng (inglese), deu (tedesco), fra (francese), spa (spagnolo), ita (italiano), nld (olandese), por (portoghese). L'elenco completo è nella documentazione di Tesseract.
L'immagine del container include la maggior parte dei pacchetti linguistici. Aggiungere più lingue a PAPERLESS_OCR_LANGUAGE aumenta il tempo di elaborazione OCR per pagina.
Modalità OCR
L'impostazione PAPERLESS_OCR_MODE controlla come Paperless-ngx gestisce i documenti che contengono già un livello di testo (frequente nei PDF creati digitalmente).
| Modalità | Comportamento | Quando usarla |
|---|---|---|
skip |
OCR solo sulle pagine senza testo. Crea sempre una copia d'archivio. | Predefinita. Ideale per input misti: PDF scansionati + digitali. |
skip_noarchive |
Come skip, ma senza creare l'archivio per documenti che hanno già testo. |
Vuoi risparmiare spazio disco sui PDF di origine digitale. |
redo |
Ri-OCR di tutte le pagine, sostituendo i livelli di testo esistenti. | Ricevi documenti con OCR di scarsa qualità. |
force |
Rasterizza il documento e applica OCR da zero. Distrugge il testo originale. | Ultima risorsa. Produce file più grandi con testo meno nitido. |
Per la maggior parte delle installazioni, skip è la scelta giusta. Gestisce sia documenti scansionati che digitali senza sprecare CPU a rielaborare documenti già ricercabili.
Se ricevi documenti da uno scanner che fa il proprio OCR (di scarsa qualità), imposta la modalità su redo. Tieni presente che redo è incompatibile con PAPERLESS_OCR_CLEAN e PAPERLESS_OCR_DESKEW.
Tipo di output OCR
PAPERLESS_OCR_OUTPUT_TYPE: pdfa (il valore predefinito) produce file PDF/A, lo standard di archiviazione. Sono autonomi e includono font incorporati. Mantieni questa impostazione a meno che tu non abbia un motivo specifico.
Dopo aver modificato qualsiasi impostazione OCR, riavvia il container webserver:
docker compose restart webserver
I documenti esistenti non vengono rielaborati. Per ripetere l'OCR su un documento, usa l'azione «Redo OCR» nell'interfaccia web.
Come funziona l'etichettatura automatica in Paperless-ngx?
Paperless-ngx supporta sei algoritmi di corrispondenza per tag, corrispondenti e tipi di documento. Quando arriva un documento, ogni tag confronta il contenuto con il proprio pattern. Se il pattern corrisponde, il tag viene applicato automaticamente.
| Algoritmo | Come funziona | Quando usarlo | Esempio |
|---|---|---|---|
| Any | Corrisponde se qualsiasi parola del campo di corrispondenza appare. | Categorie ampie. | invoice receipt bill |
| All | Corrisponde se tutte le parole appaiono (qualsiasi ordine). | Corrispondenza più precisa senza dipendenza dalla posizione. | electricity quarterly |
| Exact | Corrisponde alla frase esatta in ordine. | Nomi aziendali, numeri di conto. | Acme Corp |
| Regular Expression | Corrispondenza completa con espressione regolare. | Dati strutturati: date, numeri di riferimento, importi. | Invoice\s+#?\d{4,} |
| Fuzzy | Corrispondenza approssimativa con soglia configurabile. | Output OCR inconsistente, leggeri errori di ortografia. | Stadtwerke (corrisponde a Stadtwenke) |
| Auto | Classificatore ML che impara dalle tue assegnazioni manuali. | Dopo aver etichettato manualmente ~50+ documenti. | (impara dalle tue correzioni) |
Creare tag con regole di corrispondenza
Nell'interfaccia web, vai su Manage > Tags e crea un tag. Imposta l'algoritmo di corrispondenza e il campo Match. Alcuni esempi pratici:
- Tag: Invoice, Algoritmo:
Any, Match:invoice rechnung facture fattura(intercetta fatture in più lingue) - Tag: Bank, Algoritmo:
Regular Expression, Match:IBAN\s*[A-Z]{2}\d{2}(corrisponde a qualsiasi numero IBAN) - Tag: Medical, Algoritmo:
All, Match:patient diagnosis(richiede entrambe le parole) - Corrispondente: Electric Company, Algoritmo:
Exact, Match:Springfield Energy Inc
Addestrare il classificatore Auto
L'algoritmo Auto usa un classificatore di machine learning che Paperless-ngx riaddestra automaticamente. Per addestrarlo:
- Etichetta manualmente almeno 50 documenti nelle tue categorie
- Assicurati che questi documenti non siano nella tua casella di posta (il classificatore ignora i documenti della casella di posta)
- Il classificatore si riaddestra secondo un programma (predefinito: ogni ora tramite
document_create_classifier) - I nuovi documenti iniziano a ricevere assegnazioni automatiche
Puoi attivare un riaddestramento manuale:
docker compose exec webserver document_create_classifier
Il classificatore migliora con ogni tua correzione. Ogni correzione alimenta il ciclo di addestramento successivo.
Come configuro il consumo dei documenti in Paperless-ngx?
Paperless-ngx acquisisce documenti attraverso tre canali: caricamento manuale dall'interfaccia web, una cartella monitorata su disco e recupero email via IMAP.
Caricamento dall'interfaccia web
Trascina e rilascia i file nell'interfaccia web. Funziona immediatamente dopo l'installazione. Formati supportati: PDF, PNG, JPEG, TIFF e (con Tika abilitato) DOCX, XLSX, ODT e altri formati office.
Cartella monitorata (directory consume)
La directory ./consume mappata nel file Compose è monitorata da un watcher inotify. Inserisci un file e Paperless-ngx lo elabora in pochi secondi.
cp /tmp/scan-001.pdf /opt/paperless-ngx/consume/
Il file scompare dalla directory consume al termine dell'elaborazione. Per organizzare il consumo per tag, abilita l'etichettatura per sottodirectory:
PAPERLESS_CONSUMER_RECURSIVE: true
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS: true
Con questa impostazione, un file in consume/invoices/scan.pdf riceve automaticamente il tag invoices.
Consumo email (IMAP)
Il consumo email si configura interamente nell'interfaccia web sotto Manage > Mail. Aggiungi account email e regole.
Aggiungere un account email:
- Vai su Manage > Mail > Mail Accounts
- Imposta server IMAP, porta (993 per TLS), nome utente e password
- Indica la cartella da monitorare (es.
INBOX)
Aggiungere una regola email:
- Vai su Manage > Mail > Mail Rules
- Seleziona l'account email
- Scegli cosa consumare: solo gli allegati o l'intera email come PDF
- Imposta un'azione per le email elaborate: segna come letta, sposta in una cartella o elimina
- Opzionalmente assegna un tag, corrispondente o tipo di documento
Configurazione tipica: inoltra i documenti a un indirizzo email dedicato (es. scan@tuodominio.com), configura Paperless-ngx per monitorare quella casella e consumare gli allegati. Gli originali vengono spostati in una cartella IMAP «Archived» dopo l'elaborazione.
Come organizzo i percorsi di archiviazione e i nomi dei file?
Paperless-ngx archivia i documenti in due posizioni: il volume media contiene i file su disco, mentre PostgreSQL gestisce i metadati. La variabile PAPERLESS_FILENAME_FORMAT controlla come vengono nominati i file archiviati nella directory media.
Il file Compose sopra usa:
PAPERLESS_FILENAME_FORMAT: "{created_year}/{correspondent}/{title}"
Questo crea una struttura come:
media/documents/archive/
2026/
Springfield Energy Inc/
Electricity Bill January 2026.pdf
Dr. Smith/
Lab Results March 2026.pdf
Le variabili template disponibili includono {created_year}, {created_month}, {created_day}, {correspondent}, {document_type}, {title}, {tag_list} e {owner_username}. Se una variabile è vuota (nessun corrispondente assegnato), Paperless-ngx la sostituisce con none.
Dopo aver modificato il formato dei nomi, applicalo ai documenti esistenti:
docker compose exec webserver document_renamer
Qual è la migliore strategia di backup per Paperless-ngx?
Un backup funzionante copre il database PostgreSQL, i file dei documenti (originali + archivi + miniature) e i metadati di Paperless-ngx (tag, corrispondenti, regole di corrispondenza). L'esportatore di documenti cattura tutto in un formato portabile. Abbinalo a un dump del database per ripristini più rapidi del solo database.
Dump del database
docker compose exec db pg_dump -U paperless paperless | gzip > /opt/paperless-ngx/backups/db-$(date +%Y%m%d).sql.gz
Esportatore di documenti
L'esportatore crea uno snapshot completo: documenti, metadati e manifesto. È il metodo di backup canonico.
docker compose exec webserver document_exporter ../export -c -d
Il flag -c confronta i checksum (esporta solo i file modificati). Il flag -d elimina dall'export i file che non esistono più in Paperless-ngx. Insieme mantengono la directory di export come specchio dello stato attuale.
Automatizzare con cron
Crea uno script di backup:
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
Programmalo con cron (questo preserva le voci crontab esistenti):
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/paperless-ngx/backup.sh") | crontab -
Aggiunge un job notturno alle 03:00.
Sincronizzazione remota
La directory di export e i dump del database devono uscire dal server. Usa rsync o rclone per inviarli a una seconda posizione. Per un target compatibile S3:
rclone sync /opt/paperless-ngx/export remote:paperless-backup/export
rclone sync /opt/paperless-ngx/backups remote:paperless-backup/db-dumps
Per un altro server 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/
Per approfondire le strategie di backup dei volumi Docker, consulta la nostra guida al backup dei volumi Docker.
Come ripristino un backup di Paperless-ngx?
Il ripristino richiede un'installazione Paperless-ngx pulita. Avvia lo stack, poi importa.
Ripristino solo database (più veloce, per corruzione del database o migrazione):
gunzip < /opt/paperless-ngx/backups/db-20260320.sql.gz | \
docker compose exec -T db psql -U paperless paperless
Ripristino completo dall'esportatore (documenti, tag, corrispondenti, tutto):
docker compose exec webserver document_importer ../export
Esegui l'importatore su un database vuoto. Ricrea tutti i metadati e collega i file dalla directory di export.
Testa il ripristino periodicamente. Un backup mai ripristinato non è un backup.
Come rinforzare i container di Paperless-ngx?
Il file Compose sopra copre già le basi: file di segreti anziché password in chiaro, binding della porta su localhost e mappatura utente. Ecco ulteriori misure di hardening.
Rimuovere le capability non necessarie
Aggiungi opzioni di sicurezza al servizio webserver:
webserver:
# ... configurazione esistente ...
security_opt:
- no-new-privileges:true
Impedisce al processo del container di ottenere privilegi aggiuntivi tramite binari setuid.
Impostare limiti di risorse
Impedisci a un processo OCR fuori controllo di consumare tutte le risorse del server:
webserver:
# ... configurazione esistente ...
deploy:
resources:
limits:
memory: 2g
cpus: "2.0"
reservations:
memory: 512m
Per maggiori informazioni sui limiti di risorse, consulta la nostra guida sui limiti di risorse in Docker Compose.
Nascondere le informazioni sulla versione
Configura il reverse proxy per rimuovere l'header Server. Con Nginx:
server_tokens off;
Paperless-ngx stesso non espone la sua versione negli header HTTP, ma il reverse proxy potrebbe farlo.
Come aggiorno Paperless-ngx?
Scarica le immagini più recenti e ricrea i container. L'immagine Paperless-ngx esegue le migrazioni del database automaticamente all'avvio.
cd /opt/paperless-ngx
docker compose pull
docker compose up -d
Dopo l'aggiornamento, controlla i log per l'output delle migrazioni:
docker compose logs webserver --tail 30
Cerca righe come Applying documents.XXXX_migration_name... OK. Se le migrazioni falliscono, il container si ferma. Controlla le note di rilascio prima di aggiornamenti di versione maggiori.
Esegui sempre lo script di backup prima di aggiornare.
Qualcosa non funziona?
Il container rimane unhealthy: Controlla i log con docker compose logs <service> --tail 50. Cause frequenti: password PostgreSQL non corrispondente (rigenera .db_password e ricrea il volume del database), connessione Redis rifiutata (il broker non è ancora avviato).
L'OCR produce testo illeggibile: Lingua configurata errata. Controlla che PAPERLESS_OCR_LANGUAGE corrisponda ai tuoi documenti. Per documenti multilingue, aggiungi tutti i codici lingua separati da +.
I documenti non appaiono dopo il caricamento: Controlla il log del consumer:
docker compose logs webserver --tail 50 | grep -i consumer
Causa frequente: problemi di permessi. La directory consume deve essere scrivibile dall'UID 1000 (o dal valore di USERMAP_UID):
chown -R 1000:1000 /opt/paperless-ngx/consume
L'etichettatura automatica non funziona: Il classificatore ha bisogno di almeno ~50 documenti etichettati manualmente. Controlla se il classificatore è stato addestrato:
docker compose exec webserver document_create_classifier
Lo spazio su disco cresce velocemente: Controlla quali documenti sono i più grandi:
docker compose exec webserver document_sanity_checker
Rivedi anche la modalità OCR. La modalità force crea file d'archivio molto più grandi rispetto a skip.
Il consumo email non recupera messaggi: Controlla le credenziali IMAP nell'interfaccia web. Attiva un recupero manuale per vedere gli errori:
docker compose exec webserver mail_fetcher
Per altre guide di self-hosting, consulta la nostra guida su Immich per la gestione foto sullo stesso stack.
Copyright 2026 Virtua.Cloud. Tutti i diritti riservati. Questo contenuto è un'opera originale del team Virtua.Cloud. La riproduzione, ripubblicazione o redistribuzione senza autorizzazione scritta è vietata.
Pronto a provare?
Distribuisci il tuo server in pochi secondi. Linux, Windows o FreeBSD.
Vedi piani VPS