====== Install paperless-ngx on Debian without Docker ======
Caveat: this guide assumes a non-Raspberry pi machine, and SQLite as database (which is ok for small installations). The service will be behind an Nginx proxy.
===== Install dependencies and configure the system =====
First, we'll need to install all required dependencies (there are also dependencies for MariaDB and PostgreSQL; even if we won't use them, not installing them would require to edit the requirements.txt file later, which I don't want to do just in case it breaks something):
apt install valkey-server python3 python3-pip python3-dev fonts-liberation imagemagick libmagic-dev poppler-utils build-essential python3-setuptools python3-wheel python3-venv pkg-config default-libmysqlclient-dev libpq-dev
If you're planning on sending gpg-encrypted emails to paperless, you'll also need to add ''gnupg'' to the list of packages. You can use ''redis-server'' instead of ''valkey-server'' if you prefer. The following packages are needed if you want to run OCR on your documents:
apt install unpaper ghostscript icc-profiles-free qpdf libleptonica6 libxml2 pngquant zlib1g tesseract-ocr tesseract-ocr-//xxx//
where ''//xxx//'' is the language code for the languages your documents will be in (eng, ita, deu, etc.).
Now it's time to add a service system user and group for the application, which will be installed in ''/opt/paperless'':
adduser paperless --system --home /opt/paperless --group
===== Download, install and paperless-ngx =====
We need to download the latest paperless release from the github repo (replace ''x.x.x'' with the latest release number). Do not clone the git repo, but download the release, which contains some compiled code absent in the repo. This is the sequence of inputs to download the release file, extract it, and move everything inside ''/opt/paperless'':
cd /opt/paperless
sudo -u paperless wget https://github.com/paperless-ngx/paperless-ngx/releases/download/vx.x.x/paperless-ngx-vx.x.x.tar.xz
sudo -u paperless tar xf paperless-ngx-vx.x.x.tar.xz
mv paperless-ngx/* .
mv paperless-ngx/.* .
rmdir paperless-ngx
rm paperless-ngx-vx.x.x.tar.x
At this point we need to edit the ''paperless.conf'' file to adapt it to our installation. It is important to uncomment and properly set these variables:
PAPERLESS_REDIS
PAPERLESS_DBENGINE=sqlite # It may not be necessary to create this for sqlite, but just in case...
PAPERLESS_CONSUMPTION_DIR
PAPERLESS_DATA_DIR
PAPERLESS_MEDIA_ROOT # If needed it can be the same directory as PAPERLESS_DATA_DIR
PAPERLESS_STATICDIR=../static
PAPERLESS_SECRET_KEY
PAPERLESS_URL
PAPERLESS_OCR_LANGUAGE
PAPERLESS_TIME_ZONE
PAPERLESS_USE_X_FORWARD_HOST=true
PAPERLESS_USE_X_FORWARD_PORT=true
PAPERLESS_PROXY_SSL_HEADER='["HTTP_X_FORWARDED_PROTO", "https"]'
Make sure you create the folders you have assigned in the config file and chown them to the paperless:paperless user and group. To install all the required python packages with pip (Debian doesn't have a lot of them in its repo, plus specific versions are required) it is necessary to create a python virtual environment owned by the user paperless. It will then be possible to install the packages:
sudo -u paperless makedir venv
sudo -u paperless python3 -m venv venv
sudo -u paperless venv/bin/pip3 install -r requirements.txt
Time to populate the database:
cd src
sudo -u paperless ../venv/bin/python3 manage.py migrate
As a last installation step, something undocumented on paperless-ngx's documentation: to enable better document search (which I believe is active by default), we need to download some more python packages. First of all, enable this feature explicitly in ''paperless.conf'':
PAPERLESS_ENABLE_NLTK=true
PAPERLESS_NLTK_DIR=/opt/paperless/nltk_data
Then, download the required packages:
cd /opt/paperless
sudo -u paperless venv/bin/python3 -m nltk.downloader punkt_tab
sudo -u paperless venv/bin/python3 -m nltk.downloader punkt
sudo -u paperless venv/bin/python3 -m nltk.downloader stopwords
Before testing the server to see if it works, we need to temporarily enable debug mode. Add ''PAPERLESS_DEBUG=true'' to ''paperless.conf'', then run:
cd src
sudo -u paperless ../venv/bin/python3 manage.py runserver
It's now time to set up all the systemd services. Script examples are in the ''script'' folder and we're going to edit those and link them to the systemd folder.
paperless-consumer.service
[Unit]
Description=Paperless consumer
Requires=redis.service
[Service]
User=paperless
Group=paperless
WorkingDirectory=/opt/paperless/src
ExecStart=/opt/paperless/venv/bin/python3 manage.py document_consumer
[Install]
WantedBy=multi-user.target
paperless-scheduler.service
[Unit]
Description=Paperless Celery Beat
Requires=redis.service
[Service]
User=paperless
Group=paperless
WorkingDirectory=/opt/paperless/src
ExecStart=/opt/paperless/venv/bin/celery --app paperless beat --loglevel INFO
[Install]
WantedBy=multi-user.target
paperless-task-queue.service
[Unit]
Description=Paperless Celery Workers
Requires=redis.service
[Service]
User=paperless
Group=paperless
WorkingDirectory=/opt/paperless/src
ExecStart=/opt/paperless/venv/bin/celery --app paperless worker --loglevel INFO
[Install]
WantedBy=multi-user.target
paperless-webserver.service
[Unit]
Description=Paperless webserver
After=network.target
Wants=network.target
Requires=valkey.service
#Requires=paperless-webserver.socket
[Service]
User=paperless
Group=paperless
WorkingDirectory=/opt/paperless/src
Environment=GRANIAN_HOST=::
Environment=GRANIAN_PORT=8000
Environment=GRANIAN_WORKERS=1
ExecStart=/bin/sh -c '\
# Host: GRANIAN_HOST -> PAPERLESS_BIND_ADDR -> default \
[ -n "$PAPERLESS_BIND_ADDR" ] && export GRANIAN_HOST=$PAPERLESS_BIND_ADDR; \
# Port: GRANIAN_PORT -> PAPERLESS_PORT -> default \
[ -n "$PAPERLESS_PORT" ] && export GRANIAN_PORT=$PAPERLESS_PORT; \
# Workers: GRANIAN_WORKERS -> PAPERLESS_WEBSERVER_WORKERS -> default \
[ -n "$PAPERLESS_WEBSERVER_WORKERS" ] && export GRANIAN_WORKERS=$PAPERLESS_WEBSERVER_WORKERS; \
# URL path prefix: only set if PAPERLESS_FORCE_SCRIPT_NAME exists \
[ -n "$PAPERLESS_FORCE_SCRIPT_NAME" ] && export GRANIAN_URL_PATH_PREFIX=$PAPERLESS_FORCE_SCRIPT_NAME; \
exec /opt/paperless/venv/bin/granian --interface asginl --ws --loop uvloop "paperless.asgi:application"'
[Install]
WantedBy=multi-user.target
Now that we have the unit files ready, we need to enable and start them:
cd scripts
systemctl enable paperless-task-queue.service
systemctl enable paperless-scheduler.service
systemctl enable paperless-consumer.service
systemctl enable paperless-server.service
systemctl start paperless-task-queue.service
systemctl start paperless-scheduler.service
systemctl start paperless-consumer.service
systemctl start paperless-server.service
All that is left to do now is configure the Nginx reverse proxy:
cd /etc/nginx/sites-available/
nano docs.mydomain.tld
This is the content of the docs.mydomain.tld file:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
ssl_certificate /path/to/cert.crt;
ssl_certificate_key /path/to/cert.key;
server_name docs.mydomain.tld;
access_log /var/log/nginx/docs.mydomain.tld-access.log;
error_log /var/log/nginx/docs.mydomain.tld-error.log;
client_max_body_size 20M;
large_client_header_buffers 4 8k;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
location = /accounts/login/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_hide_header Referrer-Policy;
add_header Referrer-Policy "same-origin" always;
}
location / {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_hide_header Referrer-Policy;
add_header Referrer-Policy "no-referrer" always;
}
}
And now it's time to enable the configuration:
ln -s /etc/nginx/sites-available/docs.mydomain.tld /etc/nginx/sites-enabled/
systemctl restart nginx
===== Updating paperless-ngx =====
Paperless-ngx's documentation suggests to delete almost all previous files and copy the new ones in place, so we'll do just that. Before starting, we backup the current folder for safety purposes, and we stop all paperless services. Here is the sequence of commands:
systemctl stop paperless-consumer paperless-scheduler paperless-task-queue paperless-webserver
cd /opt
cp -R paperless paperless.bak
wget https://github.com/paperless-ngx/paperless-ngx/releases/download/vx.x.x/paperless-ngx-vx.x.x.tar.xz
tar xf paperless-ngx-vx.x.x.tar.xz
chown -R paperless:paperless paperless.bak paperless-ngx
At this point it's good to stop for a second and check that the systemd unit files in the ''scripts'' directory have not changed, so that we can keep the old ones, or modify them accordingly. Once done with the check, it's time for the update. From the original installation we need to keep the ''.env'', ''paperless.conf'', ''scripts'', and ''venv'' files and folders, so we'll delete everything but those (and of course we'll remove just those from the directory of the new version):
cd /opt/paperless
rm -r `ls -a | grep -v ".env\|paperless.conf\|scripts\|venv"`
cd /opt/paperless-ngx
rm -r .env paperless.conf scripts
mv ./* ../paperless
Now, with all the files in place, we update the python dependencies. In principle we should also manually remove all dependencies that are no longer required, but meh, we'll think about it if errors occur.
cd /opt/paperless
sudo -u paperless venv/bin/pip3 install -r requirements.txt
cd src
sudo -u paperless ../venv/bin/python3 manage.py migrate # (1)
sudo -u paperless ../venv/bin/python3 manage.py document_index reindex --if-needed
sudo -u paperless ../venv/bin/python3 manage.py document_llmindex migrate
It is now possible to restart the services.
systemctl start paperless-consumer paperless-scheduler paperless-task-queue paperless-webserver
If everything works, we can clean up:
cd /opt
rm -R paperless.bak paperless-ngx