Running Containers on a Synology DS1821+: Install Paperless-ngx with Portainer

Running Containers on a Synology DS1821+: Install Paperless-ngx with Portainer

Introduction

If you’ve ever struggled with piles of receipts, contracts, or scanned documents, Paperless-ngx can help bring order to the chaos. It’s a powerful, self-hosted document management system that automatically organizes, indexes, and makes your files searchable.

In this guide, we’ll walk through installing Paperless-ngx on a Synology DS1821+ (or similar NAS) using Portainer and Docker Compose. By the end, you’ll have a paperless workflow that can scan, OCR, and archive documents securely on your NAS.


What You’ll Need

  • A Synology NAS with Docker and Portainer installed
  • Shared folders for persistent storage (e.g., /volume1/docker/paperless)
  • At least 2GB of free RAM for smooth performance
  • A scanner or a folder where digital PDFs/images are stored

Step 1: Prepare Storage Folders

First, create the necessary folders on your NAS to store data:

  1. Open File Station in DSM.
  2. Inside your docker shared folder, create:
    • paperless_data
    • paperless_media
    • paperless_consume

The consume folder is where you’ll drop new documents—Paperless-ngx will automatically import and process them.


Step 2: Create a New Stack in Portainer

  1. Log into Portainer (http://<NAS-IP>:9000).
  2. Click Stacks+ Add Stack.
  3. Name your stack: paperless.

Step 3: Add the Docker Compose File

Paste the following Docker Compose definition:

---
networks:
    internal:
        external: false

services:
    broker:
        container_name: paperless-redis
        image: redis:7
        # If you prefer to use version 6.0
        # image: redis:6.0
        networks:
            - internal
        volumes:
            # Change to your correct path(s)
            - /volume1/paperless/redis:/data
            # - /volume2/paperless/redis:/data
        restart: unless-stopped
        user: "1000:1000" # Your Paperless user/group IDs
        sysctls:
            - net.core.somaxconn=511
        cap_add:
            - SYS_RESOURCE
        deploy:
            resources:
                limits:
                    memory: 256M
        healthcheck:
            test: ["CMD", "redis-cli", "ping"]
            interval: 30s
            timeout: 5s
            retries: 3

    db:
        container_name: paperless-db
        image: postgres:16
        # Do not simply upgrade or downgrade, as the database will not load anymore.
        networks:
            - internal
        restart: unless-stopped
        volumes:
            # Enter the correct path here
            - /volume1/paperless/db:/var/lib/postgresql/data
        #  - /volume2/paperless/db:/var/lib/postgresql/data
        environment:
            POSTGRES_DB: paperless
            POSTGRES_USER: paperless
            POSTGRES_PASSWORD: PAPERLESSDB_PASS # Replace with your password
        deploy:
            resources:
                limits:
                    memory: 512M
        healthcheck:
            test: ["CMD", "pg_isready", "-U", "paperless"]
            interval: 30s
            timeout: 5s
            retries: 3
        logging:
            driver: "json-file"
            options:
                max-size: "10m"
                max-file: "5"

    webserver:
        container_name: paperless
#        image: ghcr.io/paperless-ngx/paperless-ngx:2.13
        image: ghcr.io/paperless-ngx/paperless-ngx:latest
        networks:
            # If the Proxy Manager is on the Synology, then the network from it should also be entered here, instead of opening a port.
            - internal
        restart: unless-stopped
        depends_on:
            - db
            - broker
        ports:
            # Delete this part if the Proxy Manager is on the Synology.
            # Otherwise, select a port here that is free.
            - 8010:8000
            # - 8011:8000
            # - 8012:8000
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:8000"]
            interval: 30s
            timeout: 10s
            retries: 5
        volumes:
            # Enter the correct paths here
            - /volume1/paperless/data:/usr/src/paperless/data
            - /volume1/paperless/media:/usr/src/paperless/media
            - /volume1/paperless/export:/usr/src/paperless/export
            - /volume1/homes/timw/paperless-Inbox:/usr/src/paperless/consume
        environment:
            SSL_CERT_DIR: /etc/ssl/certs/
#            PAPERLESS_REDIS: redis://broker:6379
            PAPERLESS_REDIS: redis://paperless-redis:6379
            PAPERLESS_DBHOST: db
            PAPERLESS_DBPASS: PAPERLESSDB_PASS # This is the password from above
            USERMAP_UID: 1000 # UserID for the docker user
            USERMAP_GID: 1000 # GroupID for the docker user
            PAPERLESS_OCR_LANGUAGES: eng deu
            # Enter a random key here if you want to make Paperless accessible from outside.
            PAPERLESS_SECRET_KEY: PAPERLESS_SECRET
            # Enter your own domain behind localhost here if you are using a proxy host, otherwise delete this environment variable.
            #PAPERLESS_ALLOWED_HOSTS: "localhost,paperless.domain.de"
            PAPERLESS_TIME_ZONE: Europe/London
            PAPERLESS_OCR_LANGUAGE: eng
            # Adjust here if you want a different folder structure
            PAPERLESS_FILENAME_FORMAT: "{{created_year}}/{{ created_month }}/{{correspondent}}/{{title}}"
            # Omit the next three lines if you do not want to use Tika/Gotenberg.
            PAPERLESS_TIKA_ENABLED: 1
            PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://paperless-gotenberg:3000/ #or http://gotenberg:3000/forms/libreoffice/convert#
            PAPERLESS_TIKA_ENDPOINT: http://paperless-tika:9998
            #PAPERLESS_URL: "https://paperless.domain.de" # Remove or adjust if not using a proxy
            PAPERLESS_EMAIL_PARSE_DEFAULT_LAYOUT: 3
        deploy:
            resources:
                limits:
                    memory: 2048M
        logging:
            driver: "json-file"
            options:
                max-size: "10m"
                max-file: "5"

    db-backup:
        container_name: paperless-db-backup
        # Possibly adjust the image to match the one above
        image: postgres:16
        volumes:
            # Enter the correct path here
            - /volume1/paperless/db-backup:/dump
            - /etc/localtime:/etc/localtime:ro
        environment:
            PGHOST: db
            PGDATABASE: paperless
            PGUSER: paperless
            PGPASSWORD: PAPERLESSDB_PASS # This is the password from above
            BACKUP_NUM_KEEP: 10
            BACKUP_FREQUENCY: 7d # Every 7 days, can be adjusted
        entrypoint: |
            bash -c 'bash -s <<EOF
            trap "break;exit" SIGHUP SIGINT SIGTERM
            sleep 2m
            while /bin/true; do
              pg_dump -Fc > /dump/dump_\`date +%d-%m-%Y"_"%H_%M_%S\`.psql
              (ls -t /dump/dump*.psql|head -n $$BACKUP_NUM_KEEP;ls /dump/dump*.psql)|sort|uniq -u|xargs rm -- {}
              sleep $$BACKUP_FREQUENCY
            done
            EOF'
        networks:
            - internal
        deploy:
            resources:
                limits:
                    memory: 256M

    # Omit this part if you do not want conversion of Office documents, emails.
    gotenberg:
        container_name: paperless-gotenberg
        image: gotenberg/gotenberg:8
        restart: unless-stopped
#        environment:
#            CHROMIUM_DISABLE_ROUTES: 1
        command:
            - "gotenberg"
            - "--chromium-disable-javascript=true"
            - "--chromium-allow-list=file:///tmp/.*"
            - "--api-timeout=600s"
            - "--libreoffice-start-timeout=300s"
            - "--libreoffice-restart-after=0"
        networks:
            - internal
        deploy:
            resources:
                limits:
                    memory: 512M
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
            interval: 30s
            timeout: 5s
            retries: 3

    tika:
        container_name: paperless-tika
        image: apache/tika:2.9.2.1
        restart: unless-stopped
        networks:
            - internal
        deploy:
            resources:
                limits:
                    memory: 512M

Notes:

  • Adjust /volume1/docker/... paths if your shared folder is elsewhere.
  • Update the PAPERLESS_DBPASS with a secure password.

Step 4: Deploy the Stack

  1. Scroll down and click Deploy the stack.
  2. Wait while the containers for Redis, PostgreSQL, and Paperless-ngx start up.
  3. In Portainer, verify all containers are running (paperless-web, paperless-db, paperless-redis).

Step 5: Access Paperless-ngx

Open your browser and go to:

http://<NAS-IP>:8000

  • Log in with the default credentials (admin/admin).
  • Immediately change the password under User Settings.

Step 6: Start Organizing

  • Drop scanned documents or PDFs into the consume folder (/volume1/docker/paperless_consume).
  • Paperless-ngx will OCR, tag, and archive them automatically.
  • Use the web UI to search, categorize, and download documents.

Optional Improvements

  • HTTPS Access: Use DSM’s built-in Reverse Proxy to secure Paperless with a domain and SSL certificate.
  • Automated Scans: Configure your scanner or phone app to save directly into the consume folder.
  • Link Paperless-ngx to firefly iii with Node Red.

Conclusion

By installing Paperless-ngx on your Synology NAS, you’ve taken the first step toward a fully digital, searchable, and organized archive of your documents. Combined with Synology’s storage reliability, Paperless-ngx makes going paperless secure and hassle-free.


About the author

Tim Wilkes is a UK-based security architect with over 15 years of experience in electronics, Linux, and Unix systems administration. Since 2021, he's been designing secure systems for a telecom company while indulging his passions for programming, automation, and 3D printing. Tim shares his projects, tinkering adventures, and tech insights here - partly as a personal log, and partly in the hopes that others will find them useful.

Want to connect or follow along?

LinkedIn: [phpsytems]
Twitter / X: [@timmehwimmy]
Mastodon: [@timmehwimmy@infosec.exchange]


If you've found a post helpful, consider supporting the blog - it's a part-time passion that your support helps keep alive.

⚠️ Disclaimer

This post may contain affiliate links. If you choose to purchase through them, I may earn a small commission at no extra cost to you. I only recommend items and services I’ve personally read or used and found valuable.

As an Amazon Associate I earn from qualifying purchases.