Paperless-ngx
Videos
Overview: Paperless-ngx on Ubuntu 24.04 LTS on Azure: overview (watch on YouTube)
Launch and log in: Paperless-ngx on Ubuntu 24.04 LTS on Azure: launch and log in (watch on YouTube)
Deep Dive: Paperless-ngx on Ubuntu 24.04 LTS on Azure: deep dive (watch on YouTube)
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.
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 runs OCR on it, extracts the text, tags and indexes it, then archives a searchable original.
This SecureAnyCloud image runs Paperless-ngx bare metal behind nginx, with PostgreSQL, Redis and the full OCR pipeline on the same VM. Administrator and database credentials are generated on the first boot of every VM, so no two deployments share a password. No documents and no shared credentials ship in the image.
What you get:
- Paperless-ngx 2.20 installed from the official release tarball into
/opt/paperless - The granian application server on loopback
:8000serving the bundled Angular frontend, behind an nginx reverse proxy on:80 - A Celery worker and a Celery beat scheduler for the background task pipeline, plus a consumer process that watches an input folder for new documents
- 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 as the Celery task broker. PostgreSQL and Redis are bound to the loopback interface only.
- The full tesseract OCR pipeline, built on tesseract, Ghostscript and OCRmyPDF, so scanned PDFs and images become fully text searchable on import
- Per-VM administrator, database and secret-key credentials generated at first boot, including a fresh Django secret key. The administrator and PostgreSQL passwords are written to
/root/paperless-ngx-credentials.txtwith mode 0600, so only root can read them. - Separate Azure data disks, apart from the operating system disk: the Paperless application code, document media archive, data directory, consume folder and search index live under
/opt/paperless, and the PostgreSQL data directory sits at/var/lib/postgresql. Both disks are captured into the image, re-provisioned with every VM you deploy, and can be resized independently. - Seven systemd units enabled and active
- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended starting size. The OCR pipeline is processor and memory heavy, and document throughput benefits from both.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network. Also allow 80/tcp from the networks your users will reach Paperless on, plus 443/tcp once you enable HTTPS.
Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Paperless-ngx by SecureAnyCloud, and select Create.
On the Basics tab, 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 select Review + create and Create. First boot initialisation takes approximately one to three minutes after the VM starts.
Deploy from the Azure CLI
Replace the resource group, image reference, VNet and subnet with your own values:
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:paperless-ngx-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name paperless \
--image sac1647283583153:paperless-ngx-ubuntu-24-04:default:latest \
--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 1010First boot takes a few minutes. On first boot the VM finishes its per-VM setup in the background. It generates the VM's own credentials and starts the services. If you connect as soon as the VM shows as running, wait for that setup to finish before you continue:
Run sudo cloud-init status --wait in your SSH session.
The command prints status: done when the VM is ready. The credentials and services described below exist only after that.
Connect and retrieve the 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 the file with sudo:
sudo cat /root/paperless-ngx-credentials.txtThe file lists the Paperless administrator username (admin) and password, the database name, user and password, and the URL of the web interface. Store these somewhere safe.
Confirm the services are running
The image runs seven systemd units. Confirm that all of them are 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.
Understand the trusted host model
Django, the web framework Paperless is built on, serves only requests whose Host header it trusts. It also accepts form posts only 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. The web interface is therefore 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-webserverSign in to the Paperless web interface
Browse to http://<vm-public-ip>/. Paperless opens its sign-in page. Enter the administrator username (admin) and the administrator password from /root/paperless-ngx-credentials.txt, then select Sign in.
After you sign in, you reach the Dashboard, which shows saved views and statistics. The Documents list is the heart of the platform: every document you import is processed with OCR, tagged and made full text searchable there.
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.
Import and OCR your first document
Paperless imports documents by watching a consume directory. The consumer picks up anything you drop into /opt/paperless/consume, runs OCR, indexes it and archives it automatically.
Copy a PDF or scanned image into the directory with sudo cp <your-file>.pdf /opt/paperless/consume/. Then 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 leaves 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 20Scanners and network shares can write straight into /opt/paperless/consume over NFS, SMB or scp. This is the usual way to feed a paperless office.
The REST API
Paperless exposes a full REST API under /api/. The API requires authentication, while the sign-in page itself is open. 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/For automation and integrations, issue a long-lived API token from My Profile in the web interface and pass it as Authorization: Token <token>.
Organise with 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, tag everything from a given correspondent, or match documents whose OCR text contains a keyword. Pin the searches you run most as saved views on the dashboard.
Manage services and run commands
The paperless-webserver unit runs the granian application server on 127.0.0.1:8000, and nginx reverse proxies port 80 to it. The paperless-task-queue and paperless-scheduler units are the Celery worker and beat scheduler. The paperless-consumer unit 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/mediaRun 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>Check the dedicated data disks
The PostgreSQL database tier and the Paperless application and data tier each live on their own Azure data disk. Both disks are separate from the OS disk and captured into the image, so every VM you deploy is provisioned with both. Confirm the mounts:
findmnt -no SOURCE,SIZE,FSTYPE,TARGET /var/lib/postgresql
findmnt -no SOURCE,SIZE,FSTYPE,TARGET /opt/paperlessThe database disk mounts at /var/lib/postgresql (20 GiB) and the data disk at /opt/paperless (60 GiB). As your archive grows, resize either disk independently in the Azure Portal. Then grow the filesystem with sudo resize2fs on the corresponding device.
Enable HTTPS with Let's Encrypt
For any production deployment, serve the site over HTTPS so that session cookies and document transfers cannot be intercepted. The image ships with nginx, which certbot can configure automatically.
This procedure assumes the following:
- A DNS record points your fully qualified domain name at the VM's public IP address
- An NSG rule allows
443/tcp - You have added the domain to
PAPERLESS_URLandPAPERLESS_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 \
--redirectAfter certbot finishes, point Paperless at the HTTPS URL so that 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-webserverBack up and maintain Paperless
Back up two things 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/paperlessCopy 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.
Ubuntu's unattended-upgrades is enabled, so kernel and package 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_REDISat 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
The official Paperless-ngx documentation at https://docs.paperless-ngx.com/ covers each of these.
Support
This image is backed by 24/7 SecureAnyCloud support, with a response within 24 hours and a one-hour average for critical issues. Contact sales@secureanycloud.com 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.
Deploy on Azure
Launch Paperless-ngx on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Paperless-ngx is the popular open source document management system: a self-hosted, searchable digital archive for your paperless office. This SecureAnyCloud image runs it bare metal behind nginx, with PostgreSQL, Redis and the full OCR pipeline on the same instance.
What you get:
- The granian application server serving the bundled Angular frontend on the loopback interface, behind nginx
- A Celery worker and a Celery beat scheduler for the background task pipeline, plus a consumer process that watches an input folder for new documents
- PostgreSQL as the database and Redis as the Celery task broker, both bound to the loopback interface only
- An OCR pipeline built on tesseract, Ghostscript and OCRmyPDF, so scanned PDFs and images become fully text searchable on import
- Administrator and PostgreSQL credentials generated on the first boot of every instance, so two instances launched from the same Amazon Machine Image never share passwords. A fresh Django secret key is generated at the same time.
- The administrator and PostgreSQL passwords written to
/root/paperless-ngx-credentials.txtwith mode 0600, so only root can read them. No documents and no shared credentials ship in the image. - Separate EBS volumes, apart from the operating system disk: the Paperless application code, document media archive, data directory, consume folder and search index live under
/opt/paperless, and the PostgreSQL data directory sits at/var/lib/postgresql. Each tier can be resized independently of the others.
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the networks your users will reach Paperless on
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Paperless-ngx. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or larger. The OCR pipeline is processor and memory heavy, and document throughput benefits from both. Choose your EC2 key pair under Key pair (login).
Under Network settings, select your VPC and subnet. Create or select a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the networks your users use. Leave the root volume at the default size or larger.
Select Launch instance. First boot initialisation takes approximately one minute after the instance state becomes Running and the status checks pass.
Launch the instance from the AWS CLI
The following command launches an instance from the SecureAnyCloud Paperless-ngx Marketplace AMI into an existing subnet and security group. Replace the values as follows:
- <ami-id>: the AMI ID shown on the Marketplace listing
- <key-name>: your EC2 key pair name
- <subnet-id>: your subnet ID
- <security-group-id>: a security group that opens ports 22, 80, and 443 as described above
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":20,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=paperless-01}]'On success the command prints a JSON document. Note the instance ID. Once the instance is running, retrieve its public address with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and retrieve the initial credentials
Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched. For the Paperless-ngx 2.20 on Ubuntu 24.04 AMI, the login user is ubuntu.
ssh -i <key.pem> ubuntu@<public-ip>The per-instance administrator and PostgreSQL passwords are written to a root-only file. Read the file with sudo:
sudo cat /root/paperless-ngx-credentials.txtThe file lists the Paperless administrator username (admin) and password, the database name, user and password, and the URL of the web interface. Store these somewhere safe.
Understand the trusted host model
Django, the web framework Paperless is built on, serves only requests whose Host header it trusts. It also accepts form posts only from trusted origins.
On first boot the instance adds its own public and private addresses to PAPERLESS_URL and PAPERLESS_CSRF_TRUSTED_ORIGINS in /opt/paperless/paperless.conf. The web interface is therefore reachable immediately on the instance'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-webserverSign in to the Paperless web interface
Browse to http://<public-ip>/. Paperless opens its sign-in page. Enter the administrator username (admin) and the administrator password from /root/paperless-ngx-credentials.txt, then select Sign in.
After you sign in, you reach the Dashboard, which shows saved views and statistics. The Documents list is the heart of the platform: every document you import is processed with OCR, tagged and made full text searchable there.
Change the administrator password
For a production deployment, rotate the administrator password that was generated on first boot. Select the gear or your user menu, open My Profile, and change the password there.
You can also reset the password from the command line. The Paperless manage.py changepassword admin command prompts you for the new password interactively. Run it from your SSH session and type the new password when asked.
Invoke the management command as the paperless user with the configuration path set, like every other admin command shown in step 10.
Import and OCR your first document
Paperless imports documents by watching a consume directory. The consumer picks up anything you drop into /opt/paperless/consume, runs OCR, indexes it and archives it automatically.
Copy a PDF or scanned image into the directory with sudo cp <your-file>.pdf /opt/paperless/consume/. Then 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 leaves the consume directory and appears in the Documents list in the web interface, with its extracted text searchable.
Watch the pipeline work with journalctl -u paperless-consumer -u paperless-task-queue -f. Press Ctrl-C to stop following. Or check the recent log without following:
sudo journalctl -u paperless-consumer -u paperless-task-queue --no-pager -n 20Scanners and network shares can write straight into /opt/paperless/consume over NFS, SMB or scp. This is the usual way to feed a paperless office.
The REST API
Paperless exposes a full REST API under /api/. The API requires authentication, while the sign-in page itself is open. 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/For automation and integrations, issue a long-lived API token from My Profile in the web interface and pass it as Authorization: Token <token>.
Organise with 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, tag everything from a given correspondent, or match documents whose OCR text contains a keyword. Pin the searches you run most as saved views on the dashboard.
Manage services and run commands
The image runs seven systemd units. Check their state at any time:
systemctl status postgresql redis-server nginx \
paperless-webserver paperless-task-queue paperless-scheduler paperless-consumerThe paperless-webserver unit runs the granian application server on 127.0.0.1:8000, and nginx reverse proxies port 80 to it. The paperless-task-queue and paperless-scheduler units are the Celery worker and beat scheduler. The paperless-consumer unit watches the consume directory.
Run Paperless management commands as the paperless user:
sudo -u paperless PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf \
/opt/paperless/.venv/bin/python /opt/paperless/src/manage.py <command>Enable HTTPS with Let's Encrypt
For any production deployment, serve the site over HTTPS so that session cookies and document transfers cannot be intercepted. The image ships with nginx, which certbot can configure automatically.
This procedure assumes that a DNS record points your fully qualified domain name at the instance's public IP address, and that you have added the domain to PAPERLESS_URL and PAPERLESS_CSRF_TRUSTED_ORIGINS (step 4).
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 \
--redirectAfter certbot finishes, point Paperless at the HTTPS URL so that 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-webserverBack up and maintain Paperless
Back up two things 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 -u paperless PAPERLESS_CONFIGURATION_PATH=/opt/paperless/paperless.conf \
/opt/paperless/.venv/bin/python /opt/paperless/src/manage.py document_exporter /var/backups/paperlessCopy the export directory to an Amazon S3 bucket or another object store. Because the data and database tiers are on their own EBS volumes, you can also take coordinated EBS snapshots. The scheduler runs Paperless's periodic tasks, such as email checking and index optimisation, automatically.
Ubuntu's unattended-upgrades is enabled by default, so kernel and package security patches apply automatically. To update Paperless itself, follow the upgrade workflow in the official documentation at https://docs.paperless-ngx.com/.
Scale beyond a single instance
For larger deployments, decouple Paperless from the single-instance pattern:
- Move PostgreSQL to Amazon RDS for PostgreSQL and update the database host in
/opt/paperless/paperless.conf - Move the document store to Amazon S3 using Paperless's object storage support, or to Amazon EFS
- Move Redis to Amazon ElastiCache for Redis and point
PAPERLESS_REDISat the cluster endpoint - Put the web tier behind an Application Load Balancer, add the load balancer hostname to the trusted origins, and run the Celery workers on dedicated instances
- Serve static assets through Amazon CloudFront
The official Paperless-ngx documentation at https://docs.paperless-ngx.com/ covers each of these.
Screenshots
The Paperless-ngx sign-in page, served on first boot with a per-instance administrator password and no manual setup.
The Paperless-ngx documents view after you sign in as the administrator: the searchable document archive.
A document detail view showing the rendered preview alongside the OCR-extracted, full text searchable content.
Support
SecureAnyCloud provides 24/7/365 expert technical support for this image, with a response within 24 hours and a one-hour average for critical issues. Contact sales@secureanycloud.com.
Deploy on AWS
Launch Paperless-ngx on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com