Skip to main content

Install Paperless-ngx on Debian 12 (bare-metal)

Paperless is a cool selfhosted application that allows you to manage your paper documents in a digital form. It provides OCR capabilities with automatic language detection (more on that later) and a bunch of other nice features. This guide walks you through the process on installing Paperless-ngx on a Debian 12 system. Before continuing, please note the following:

  • Paperless-ngx has a Docker image avaiable for you to download. If you want to go the hassle-free way, choose this option
  • The official documentation for bare-metal installation was written at the time when Debian Buster was the latest release of Debian. Since that's not really up to date anymore, I decided to go through this process on Debian 12 to see if it still works or what changes are necessary to make it possible.

System preparation

This guide assumes that you have already installed a Debian 12 system on bare-metal or as a VM, so we won't go through the process here. You can checkout any article online as it's a fairly simple process.

Installation

Install dependencies

First of all, we need to install a bunch of packages as dependencies for the Paperless-ngx application. Go for a cup of coffee while you run this, it's gonna take a few minutes.

  • Install the following packages
sudo apt install python3 python3-pip python3-dev imagemagick fonts-liberation gnupg libpq-dev default-libmysqlclient-dev pkg-config libmagic-dev mime-support libzbar0 poppler-utils
  • Then get a few more for OCR
sudo apt install unpaper ghostscript icc-profiles-free qpdf liblept5 libxml2 pngquant zlib1g tesseract-ocr
  • If you are on Raspberry Pi, you are going to need libatlas-base-dev and libxslt1-dev as well.

Install Redis

You can install Redis from the official Debian repository, which will get you the version 7.0. Papereless requires anything newer than 6.0, so it's fine, howerver you can install a more recent 7.2 version through Redis repositories as per their official documentation. I decided to follow the Redis docs, so I'm going to be adding a new repo.

  • First of all, install some basic prerequisites, which may already be on your system
sudo apt install lsb-release curl gpg
  • Add repository to apt using the following commands
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
  • Then you just update your repos and install the latest stable redis
sudo apt update
sudo apt install redis
Configure Redis for systemd

For some reason, Redis doesn't automatically create a systemd service + there's a configuration option we need to change for it to work properly.

  • Firstly, create a new file called redis.service in /etc/systemd/system folder using your favorite editor and paste the following contents into it:
[Unit]
Description=Redis
After=syslog.target

[Service]
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
RestartSec=5s
Restart=on-success

[Install]
WantedBy=multi-user.target

Make sure the binary /usr/bin/redis-server and config /etc/redis/redis.conf file for Redis exist on your system. Change them in the systemd unit file if necessary.

  • Reload systemd daemons configuration
sudo systemctl daemon-reload
  • Before starting the service, you need to also edit the Redis configuration file, otherwise it will get stuck in a loop (which happened in my case)
  • Open the /etc/redis/redis.conf file and change the following options to look like this
    • deamonize no
    • supervised systemd
################################# GENERAL #####################################

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
# When Redis is supervised by upstart or systemd, this parameter has no impact.
daemonize no

# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
#   supervised no      - no supervision interaction
#   supervised upstart - signal upstart by putting Redis into SIGSTOP mode
#                        requires "expect stop" in your upstart job config
#   supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
#                        on startup, and updating Redis status on a regular
#                        basis.
#   supervised auto    - detect upstart or systemd method based on
#                        UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
#       They do not enable continuous pings back to your supervisor.
#
# The default is "no". To run under upstart/systemd, you can simply uncomment
# the line below:
#
supervised systemd
  • After that, you can enable and start the service
sudo systemctl enable /etc/systemd/system/redis.service
sudo systemctl start /etc/systemd/system/redis.service

or

sudo systemctl enable /etc/systemd/system/redis.service --now
  • Please check if the service started properly and resolve any issues based on the output of the following command
sudo systemctl status /etc/systemd/system/redis.service

Install and setup database (PostgreSQL)

Since Redis isn't an actual database, we need something to store our data. By default, we can you the included SQLite database. For a more robust setup, it is advised to go for either PostgreSQL or MariaDB. We will go for PostgreSQL, since it's the preffered option.

  • Install PostgreSQL from the official repo
sudo apt install postgresql

Paperless doesn't setup the database automatically in any way, so we need to prepare it ourselves. We are gonna create a database and user + password.

  • Firstly, login to PostgreSQL - switch to postgres user and then run psql
sudo su postgres
postgres$ psql
psql (15.3 (Debian 15.3-0+deb12u1))
Type "help" for help.
  • When you are in, create a new database
postgres=# create database paperless;
CREATE DATABASE
  • Next up is the user, which paperless is going to use to connect to the database
postgres=# create user paperless with encrypted password 'REDACTED';
CREATE ROLE
  • Lastly, grant all privileges to the Paperless user on the Paperless database
postgres=# grant all privileges on database paperless to paperless;
GRANT

Save the username and password somewhere safe, we will use it later.

Normally, this should be enough for everything to work properly, but for some reason, during the later steps, the application failed due to some error with the database, so I had to give the Paperless user a superuser permission on the database. This is something I would advise strongly against, however in this case, it's a standalone instance used only by Paperless, which can manage all data there anyway.

Similar issue has been mentioned on their Github here and resolved by temporarily assigning superuser permission to the Paperless user.

  • List the current roles
postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of
-----------+------------------------------------------------------------+-----------
 paperless |                                                            | {}
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
  • Add paperless to Superuser role
postgres=# alter user paperless with superuser;
ALTER ROLE
  • Check if the user is actually there
postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of
-----------+------------------------------------------------------------+-----------
 paperless | Superuser                                                  | {}
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}