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: 768mTuning tips
- Set
PAPERLESS_TASK_WORKERS=1andPAPERLESS_THREADS_PER_WORKER=1to 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
- Go to File Station and open the docker folder. Inside the docker folder, create one new folder and name it paperlessngx.
- Now create seven new folders inside the paperlessngx folder that you created previously and name them consume, data, db, export, media, redis, trash.
- Log into Portainer using your username and password. On the left sidebar in Portainer, click on Home then Live connect.
- On the left sidebar in Portainer, click on Stacks then +Add stack.
- In the Name field type in paperlessngx.
- 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
