Self-hosted • Privacy-first • No tracking
Home / Homelab / Paperless-ngx Docker Setup: A Complete Homelab Guide for 2024
Homelab #docker#self-hosted#homelab#paperless-ngx#document-management ⏱ 11 min • 👁 6 • Aug 29, 2026

Paperless-ngx Docker Setup: A Complete Homelab Guide for 2024

Step-by-step guide to deploy Paperless-ngx with Docker Compose. Covers requirements, secure config, reverse proxy, backups, and troubleshooting.

AdSense — Top (970x90) • Responsive
Paperless-ngx Docker Setup: A Complete Homelab Guide for 2024

Introduction

Paperless-ngx is a powerful document management system designed to archive, index, and search your physical and digital documents. It turns a chaotic pile of PDFs, scans, and emails into a structured, OCR-searchable archive. For homelab enthusiasts, it represents a cornerstone of self-hosted productivity, eliminating the need for proprietary cloud services and keeping your data fully under your control.

This guide provides a complete, production-oriented walkthrough for deploying Paperless-ngx using Docker Compose. We will cover everything from hardware prerequisites to advanced security hardening. You will learn how to set up a robust stack with PostgreSQL and Redis, configure the document consumption directory, enable OCR for scanned images, and ensure your data is backed up safely.

We will also address common pitfalls encountered during installation, such as permission errors and database connection issues. By the end, you will have a fully functional Paperless-ngx instance accessible via a reverse proxy with SSL, ready to process your first batch of documents.

All commands and configurations provided are copy-paste ready. We use the latest image tag for Paperless-ngx, but you should always check the official release page before pinning a version. The same applies to the PostgreSQL and Redis images; we use specific major versions (e.g., 16, 7) known to be stable, but verify compatibility in the official documentation.

Prerequisites / Requirements

Before installing, ensure your host system meets the following requirements. These are typical values; actual usage depends on your document volume and complexity.

Component Minimum Recommended Notes
CPU 1 core 2-4 cores OCR and PDF indexing are CPU-intensive. More cores speed up batch processing.
RAM 2 GB 4-8 GB The stack (PostgreSQL, Redis, Paperless) idles at ~1-2 GB. OCR jobs can double this temporarily.
Storage 10 GB free 50+ GB free Documents, PostgreSQL data, and the media folder grow over time. Use a fast SSD for the consume and data volumes.
OS Linux (Debian/Ubuntu), macOS, Windows - Docker Desktop works on Windows/macOS, but Linux is the standard for homelab servers.
Software Docker Engine 20.10+ Docker Compose v2 Install Docker and the Compose plugin. See official Docker docs.
Network Stable LAN Static IP for the host Required for reverse proxy setup and persistent access.

Important: The consume directory is a bind mount. The user running Docker (usually root or a user in the docker group) must have read/write access. On Linux, if you run into permission errors, you may need to chown the directory to the container's UID (typically 1000:1000).

Step-by-Step Installation Guide

We will create a dedicated directory structure and a docker-compose.yml file. The stack uses three services: db (PostgreSQL), broker (Redis), and webserver (Paperless-ngx).

Step 1: Create the Project Directory

Open a terminal on your Docker host and create the main directory.

mkdir -p ~/paperless-ngx
cd ~/paperless-ngx

Step 2: Create Subdirectories for Persistent Data

Create the required folders for data, media, and consume. The consume folder is where you will drop documents for automatic ingestion.

mkdir -p data media consume export

Step 3: Set Correct Permissions on Bind Mounts

To avoid permission issues, set the ownership of these directories to the default container user (UID 1000).

sudo chown -R 1000:1000 data media consume export

Step 4: Create the Docker Compose File

Create a file named docker-compose.yml in the ~/paperless-ngx directory. Use your preferred text editor (nano, vim).

nano docker-compose.yml

Paste the following complete configuration. We use latest for the Paperless image. For PostgreSQL and Redis, we pin to stable major versions.

---
services:
  db:
    image: postgres:16
    restart: unless-stopped
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless-pass # Change this!
    networks:
      - paperless-net

  broker:
    image: redis:7
    restart: unless-stopped
    volumes:
      - ./data/redis:/data
    networks:
      - paperless-net

  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    restart: unless-stopped
    depends_on:
      - db
      - broker
    ports:
      - "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: paperless-pass # Must match POSTGRES_PASSWORD above
      PAPERLESS_DBNAME: paperless
      PAPERLESS_SECRET_KEY: change-me-to-a-long-random-string
      PAPERLESS_TIME_ZONE: UTC # Set to your local timezone, e.g., Europe/Berlin
      PAPERLESS_OCR_LANGUAGE: eng # Add more languages with +, e.g., eng+deu
      PAPERLESS_OCR_MODE: skip # Set to 'redo' if you want to force OCR on existing files
    networks:
      - paperless-net

networks:
  paperless-net:
    driver: bridge

Important: Change the POSTGRES_PASSWORD and PAPERLESS_DBPASS values to a strong, unique password. Also change PAPERLESS_SECRET_KEY to a long random string (e.g., openssl rand -hex 32). Never use the default values in production.

Step 5: Start the Stack

Bring up all services in detached mode.

docker compose up -d

This command pulls the images and starts the containers. The first start may take a few minutes as it initializes the database and runs migrations.

Step 6: Verify the Stack Status

Check if all containers are running correctly.

docker compose ps

You should see three services with Up status. If one is restarting, check the logs for errors (see troubleshooting section).

Step 7: Create an Admin User

Create a superuser account to access the web interface.

docker compose exec webserver python3 manage.py createsuperuser

Follow the prompts to set a username, email, and password.

Step 8: Access the Web Interface

Open your browser and navigate to http://localhost:8000. Log in with the credentials you just created. You should see the Paperless-ngx dashboard.

Step 9: Test Document Consumption

Place a PDF or image file into the ~/paperless-ngx/consume directory on your host. Wait a few seconds. The system will automatically pick it up, perform OCR, and index it. You can watch the logs to see the process.

docker compose logs -f webserver

You should see log entries about consuming the file and adding it to the index. After a few moments, the document appears in the web UI.

Step 10: Configure the Time Zone and OCR Language (Optional)

Edit the docker-compose.yml file to set your correct time zone and OCR languages. For example, for German and English:

PAPERLESS_TIME_ZONE: Europe/Berlin
PAPERLESS_OCR_LANGUAGE: eng+deu

After editing, apply the changes:

docker compose up -d

Step 11: Set Up a Reverse Proxy with SSL (Recommended)

For secure remote access, use a reverse proxy like Nginx Proxy Manager or Caddy. Here's a minimal Caddy example that automatically obtains SSL certificates.

Create a Caddyfile in a separate directory:

papers.yourdomain.com {
    reverse_proxy 127.0.0.1:8000
}

Run Caddy with Docker:

docker run -d --name caddy \
  -p 80:80 -p 443:443 \
  -v $PWD/Caddyfile:/etc/caddy/Caddyfile \
  -v caddy_data:/data \
  -v caddy_config:/config \
  caddy:latest

Replace papers.yourdomain.com with your actual domain. Ensure your DNS points to your homelab IP.

Step 12: Final Verification and Post-Installation Checks

  • Verify the reverse proxy works by visiting https://papers.yourdomain.com.
  • Check the Paperless logs for any warnings.
  • Ensure the consume directory is accessible by your scanner or mobile app (e.g., Paperless-ngx mobile app can upload directly).
  • Run a manual backup of the data and media directories to an external drive or NAS.

Advanced Configuration and Optimization

Reverse Proxy and SSL

Using a reverse proxy is essential for exposing Paperless-ngx securely. We recommend Caddy for automatic HTTPS or Nginx Proxy Manager for a GUI-based approach. Key configuration points:

  • Set PAPERLESS_URL environment variable to your external URL to ensure correct links in emails and the web UI.
  • Enable WebSocket support if you plan to use the live document feed (not critical for standard use).

Backup Strategy

Backing up Paperless-ngx is straightforward. You need to back up two things: the PostgreSQL database and the media files (which include originals and thumbnails).

Database Backup: Use pg_dump inside the db container.

docker compose exec db pg_dump -U paperless paperless > backup.sql

Media Backup: Simply copy the media directory to your backup location.

rsync -av ~/paperless-ngx/media /path/to/backup/location

For a complete backup, also include the data directory (contains the SQLite database if you didn't use PostgreSQL, but we do, so it's mostly cache). Automate this with a cron job.

Performance Tuning

  • OCR Threads: Set PAPERLESS_OCR_THREADS to the number of CPU cores you have. This speeds up batch OCR.
  • PostgreSQL Tuning: For large libraries, adjust shared_buffers and effective_cache_size in a custom postgresql.conf. This is optional for most homelabs.
  • Redis: The default Redis configuration is sufficient for a single Paperless instance.

Optional Hardening

Warning: The following settings are advanced. They are not guaranteed to work with all applications and may break container functionality if applied blindly. Test thoroughly in a staging environment.

To run the Paperless webserver with read-only root filesystem and drop all capabilities, add these lines to the webserver service:

  webserver:
    ...
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL

With read_only: true, the container cannot write to its own filesystem. The tmpfs mount provides a writable /tmp. The cap_drop: ALL removes all Linux capabilities. You must ensure the data, media, export, and consume volumes are writable (they are external volumes, so they are fine).

Note: This configuration is stricter than the default and may cause issues with certain Paperless features that write to the container layer (e.g., the built-in upgrade process). If you encounter errors, revert to the default configuration.

Troubleshooting Common Issues

Issue Likely Cause Solution
Permission denied when consuming files The consume directory is not owned by UID 1000. Run sudo chown -R 1000:1000 consume on the host.
Could not connect to the database The PAPERLESS_DBPASS does not match POSTGRES_PASSWORD. Check the environment variables in docker-compose.yml and ensure they match. Then run docker compose up -d to recreate.
redis.exceptions.ConnectionError The broker container is not running or the network is misconfigured. Run docker compose ps to check if broker is up. If not, check logs with docker compose logs broker. Ensure the PAPERLESS_REDIS URL is correct.
OCR does not process images PAPERLESS_OCR_MODE is set to skip. Change to redo or force in docker-compose.yml and restart.
Document consumption is very slow The CPU is underpowered or the consume directory is on a slow disk. Check docker compose logs for CPU usage. Consider adding more cores or moving the consume directory to an SSD.
Web UI shows 500 Internal Server Error The PAPERLESS_SECRET_KEY is not set or is too short. Generate a new key with openssl rand -hex 32 and set it in the environment. Restart the stack.
Can't access the web UI from another device Firewall is blocking port 8000. Open port 8000 in your firewall (e.g., ufw allow 8000). If using a reverse proxy, forward ports 80/443 instead.

Conclusion and FAQ

You now have a fully functional Paperless-ngx instance running on Docker. The combination of PostgreSQL, Redis, and the Paperless webserver provides a scalable and reliable document management system. By using a reverse proxy, you have secured remote access, and with a proper backup strategy, your documents are safe.

Remember that the latest tag is not a version. Always check the official release page before pinning a version. The configuration provided here is a solid baseline; adjust it to your specific hardware and document volume.

FAQ

Q1: How do I update Paperless-ngx to a new release?

To update, pull the new image and recreate the containers. Run docker compose pull webserver followed by docker compose up -d. The system will run database migrations automatically. Always back up your database and media before updating.

Q2: Can I use SQLite instead of PostgreSQL?

Yes, Paperless-ngx supports SQLite. However, PostgreSQL is recommended for production use, especially with multiple concurrent users or large document volumes. To use SQLite, remove the db service and set PAPERLESS_DBENGINE: sqlite in the webserver environment.

Q3: How do I add OCR support for multiple languages?

Set the PAPERLESS_OCR_LANGUAGE environment variable to a plus-separated list of language codes. For example, eng+deu+fra. The system will download the required language data on startup. Ensure you have sufficient storage for the language packs.

Q4: What is the best way to ingest documents from a scanner?

The simplest way is to configure your scanner to save files directly to the consume directory on your homelab via SMB or NFS. Alternatively, use the Paperless-ngx mobile app for iOS/Android, which can upload documents directly to the server via the API.

Q5: How do I move the installation to a new server?

Stop the stack, back up the entire ~/paperless-ngx directory (including data, media, export, and consume), and copy it to the new server. Then run docker compose up -d on the new host. The system will detect the existing database and media and resume normal operation. Ensure the new server has the same directory paths or update the volume mounts accordingly.

⚠️ Content disclosure: This article was AI-assisted. Versions and commands can change quickly in the self-hosted world — always verify against the official documentation before running anything in production.
AdSense — In-article (responsive)

Related Guides