Application Stacks Azure

Paperless-ngx on Ubuntu 24.04 on Azure User Guide

| Product: Paperless-ngx on Ubuntu 24.04 LTS on Azure

Overview

Paperless-ngx is the popular open source document management system: a self-hosted, searchable digital archive for your paperless office. Drop a scan or PDF into the consume directory and Paperless OCRs it, extracts the text, tags and indexes it, then archives a searchable original.

This image runs Paperless-ngx bare metal behind nginx. The granian application server serves the bundled Angular frontend on the loopback interface, a Celery worker and a Celery beat scheduler run the background task pipeline, and a consumer process watches an input folder for new documents. PostgreSQL provides the database and Redis provides the Celery task broker, all on the same VM and bound to the loopback interface only. The optical character recognition pipeline is built on tesseract, Ghostscript and OCRmyPDF, so scanned PDFs and images are made fully text searchable on import.

Paperless administrator and PostgreSQL credentials are generated on the first boot of every deployed VM. Two VMs launched from the same image never share passwords. A fresh Django secret key is generated at the same time. The initial administrator password and the PostgreSQL password are written to /root/paperless-ngx-credentials.txt with mode 0600 so that only the root user can read them. No documents and no shared credentials ship in the image.

The Paperless application code, the document media archive, the data directory, the consume folder and the search index all live under /opt/paperless on a dedicated Azure data disk separate from the operating system disk. The PostgreSQL data directory sits on its own data disk at /var/lib/postgresql. Both disks are captured into the image, are re-provisioned with every VM you deploy, and can be resized independently.

What is included:

  • Paperless-ngx 2.20 installed from the official release tarball into /opt/paperless
  • granian application server on loopback :8000, nginx reverse proxy on :80
  • PostgreSQL database on a dedicated 20 GiB data disk at /var/lib/postgresql
  • Application, media archive, consume folder and search index on a dedicated 60 GiB data disk at /opt/paperless
  • Redis task broker and the full tesseract OCR pipeline
  • Per-VM administrator, database and secret-key credentials generated at first boot, in a root-only file
  • Seven systemd units enabled and active
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended starting point: the OCR pipeline is processor and memory heavy, and document throughput benefits from both. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks your users will reach Paperless on.

Step 1: Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Paperless-ngx by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the two dedicated data disks on the Disks tab, then Review + create and Create. First boot initialisation takes approximately one to three minutes after the VM starts.

Step 2: Deploy from the Azure CLI

Replace the resource group, image reference, VNet and subnet with your own:

az vm create \
  --resource-group <your-rg> \
  --name paperless \
  --image <marketplace-image-urn> \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name paperless --port 80 --priority 1010

Step 3: Connect and Retrieve Initial Credentials

Connect over SSH with the key pair you supplied at deploy time:

ssh azureuser@<vm-public-ip>

The per-VM administrator and PostgreSQL passwords are written to a root-only file. Read it with sudo:

sudo cat /root/paperless-ngx-credentials.txt

The file lists the Paperless administrator username (admin) and password, the database name, user and password, and the URL to reach the web interface. Keep these somewhere safe.

Step 4: Confirm the Services Are Running

The image runs seven systemd units. Confirm they are all active:

systemctl is-active postgresql redis-server nginx \
  paperless-webserver paperless-task-queue paperless-scheduler paperless-consumer
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/accounts/login/

All seven units report active and the sign-in page returns 200.

Service status, sign-in page health check and the two dedicated data disks on a freshly deployed VM

Step 5: The Trusted Host Model

Django, the web framework Paperless is built on, only serves requests whose Host header it trusts, and only accepts form posts from trusted origins. On first boot the VM adds its own public and private addresses to PAPERLESS_URL and PAPERLESS_CSRF_TRUSTED_ORIGINS in /opt/paperless/paperless.conf, so the web interface is reachable immediately on the VM's launch address. If you put Paperless behind a custom domain or a load balancer, add that hostname too and restart the webserver:

sudo sed -i 's|^PAPERLESS_URL=.*|PAPERLESS_URL=https://paperless.your-domain.example|' /opt/paperless/paperless.conf
sudo systemctl restart paperless-webserver

Step 6: First Login to the Paperless Web Interface

Open a web browser and navigate to http://<vm-public-ip>/. Paperless presents its sign-in page. Enter the administrator username admin and the administrator password from /root/paperless-ngx-credentials.txt, then select Sign in.

The Paperless-ngx sign-in page, served on first boot with a per-VM administrator password and no manual setup

After signing in you reach the Dashboard, which shows saved views and statistics, and the Documents list, which is the heart of the platform: every document you import is OCRed, tagged and full text searchable here.

The Paperless-ngx dashboard after signing in as the administrator

The Documents view, the searchable document archive

For a production deployment rotate the administrator password that was generated on first boot: open My Profile from the user menu and change it there.

Step 7: Import and OCR Your First Document

Paperless imports documents by watching a consume directory. Anything you drop into /opt/paperless/consume is picked up by the consumer, OCRed, indexed and archived automatically. Copy a PDF or scanned image there with sudo cp <your-file>.pdf /opt/paperless/consume/ and make the paperless user the owner with sudo chown paperless:paperless /opt/paperless/consume/<your-file>.pdf.

Within a few seconds the consumer hands the file to a Celery worker, which runs OCR and indexing. The file then disappears from the consume directory and appears in the Documents list in the web interface, with its extracted text searchable. Check the pipeline's recent activity at any time:

sudo journalctl -u paperless-consumer -u paperless-task-queue --no-pager -n 20

Scanners and network shares can write straight into /opt/paperless/consume over NFS, SMB or scp, which is the usual way to feed a paperless office.

Step 8: The REST API

Paperless exposes a full REST API under /api/. It requires authentication; the sign-in page itself is open. You can verify both with curl: the unauthenticated request is rejected and the authenticated one succeeds:

# The sign-in page is served without authentication
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/accounts/login/
# Without credentials the API is rejected
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/api/documents/
# With the admin credentials it returns 200
curl -s -o /dev/null -w '%{http_code}\n' -u 'admin:<PAPERLESS_ADMIN_PASSWORD>' http://127.0.0.1/api/documents/

The per-VM credentials file and the REST API rejecting anonymous requests while accepting the administrator credentials

You can also issue a long lived API token from My Profile in the web interface and pass it as Authorization: Token <token> for automation and integrations.

Step 9: Tags, Correspondents and Document Types

Paperless organises documents with tags, correspondents (who a document is from), document types (invoice, contract, payslip) and storage paths. Create these from the left hand menu, then build matching rules so Paperless applies them automatically on import, for example tagging anything from a given correspondent, or matching documents whose OCR text contains a keyword. Saved views on the dashboard let you pin the searches you run most.

Step 10: Services and Operations

The paperless-webserver unit runs the granian application server on 127.0.0.1:8000; nginx reverse proxies port 80 to it. The paperless-task-queue and paperless-scheduler units are the Celery worker and beat scheduler; paperless-consumer watches the consume directory. Confirm the runtime versions:

/opt/paperless/.venv/bin/python -c 'import django; print("Django", django.get_version())'
ls -ld /opt/paperless/src /opt/paperless/.venv /opt/paperless/media

Runtime versions and the install layout under /opt/paperless

Run Paperless management commands as the paperless user with the configuration path set:

sudo -u paperless PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf \
  /opt/paperless/.venv/bin/python /opt/paperless/src/manage.py <command>

Step 11: The Dedicated Data Disks

The PostgreSQL database tier and the Paperless application + data tier each live on their own Azure data disk, separate from the OS disk and captured into the image, so every VM you deploy is provisioned with both:

findmnt -no SOURCE,SIZE,FSTYPE,TARGET /var/lib/postgresql
findmnt -no SOURCE,SIZE,FSTYPE,TARGET /opt/paperless

The database disk mounts at /var/lib/postgresql (20 GiB) and the data disk at /opt/paperless (60 GiB). Resize either independently in the Azure Portal as your archive grows, then grow the filesystem with sudo resize2fs on the corresponding device.

The two dedicated data disks: the PostgreSQL tier and the Paperless data tier, each independently resizable

Step 12: Enable HTTPS with Let's Encrypt

For any production deployment serve the site over HTTPS so session cookies and document transfers cannot be intercepted. The image ships with nginx, which certbot can configure automatically. The following assumes a DNS record pointing your fully qualified domain name at the VM's public IP address, an NSG rule allowing 443/tcp, and that you have added the domain to PAPERLESS_URL and PAPERLESS_CSRF_TRUSTED_ORIGINS (step 5):

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d paperless.your-domain.example \
  --non-interactive --agree-tos -m you@your-domain.example \
  --redirect

After certbot finishes, point Paperless at the HTTPS URL so it generates correct links and trusts the origin:

sudo sed -i 's|^PAPERLESS_URL=.*|PAPERLESS_URL=https://paperless.your-domain.example|' /opt/paperless/paperless.conf
sudo systemctl restart paperless-webserver

Step 13: Backups and Maintenance

Paperless has two things that must be backed up together: the PostgreSQL database and the document store under /opt/paperless/media. The cleanest backup is Paperless's own document exporter, which writes a self contained, importable archive:

sudo mkdir -p /var/backups/paperless && sudo chown paperless:paperless /var/backups/paperless
sudo -u paperless PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf \
  /opt/paperless/.venv/bin/python /opt/paperless/src/manage.py document_exporter /var/backups/paperless
sudo ls /var/backups/paperless

Ship the export directory to Azure Blob Storage or another object store. Because the data and database tiers are on their own data disks, you can also take coordinated Azure disk snapshots. The scheduler runs Paperless's periodic tasks, such as email checking and index optimisation, automatically.

For kernel and package updates, Ubuntu's unattended-upgrades is enabled, so security patches apply automatically. To update Paperless itself, follow the upgrade workflow in the official documentation at https://docs.paperless-ngx.com/.

Scaling Beyond a Single VM

For larger deployments decouple Paperless from the single VM pattern:

  • Move PostgreSQL to Azure Database for PostgreSQL and update the database host in /opt/paperless/paperless.conf
  • Move the document store to Azure Blob Storage mounted via BlobFuse, or to Azure Files
  • Move Redis to Azure Cache for Redis and point PAPERLESS_REDIS at the cache endpoint
  • Put the web tier behind Azure Application Gateway, add the gateway hostname to the trusted origins, and run the Celery workers on dedicated VMs

Each of these is documented in the official Paperless-ngx documentation at https://docs.paperless-ngx.com/.

Support

This image is backed by 24/7 cloudimg support. Guaranteed response within 24 hours, one hour average for critical issues. Contact support@cloudimg.co.uk for help with deployment, upgrades, OCR language configuration, consume-folder automation, TLS termination and database administration.

All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.