Server Configurations

The default is to use Django’s development server provided by ./ runserver command, as that’s easy and does the job well enough on a home network. However it is heavily discouraged to use it for more than that.

If you want to do things right you should use a real webserver capable of handling more than one thread. You will also have to let the webserver serve the static files (CSS, JavaScript) from the directory configured in STATIC_DIR. The default static files directory is static.

For that you need to activate your virtual environment and collect the static files with the command:

$ ./ collectstatic

Setting up a web server can sound daunting for folks who don’t normally do that kind of thing. This guide will help you walk through the configuration for Apache or Nginx on Linux and OSX.


If this all looks too overwhelming for you, we do offer affordable hosted solutions for folks who want to use Papermerge but don’t know how to run a web server, or don’t have time to keep up with updates.


The most common setup for Papermerge on a linux server is to use Apache, so if you’re not sure what to pick, Apache might be the best bet, as it’s free, easy to configure, and well documented.

In order use apache web server with Django (web framework used by Papermerge) you need to install so called module mod_wsgi

Step 1 - Install Apache Web Server

On Ubuntu 20.04 LTS you install apache web server with following command:

$ sudo apt install apache2

Step 2 - Get mod_wsgi

Get latest release of mod_wsgi from here. Extract archive:

unzip mod_wsgi-4.7.1
cd mod_wsgi-4.7.1

Step 3 - Build & Install mod_wsgi

In order to build mod_wsgi on Ubuntu Linux, you need three things:

  • build-essential ubuntu package with gcc compiler and friends
  • apache2-dev package
  • python interpreter from your papermerge virtual environment

Let’s first install required packages:

$ sudo apt install build-essential apache2-dev

Next, activate your Papermerge virtual environment (python virtual environment):

$ source /opt/papermerge/.venv/bin/activate


Activating python virtual environment is very important step. Because when compilying mod_wsgi it must find in $PATH python interpreter located in same virtual environment with other python dependencies.

Switch to extracted directory mod_wsgi-4.7.1 and run following commands:

$ ./configure
$ make
$ sudo make install

On Ubuntu 20.04 LTS sudo make install command will copy binary file to /usr/lib/apache2/modules/

Next enable mod_wsgi module with following command:

$ a2enmod mod_wsgi

You can double check if mod_wsgi module was enabled with:

$ apachectl -M

It should display a list enabled modules. Among other should be:

wsgi_module (shared)

Step 4 - Configure Virtual Host

In directory /etc/apache2/sites-available create a virtual configuration file for papermerge. Let’s say Here is configuration example for virtual host:

<VirtualHost *:8060>
    <Directory /opt/papermerge/config>
        Require all granted

    Alias /media/ /var/media/papermerge/
    Alias /static/ /var/static/papermerge/

    <Directory /var/media/papermerge>
       Require all granted

    <Directory /var/startic/papermerge>
      Require all granted

    ServerName papermerge.home
    ServerRoot /opt/papermerge

WSGIPythonHome /opt/papermerge/.venv/
WSGIPythonPath /opt/papermerge/
WSGIScriptAlias / /opt/papermerge/config/

The first bit in the WSGIScriptAlias line is the base URL path you want to serve your application at (/ indicates the root url), and the second is the location of a WSGI file, inside papermerge project as config/ This tells Apache to serve any request below the given URL using the WSGI application defined in that file.

WSGIPythonHome is path to python’s virtual environment.

Nginx + Gunicorn

Another way to deploy Papermerge behind a real web server is by using Nginx + Gunicorn duo. Gunicorn is called application server - it serves WSGI (Papermerge/Django) application via HTTP protocol (in that sense Gunicorn is kind of web server). However, gunicorn cannot serve static content (JavaScript, CSS, images), this task falls on NginX shoulders.

Step 1 - Install Gunicorn

Gunicorn is not provided in list of dependencies. Thus, you need to installed in your current virtual python environment:

$ source .venv/bin/activate
$ pip install gunicorn

Create gunicorn configuration file:

$ cat /opt/etc/

workers = 2
errorlog = "/opt/log/gunicorn.error"
accesslog = "/opt/log/gunicorn.access"
loglevel = "debug"

bind = [""]


Gunicorn configuration file must have .py extention and its syntax is valid python syntax.


Binding port is 9001. This same port will be later used to proxy http requests from nginx to gunicorn.

and environment variables file:

$ cat /opt/etc/gunicorn.env


You need to create a file in /opt/papermerge/config/setting/ directory. Here is an example of file content:

$ cat /opt/papermerge/config/settings/

from .base import *  # noqa

DEBUG = False

Step 2 - Systemd Service for Gunicorn

Example of systemd unit file for Gunicorn:

Description=Gunicorn Service

ExecStart=/opt/papermerge/.venv/bin/gunicorn config.wsgi:application --config /opt/etc/

Step 3 - Nginx

And finally connect nginx with gunicorn. Here is a sample configuration for nginx:

server {
    server_name papermerge.home;
    listen 9000;

    location /static/ {
        alias /opt/static/;

    location /media/ {
        alias /opt/media/;

    location / {


Here is worker.service unit:

Description=Papermerge Worker

ExecStart=/opt/papermerge/.venv/bin/python /opt/papermerge/ worker --pidfile /tmp/



Notice that ExecStart is absolute path to python interpreter inside python virtual environment. Absolute path to python interpreter inside virtual environment is enough information for python to figure out the rest of python dependencies from the same virtual environment. Thus, you don’t need to provide futher information about virtual environment.

Systemd .service may be placed in one of several locations. One options is to place it in /etc/systemd/system together with other system level units. In this case you need root access permissions.

Another option is to place .service file inside $HOME/.config/systemd/user/ In this case you can start/check status/stop systemd unit service with following commands:

systemctl --user start worker
systemctl --user status worker
systemctl --user stop worker