Install paperless-ngx on Synology NAS

Yes — for 2 GB RAM, the key is to keep Paperless-ngx as lean as possible and avoid optional services like Tika and Gotenberg unless you truly need them. Paperless-ngx’s own docs recommend Docker, and Synology’s DS225+ ships with 2 GB RAM, so a minimal stack is the right approach here. docs.paperless-ngx

Minimal layout

Use only these containers:

  • paperless-ngx webserver
  • PostgreSQL
  • Redis

Skip these at first:

  • Tika.
  • Gotenberg.
  • Extra sidecars, OCR helpers, or file conversion services.

That matches the common minimal Paperless-ngx pattern and keeps memory use much lower than the fuller Synology setups that include office-conversion components. docs.paperless-ngx

Recommended limits

A conservative starting point on 2 GB:

  • Redis: 64 MB max.
  • PostgreSQL: 256 MB to 384 MB.
  • Paperless webserver: 512 MB to 768 MB.
  • Leave the rest for DSM, Synology Drive, and filesystem cache.

A real Synology example with a fuller stack showed Paperless itself around 904 MB idle, plus extra memory for Postgres, Redis, Tika, and Gotenberg, which is why trimming the stack matters on your NAS. deployn

Example Compose

services:
  broker:
    image: redis:7
    command: ["redis-server", "--appendonly", "no", "--maxmemory", "64mb", "--maxmemory-policy", "allkeys-lru"]
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: change_me
    volumes:
      - ./db:/var/lib/postgresql/data
    restart: unless-stopped
    mem_limit: 384m

  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    depends_on:
      - broker
      - db
    ports:
      - "8000:8000"
    environment:
      PAPERLESS_REDIS: redis://broker:6379
      PAPERLESS_DBHOST: db
      PAPERLESS_SECRET_KEY: change_me_too
      PAPERLESS_TIME_ZONE: Etc/UTC
      PAPERLESS_OCR_LANGUAGES: eng
      PAPERLESS_TASK_WORKERS: 1
      PAPERLESS_THREADS_PER_WORKER: 1
      PAPERLESS_EMAIL_TASK_CRON: disable
    volumes:
      - ./data:/usr/src/paperless/data
      - ./media:/usr/src/paperless/media
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume
    restart: unless-stopped
    mem_limit: 768m

Tuning tips

  • Set PAPERLESS_TASK_WORKERS=1 and PAPERLESS_THREADS_PER_WORKER=1 to reduce memory pressure. That’s a common way to make Paperless-ngx behave better on small systems. github
  • Use only one OCR language if possible.
  • Keep the consume folder small and process documents in batches.
  • If you also run Synology Drive, expect less headroom; watch DSM memory usage after startup.

If you want, I can turn this into a Synology Container Manager compose file with the exact folder paths and environment variables filled in.

Source: mariushosting.com

  1. Go to File Station and open the docker folder. Inside the docker folder, create one new folder and name it paperlessngx.
  2. Now create seven new folders inside the paperlessngx folder that you created previously and name them consume, data, db, export, media, redis, trash
  3. Log into Portainer using your username and password. On the left sidebar in Portainer, click on Home then Live connect.
  4. On the left sidebar in Portainer, click on Stacks then +Add stack.
  5. In the Name field type in paperlessngx.
  6. Use the following docker compose file:
services:
  redis:
    image: redis:8
    command:
      - /bin/sh
      - -c
      - redis-server --requirepass redispass
    container_name: PaperlessNGX-REDIS
    hostname: paper-redis
    security_opt:
      - no-new-privileges:true
    read_only: true
    user: 1026:101
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping || exit 1"]
    volumes:
      - /volume1/docker/paperlessngx/redis:/data:rw
    environment:
      TZ: Europe/Zurich
    restart: on-failure:5

  db:
    image: postgres:18
    container_name: PaperlessNGX-DB
    hostname: paper-db
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "pg_isready", "-q", "-d", "paperless", "-U", "paperlessuser"]
      timeout: 45s
      interval: 10s
      retries: 10
    volumes:
      - /volume1/docker/paperlessngx/db:/var/lib/postgresql:rw
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperlessuser
      POSTGRES_PASSWORD: paperlesspass
    restart: on-failure:5

  paperless:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: PaperlessNGX
    hostname: paperless-ngx
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
      interval: 30s
      timeout: 10s
      retries: 5
    ports:
      - 8777:8000
    volumes:
      - /volume1/docker/paperlessngx/data:/usr/src/paperless/data:rw
      - /volume1/docker/paperlessngx/media:/usr/src/paperless/media:rw
      - /volume1/docker/paperlessngx/export:/usr/src/paperless/export:rw
      - /volume1/docker/paperlessngx/consume:/usr/src/paperless/consume:rw
      - /volume1/docker/paperlessngx/trash:/usr/src/paperless/trash:rw
    environment:
      PAPERLESS_REDIS: redis://:redispass@paper-redis:6379
      PAPERLESS_DBENGINE: postgresql
      PAPERLESS_DBHOST: paper-db
      PAPERLESS_DBNAME: paperless
      PAPERLESS_DBUSER: paperlessuser
      PAPERLESS_DBPASS: paperlesspass
      PAPERLESS_EMPTY_TRASH_DIR: ../trash
      PAPERLESS_FILENAME_FORMAT: '{{ created_year }}/{{ correspondent }}/{{ document_type }}/{{ title }}'
      PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD: 6
      PAPERLESS_TASK_WORKERS: 1
      PAPERLESS_CONSUMER_POLLING_INTERVAL: 10
      USERMAP_UID: 1026
      USERMAP_GID: 101
      PAPERLESS_TIME_ZONE: Europe/Zurich
      PAPERLESS_SECRET_KEY: ***
      PAPERLESS_ADMIN_USER: adm_awl_paperless
      PAPERLESS_ADMIN_PASSWORD: ***
      PAPERLESS_URL: http://192.168.0.206
      PAPERLESS_CSRF_TRUSTED_ORIGINS: http://192.168.0.206
      PAPERLESS_OCR_LANGUAGE: deu+eng+ita+fra
    restart: on-failure:5
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

Version with databasus (tool to backup the PostgreSQL database within the docker):

services:
  redis:
    image: redis:8
    command:
      - /bin/sh
      - -c
      - redis-server --requirepass redispass
    container_name: PaperlessNGX-REDIS
    hostname: paper-redis
    security_opt:
      - no-new-privileges:true
    read_only: true
    user: 1026:101
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping || exit 1"]
    volumes:
      - /volume1/docker/paperlessngx/redis:/data:rw
    environment:
      TZ: Europe/Zurich
    restart: on-failure:5

  db:
    image: postgres:18
    container_name: PaperlessNGX-DB
    hostname: paper-db
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "pg_isready", "-q", "-d", "paperless", "-U", "paperlessuser"]
      timeout: 45s
      interval: 10s
      retries: 10
    volumes:
      - /volume1/docker/paperlessngx/db:/var/lib/postgresql:rw
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperlessuser
      POSTGRES_PASSWORD: paperlesspass
    restart: on-failure:5

  paperless:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: PaperlessNGX
    hostname: paperless-ngx
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
      interval: 30s
      timeout: 10s
      retries: 5
    ports:
      - 8777:8000
    volumes:
      - /volume1/docker/paperlessngx/data:/usr/src/paperless/data:rw
      - /volume1/docker/paperlessngx/media:/usr/src/paperless/media:rw
      - /volume1/docker/paperlessngx/export:/usr/src/paperless/export:rw
      - /volume1/docker/paperlessngx/consume:/usr/src/paperless/consume:rw
      - /volume1/docker/paperlessngx/trash:/usr/src/paperless/trash:rw
    environment:
      PAPERLESS_REDIS: redis://:redispass@paper-redis:6379
      PAPERLESS_DBENGINE: postgresql
      PAPERLESS_DBHOST: paper-db
      PAPERLESS_DBNAME: paperless
      PAPERLESS_DBUSER: paperlessuser
      PAPERLESS_DBPASS: paperlesspass
      PAPERLESS_EMPTY_TRASH_DIR: ../trash
      PAPERLESS_FILENAME_FORMAT: '{{ created_year }}/{{ correspondent }}/{{ document_type }}/{{ title }}'
      PAPERLESS_OCR_ROTATE_PAGES_THRESHOLD: 6
      PAPERLESS_TASK_WORKERS: 1
      PAPERLESS_CONSUMER_POLLING_INTERVAL: 10
      USERMAP_UID: 1026
      USERMAP_GID: 101
      PAPERLESS_TIME_ZONE: Europe/Zurich
      PAPERLESS_SECRET_KEY: ***
      PAPERLESS_ADMIN_USER: adm_awl_paperless
      PAPERLESS_ADMIN_PASSWORD: ***
      PAPERLESS_URL: http://192.168.0.206
      PAPERLESS_CSRF_TRUSTED_ORIGINS: http://192.168.0.206
      PAPERLESS_OCR_LANGUAGE: deu+eng+ita+fra
    restart: on-failure:5
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
  
  databasus:
    image: databasus/databasus:latest
    container_name: PaperlessNGX-Databasus
    healthcheck:
      test: timeout 10s bash -c ':> /dev/tcp/127.0.0.1/4005' || exit 1
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 90s  
    ports:
      - 4005:4005
    volumes:
      - /volume1/docker/databasus:/databasus-data:rw
    restart: on-failure:5

Submit a Comment

Your email address will not be published. Required fields are marked *