# Server Development

Getting started guide for the server development

# Preamble

This whole guide is based on Ubuntu 22.04 LTS. Other Ubuntu and Debian based systems should be similar if not even identical.

We assume that you already have somewhere a Postgres database running. If not follow the guide to setup postgres.

# Installation

  1. Install some generic stuff

    sudo apt-get update
    sudo apt-get install -y \
            git \
            libyaml-dev \
            libpython3-dev \
            libpq-dev \
            libffi-dev \
            python3-dev \
            python3-pip \
            python3-psycopg2 \
    sudo pip3 install --upgrade pip
  2. Clone git repository

    git clone https://gitlab.com/psono/psono-server.git ~/psono-server
  3. Checkout new branch

    cd ~/psono-server
    git fetch
    git checkout develop
    git checkout -b [name_of_your_new_branch]
  4. Install python requirements

    sudo pip3 install -r requirements.txt
    sudo pip3 install -r requirements-dev.txt
  5. Create settings folder

    mkdir ~/.psono_server
  6. Create a settings.yaml in ~/.psono_server/ with the following content

    # generate the following six parameters with the following command
    # python3 ~/psono-server/psono/manage.py generateserverkeys
    EMAIL_SECRET_SALT: '$2b$12$o9HKh8yvEqYe6k0Do/YZdu'
    PRIVATE_KEY: 'debe5115baf449b0c53ac112d5df314bb7adcb46308b6847908c97b06746a65c'
    PUBLIC_KEY: '9b8f35c6261fa9840f00b86026fe11ec4e0e0cbf84b2f860713da1e442c79577'
    # The URL of the web client (path to e.g activate.html without the trailing slash)
    # WEB_CLIENT_URL: 'https://psono.example.com'
    # Switch DEBUG to false if you go into production
    DEBUG: True
    # Adjust this according to Django Documentation https://docs.djangoproject.com/en/2.2/ref/settings/
    ALLOWED_HOSTS: ['*']
    # Should be your domain without "www.". Will be the last part of the username
    ALLOWED_DOMAINS: ['example.com']
    # If you want to disable registration, you can comment in the following line
    # If you want to disable the lost password functionality, you can comment in the following line
    # If you want to enforce that the email address and username needs to match upon registration
    # If you want to restrict registration to some email addresses you can specify here a list of domains to filter
    # REGISTRATION_EMAIL_FILTER: ['company1.com', 'company2.com']
    # Should be the URL of the host under which the host is reachable
    # If you open the url and append /info/ to it you should have a text similar to {"info":"{\"version\": \"....}
    HOST_URL: 'https://psono.example.com/server'
    # The email used to send emails, e.g. for activation
    # Not necessary if you do not plan to develop around the user activation
    # ATTENTION: If executed in a docker container, then "localhost" will resolve to the docker container, so
    # "localhost" will not work as host. Use the public IP or DNS record of the server.
    EMAIL_FROM: 'the-mail-for-for-example-useraccount-activations@test.com'
    EMAIL_HOST: 'smtp.example.com'
    EMAIL_PORT: 25
    EMAIL_USE_TLS: False
    EMAIL_USE_SSL: False
    # In case one wants to use mailgun, comment in below lines and provide the mailgun access key and server name
    # EMAIL_BACKEND: 'anymail.backends.mailgun.EmailBackend'
    # In case you want to offer Yubikey support, create a pair of credentials here https://upgrade.yubico.com/getapikey/
    # and update the following two lines before commenting them in
    # YUBIKEY_CLIENT_ID: '123456'
    # If you have your own Yubico servers, you can specify here the urls as a list
    # YUBICO_API_URLS: ['https://api.yubico.com/wsapi/2.0/verify']
    # Cache enabled without belows Redis may lead to unexpected behaviour
    # Cache with Redis
    # By default you should use something different than database 0 or 1, e.g. 13 (default max is 16, can be configured in
    # redis.conf) possible URLS are:
    #    redis://[:password]@localhost:6379/0
    #    rediss://[:password]@localhost:6379/0
    #    unix://[:password]@/path/to/socket.sock?db=0
    # CACHE_ENABLE: False
    # CACHE_REDIS: False
    # CACHE_REDIS_LOCATION: 'redis://'
    # Enables the management API, required for the psono-admin-client / admin portal
    # Enables the fileserver API, required for the psono-fileserver
    # Enables files for the client
    # FILES_ENABLED: False
    # Allows that users can search for partial usernames
    # Allows that users can search for email addresses too
    # Disables central security reports
    # Configures a system wide DUO connection for all clients
    # DUO_SECRET_KEY: ''
    # If you are using the DUO proxy, you can configure here the necessary HTTP proxy
    # DUO_PROXY_HOST: 'the-ip-or-dns-name-goes-here'
    # DUO_PROXY_PORT: 80
    # If your proxy requires specific headers you can also configure these here
    # Normally only one of the configured second factors needs to be solved. Setting this to True forces the client to solve all
    # Allows admins to limit the offered second factors in the client
    # ALLOWED_SECOND_FACTORS: ['yubikey_otp', 'google_authenticator', 'duo', 'webauthn']
    # Your Postgres Database credentials
    # ATTENTION: If executed in a docker container, then "localhost" will resolve to the docker container, so
    # "localhost" will not work as host. Use the public IP or DNS record of the server.
            'ENGINE': 'django.db.backends.postgresql_psycopg2'
            'NAME': 'psono'
            'USER': 'psono'
            'PASSWORD': 'password'
            'HOST': 'localhost'
            'PORT': '5432'
    # for master / slave replication setup comment in the following (all reads will be redirected to the slave
    #    slave:
    #        'ENGINE': 'django.db.backends.postgresql_psycopg2'
    #        'NAME': 'YourPostgresDatabase'
    #        'USER': 'YourPostgresUser'
    #        'PASSWORD': 'YourPostgresPassword'
    #        'HOST': 'YourPostgresHost'
    #        'PORT': 'YourPostgresPort'
    # Update the path to your templates folder
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': ['/home/psono/psono-server/psono/templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [

    Update database credentials / secrets / paths like described in the comments

  7. Test E-Mail (optional)

    The most tedious step is usually for me to get e-mail working. To make this step easier, we offer a small test script which will send a test e-mail.

    To send a test e-mail to something@something.com execute:

    python3 ~/psono-server/psono/manage.py sendtestmail something@something.com

    If you receive this test e-mail, e-mail should be configured proper.

  8. Create our database

    python3  ~/psono-server/psono/manage.py migrate

# Run the dev server

From this point on forward, you can develop it like any other django application

To start the server you can do for example:

python3 ~/psono-server/psono/manage.py runserver

This will start the Psono server on port 10100. If you open now http://your-ip:10100/info/ you should see something like this:

{"info":"{\"version\": \"....}

If you don't, please make sure no firewall is blocking your request.

# Update database model

If you ever change parts of the model, then you can create the migration script with the following command

python3  ~/psono-server/psono/manage.py makemigrations restapi

and apply it then to your postgres installation with:

python3  ~/psono-server/psono/manage.py migrate

# Create user on the commandline:

If you are developing and don't want to setup email or go to the database to activate a user, you can just create a user on the command line with the following command:

python3 ./psono/manage.py createuser username@example.com myPassword email@something.com

Other useful commands can be found under Commands

# Run Unit Tests (with coverage)

To run unit tests, the database user needs CREATEDB rights.

coverage run --source='.' ./psono/manage.py test restapi.tests administration.tests fileserver.tests

To get a nice report one can do:

coverage report --omit=psono/restapi/migrations/*,psono/restapi/tests*,psono/administration/migrations/*,psono/administration/tests*,psono/fileserver/migrations/*,psono/fileserver/tests*


coverage html --omit=psono/restapi/migrations/*,psono/restapi/tests*,psono/administration/migrations/*,psono/administration/tests*,psono/fileserver/migrations/*,psono/fileserver/tests*

The output of this command can be shown on https://your-ip/htmlcov/

# Run local dummy smtp server

If you want to debug e-mails, like those sent during the registration, one can start a local dummy smtp server with the following command

sudo python -m smtpd -n -c DebuggingServer localhost:25