Setting up for local development

from emersion

Jul 29, 2021, 10:00:00 PM

I sometimes contribute to An important step in the contribution process is to properly test the patches, even if they’re a simple change. Getting a good local development setup can be an intimidating task. I have a setup which tries to minimize the amount of steps and indirections involved. This post is a loose attempt at documenting it.

Disclaimer: this is not an official resource, and this will likely become out-of-date as evolves. This article should be treated as a list of hints, not as a complete tutorial. Some more advanced features like webhooks are not covered.

See the official documentation for the canonical source of truth.

Install dependencies

Follow your distribution’s instructions to setup Postgres and Redis.

Using the package repositories for your distribution will definitely help, as all Python dependencies aren’t always packaged. If you insist on not using these repositories, most of the Python dependencies are in the AUR, but sometimes are out-of-date or broken. Just try running the Python scripts and install python-<import name> when you hit an import error. is the base service that many other services depend on at least for authentication. This it should be the first one to be set up.

Start by cloning the repository somewhere, together with

cd ~/src
git clone
git clone

Then configure PYTHONPATH to look up these directories, and set up SRHT_PATH:

export PYTHONPATH=$HOME/src/$HOME/src/
export SRHT_PATH=$HOME/src/

Generate static assets and build the API:

cd api && go build

The next step is getting the configuration right for Start with the example config file (mv config.example.ini config.ini) then populate the various fields. For the service-independent [] section, the keys can be generated with helpers found in and the redis-host field should be set to redis:// The [mail] section doesn’t need to be populated.

Then comes the [] section. To avoid the need to setup some hosts, I like setting origin= (port same as debug-port).

To create and initialize the database:


If you later update, run ./metasrht-migrate upgrade head to run database migrations.

Create a new admin user:

./metasrht-manageuser -t admin root

Once all that preparation work is done, should be ready to be started:

python should be pretty simple to get running. Just like, clone the repository, append it to PYTHONPATH, build static assets and the API.

The same configuration file should be used for all services, so that all can share the options from the common sections. So I just set up a symbolic link:

ln -s ../ config.ini

Take the specific blocks from config.example.ini and append them to config.ini. As usual, populate the origin and connection-string options. Since depends on for authentication, one extra step is to generate some OAuth credentials in for (and any other additional service you’ll setup later on). should now run just fine.

Same as, but also needs to be added to PYTHONPATH (just like

I like configuring repos=./repos and then setting up test repositories like so:

git init
git remote add $HOME/src/

A git push should then show up in’s web UI.

This one is a bit more tricky, because it interacts with SMTP servers.

The setup isn’t very different from other services. At the configuration phase, the outgoing e-mail server needs to be configured in the [mail] section. I use go-smtp’s debug server, which just dumps all traffic to stdout:

git clone
cd go-smtp
go run ./cmd/smtp-debug-server

Set smtp-host= and smtp-port=1025, then you should be good to go. Start the service as usual.

Incoming e-mail messages will be handled by two separate processes:

  • A LMTP server will put the messages into a queue. Start the server with ./listssrht-lmtp.
  • A Celery worker will dequeue messages and dispatch them. Start the worker with celery -A listssrht.process worker.

Then submit messages to the LMTP server at /tmp/

Other services

Other services are very similar to the ones described so far. Some will need a slightly different setup. The IRC channel is a good place to ask for help if you’re hitting a roadblock.