Administrator Guide
Administrator Guide
This guide covers deploying, configuring, and maintaining Paperless Vault.
Installation Requirements
System Requirements
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4+ cores |
| RAM | 4 GB | 8+ GB |
| Storage | 20 GB | 100+ GB SSD |
| Docker | 20.10+ | Latest |
| Docker Compose | 2.0+ | Latest |
Network Requirements
- Outbound HTTPS (443) for Cloudflare Tunnel
- Internal ports: PostgreSQL (5432), Redis (6379)
- External ports: 18000 (dev), 28000 (stage), 38000 (prod)
Deployment
Quick Start
# Clone the repository
git clone git@bitbucket.org:wilsonify/paperless-vault.git
cd paperless-vault
# Deploy development environment
cd deploy/01_dev
cp .env.example .env
# Edit .env with your settings
docker compose up -d
Environment Configuration
Each environment has its own .env file:
# Core Settings
PAPERLESS_SECRET_KEY=your-secret-key-here
PAPERLESS_ADMIN_USER=admin
PAPERLESS_ADMIN_PASSWORD=secure-password
# Database
POSTGRES_PASSWORD=database-password
# Cloudflare Tunnel
CLOUDFLARE_TUNNEL_TOKEN=your-tunnel-token
# Document Processing
PAPERLESS_OCR_LANGUAGE=eng
PAPERLESS_CONSUMER_POLLING=30
PAPERLESS_TIME_ZONE=America/New_York
# Tika & Gotenberg (Office document support)
PAPERLESS_TIKA_ENABLED=true
PAPERLESS_TIKA_ENDPOINT=http://tika:9998
PAPERLESS_TIKA_GOTENBERG_ENDPOINT=http://gotenberg:3000
Environment Variables Reference
Essential Settings
| Variable | Description | Default |
|---|---|---|
PAPERLESS_SECRET_KEY |
Django secret key (required) | - |
PAPERLESS_ADMIN_USER |
Initial admin username | admin |
PAPERLESS_ADMIN_PASSWORD |
Initial admin password | - |
PAPERLESS_URL |
Public URL for the instance | - |
Database Configuration
| Variable | Description | Default |
|---|---|---|
PAPERLESS_DBHOST |
PostgreSQL host | db |
PAPERLESS_DBPORT |
PostgreSQL port | 5432 |
PAPERLESS_DBNAME |
Database name | paperless |
PAPERLESS_DBUSER |
Database user | paperless |
PAPERLESS_DBPASS |
Database password | - |
OCR Settings
| Variable | Description | Default |
|---|---|---|
PAPERLESS_OCR_LANGUAGE |
OCR languages | eng |
PAPERLESS_OCR_MODE |
skip, redo, force | skip |
PAPERLESS_OCR_PAGES |
Max pages to OCR | 0 (all) |
PAPERLESS_OCR_OUTPUT_TYPE |
Output format | pdfa |
Consumer Settings
| Variable | Description | Default |
|---|---|---|
PAPERLESS_CONSUMER_POLLING |
Poll interval (seconds) | 30 |
PAPERLESS_CONSUMER_DELETE_DUPLICATES |
Delete duplicate files | false |
PAPERLESS_CONSUMER_RECURSIVE |
Watch subdirectories | false |
Service Architecture
Docker Services
services:
webserver: # Main Paperless application
db: # PostgreSQL database
redis: # Redis message broker
tunnel: # Cloudflare Tunnel
gotenberg: # Document conversion (Office → PDF)
tika: # Content extraction
Volume Mounts
| Volume | Purpose | Container Path |
|---|---|---|
| data | Application data | /usr/src/paperless/data |
| media | Document storage | /usr/src/paperless/media |
| consume | Import folder | /usr/src/paperless/consume |
| export | Export folder | /usr/src/paperless/export |
| pgdata | Database files | /var/lib/postgresql/data |
| redisdata | Redis persistence | /data |
Backup & Restore
Database Backup
# Create backup
docker compose exec db pg_dump -U paperless paperless > backup.sql
# With timestamp
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
docker compose exec db pg_dump -U paperless paperless > backup-${TIMESTAMP}.sql
Database Restore
# Stop the webserver first
docker compose stop webserver
# Restore database
docker compose exec -T db psql -U paperless -d postgres -c "DROP DATABASE IF EXISTS paperless;"
docker compose exec -T db psql -U paperless -d postgres -c "CREATE DATABASE paperless;"
docker compose exec -T db psql -U paperless paperless < backup.sql
# Restart webserver
docker compose start webserver
Media Backup
# Backup media files
tar -czvf media-backup.tar.gz ./media/
# Or use rsync for incremental backups
rsync -avz ./media/ /backup/location/media/
Full System Backup Script
#!/bin/bash
BACKUP_DIR="/backups/paperless"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "${BACKUP_DIR}/${TIMESTAMP}"
# Database backup
docker compose exec -T db pg_dump -U paperless paperless > "${BACKUP_DIR}/${TIMESTAMP}/database.sql"
# Media backup
tar -czvf "${BACKUP_DIR}/${TIMESTAMP}/media.tar.gz" ./media/
# Configuration backup
cp .env "${BACKUP_DIR}/${TIMESTAMP}/.env"
cp docker-compose.yml "${BACKUP_DIR}/${TIMESTAMP}/docker-compose.yml"
echo "Backup complete: ${BACKUP_DIR}/${TIMESTAMP}"
Environment Promotion
Dev → Stage
# From prod directory, create backup
cd deploy/03_prod
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
docker compose exec -T db pg_dump -U paperless paperless > ../prod-db-${TIMESTAMP}.sql
# Copy to stage
cd ../02_stage
docker compose stop webserver
# Restore database
docker compose exec -T db psql -U paperless -d postgres -c "DROP DATABASE IF EXISTS paperless;"
docker compose exec -T db psql -U paperless -d postgres -c "CREATE DATABASE paperless OWNER paperless;"
docker compose exec -T db psql -U paperless paperless < ../prod-db-${TIMESTAMP}.sql
# Sync media files
rsync -avz ../03_prod/media/ ./media/
# Start services
docker compose start webserver
Stage → Prod
Follow the same process, replacing source and destination directories.
Monitoring
Check Service Status
# View all services
docker compose ps
# Check logs
docker compose logs -f webserver
docker compose logs -f --tail=100 webserver
# Check specific service
docker compose logs gotenberg
docker compose logs tika
Health Checks
# Check Paperless
curl -I http://localhost:18000/api/
# Check Gotenberg
curl http://localhost:3000/health
# Check Tika
curl http://localhost:9998/tika
Resource Usage
# Container stats
docker stats
# Disk usage
docker system df
Troubleshooting
Common Issues
502 Bad Gateway
Cause: Webserver not running or unhealthy
# Check webserver status
docker compose ps webserver
# View logs
docker compose logs webserver
# Restart
docker compose restart webserver
Document Import Failures
Cause: Corrupt files, unsupported formats, or service issues
# Check consumer logs
docker compose logs webserver | grep -i consumer
# Check for Tika errors
docker compose logs tika
# Check for Gotenberg errors
docker compose logs gotenberg
OCR Not Working
Cause: Missing language packs or Tesseract issues
# Check OCR settings
docker compose exec webserver printenv | grep OCR
# Install additional language
# Add to Dockerfile: apt-get install tesseract-ocr-deu
Database Connection Errors
Cause: Database not ready or credentials mismatch
# Check database status
docker compose ps db
docker compose logs db
# Test connection
docker compose exec webserver python manage.py dbshell
Debug Mode
Enable detailed logging:
# In .env
PAPERLESS_DEBUG=true
PAPERLESS_LOGGING_LEVEL=DEBUG
Reset Admin Password
docker compose exec webserver python manage.py changepassword admin
Rebuild Index
docker compose exec webserver document_index reindex
Security Best Practices
Secrets Management
- Never commit
.envfiles to version control - Use strong, unique passwords for each environment
- Rotate
PAPERLESS_SECRET_KEYperiodically - Use different credentials for dev/stage/prod
Network Security
- Use Cloudflare Tunnel instead of exposing ports
- Enable Cloudflare Access for additional authentication
- Keep Docker and services updated
- Use internal networks for service communication
File Permissions
# Ensure proper ownership
chown -R 1000:1000 media/ data/ consume/
# Restrict permissions
chmod 700 media/ data/
chmod 750 consume/
Maintenance Tasks
Regular Maintenance
| Task | Frequency | Command |
|---|---|---|
| Backup database | Daily | pg_dump |
| Backup media | Weekly | rsync |
| Update containers | Monthly | docker compose pull |
| Prune Docker | Monthly | docker system prune |
| Check logs | Weekly | docker compose logs |
Update Procedure
# Pull latest images
docker compose pull
# Recreate containers
docker compose up -d
# Check logs for issues
docker compose logs -f
Cleanup Old Data
# Remove unused Docker resources
docker system prune -a
# Clean up old backups (keep last 30 days)
find /backups -type f -mtime +30 -delete
Cloudflare Tunnel Setup
Create Tunnel
- Go to Cloudflare Zero Trust Dashboard
- Navigate to Networks → Tunnels
- Create a new tunnel
- Copy the tunnel token
Configure Tunnel
Create config.yml:
tunnel: your-tunnel-id
credentials-file: /etc/cloudflared/credentials.json
ingress:
- hostname: paperless-dev.example.com
service: http://webserver:8000
- hostname: paperless-stage.example.com
service: http://webserver:8000
- hostname: paperless-prod.example.com
service: http://webserver:8000
- service: http_status:404
DNS Configuration
Cloudflare automatically creates DNS records when using tunnels. Verify:
- Go to DNS settings in Cloudflare
- Confirm CNAME records point to tunnel
- Enable proxy (orange cloud)
Quick Reference
Common Commands
# Start services
docker compose up -d
# Stop services
docker compose down
# View logs
docker compose logs -f
# Restart service
docker compose restart webserver
# Execute command in container
docker compose exec webserver python manage.py [command]
# Backup database
docker compose exec db pg_dump -U paperless paperless > backup.sql
# Restore database
docker compose exec -T db psql -U paperless paperless < backup.sql
Important Paths
| Path | Description |
|---|---|
/deploy/01_dev/ |
Development environment |
/deploy/02_stage/ |
Staging environment |
/deploy/03_prod/ |
Production environment |
./media/ |
Document storage |
./consume/ |
Import folder |
./export/ |
Export folder |