This document describes how to deploy a production Patchwork instance. Patchwork 4.0 is a single Go binary that replaces the previous Django/Python deployment.
Patchwork requires:
- The
pwbinary (built from source or downloaded from a release) - A supported database: PostgreSQL (recommended), MySQL/MariaDB, or SQLite
- A mail transfer agent (e.g. Postfix) for receiving patches
- A reverse proxy (e.g. nginx) for TLS termination (optional but recommended)
Building from source requires Go 1.22 or later:
$ git clone https://github.com/getpatchwork/patchwork.git
$ cd patchwork
$ make
$ sudo make installInstall PostgreSQL and create a database:
$ sudo apt-get install -y postgresql
$ sudo -u postgres createuser -d patchwork
$ sudo -u postgres createdb -O patchwork patchworkNo setup is needed. Simply point the configuration at a file path:
[database]
url = "sqlite:///var/lib/patchwork/patchwork.db"Note
SQLite is suitable for small installations and development. For production use with multiple concurrent users, PostgreSQL is recommended.
Generate a default configuration file:
$ pw config > /etc/patchwork.tomlEdit /etc/patchwork.toml to set at least the database URL and the HTTP base
URL. See :doc:`configuration` for a full reference of all available settings.
A minimal configuration looks like:
[database]
url = "postgres://patchwork:secret@localhost/patchwork"
auto-sync = true
[http]
listen = "127.0.0.1:8080"
base-url = "https://patchwork.example.com"
[ingress]
listen = "127.0.0.1:2525"
[smtp]
host = "localhost"
port = 25
from = "patchwork@example.com"Create the database schema and seed default data:
$ pw db syncCreate a user account with admin privileges:
$ pw admin user create --admin -u admin -e admin@example.comThe command will prompt for a password interactively.
Create your first project:
$ pw admin project create \
-n "My Project" \
-l my-project \
-i my-project.example.com \
-e patches@example.comPatchwork consists of two long-running services:
pw http- The HTTP server exposing the web interface and REST API.
pw ingress- The SMTP daemon that receives emails from your mail transfer agent.
The make install target installs systemd unit files. Enable and start the
services:
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now pw-http pw-ingressThe unit files are installed to /usr/lib/systemd/system/. To override
settings, use systemctl edit:
$ sudo systemctl edit pw-httpNote
Both services read configuration from /etc/patchwork.toml by default.
Use the PATCHWORK_TOML environment variable to specify an alternative
path.
A reverse proxy like nginx is recommended for TLS termination and static file
serving. The make install target installs a default nginx configuration to
/etc/nginx/conf.d/patchwork.conf.
A minimal nginx configuration:
server {
listen 443 ssl;
server_name patchwork.example.com;
ssl_certificate /etc/letsencrypt/live/patchwork.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/patchwork.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
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-Proto $scheme;
}
}Patchwork needs to receive emails from your mailing list. The recommended
approach is to configure your mail transfer agent to forward messages to the
pw ingress SMTP daemon.
This is the recommended setup. Configure Postfix to route mail for your list
domain to the pw ingress daemon using transport maps.
Add to /etc/postfix/main.cf:
transport_maps = lmdb:/etc/postfix/transportCreate /etc/postfix/transport:
lists.example.com smtp:127.0.0.1:2525Build the transport map and reload Postfix:
$ sudo postmap /etc/postfix/transport
$ sudo systemctl reload postfixAll mail addressed to lists.example.com will now be forwarded to
pw ingress over SMTP. No shell scripts, no special user accounts, no
database grants.
Note
The pw ingress daemon matches incoming emails to projects by their
List-ID header. Make sure the -e (list email) and -i (list ID)
values of your project match what your mailing list software produces.
For simpler setups, you can use a mail retriever like getmail to download messages from an inbox and pipe them to Patchwork:
[destination]
type = MDA_external
path = /usr/bin/pw
arguments = ("ingress", "--stdin",)For one-off imports, pw ingress can read from stdin:
$ pw ingress --stdin < email.eml
$ pw ingress --mbox < archive.mboxThe --list-id flag can be used to override the List-ID header.
Patchwork can update patch states automatically when commits are pushed. A
post-receive Git hook can be configured to mark patches as "accepted" when
their corresponding commits land in the repository.
Refer to the post-receive.hook script in the Patchwork source tree for an
example implementation that uses the REST API.
Run garbage collection periodically to clean up expired sessions, stale email confirmations, and inactive users:
$ pw admin gcA cron job or systemd timer is recommended (e.g. /etc/cron.daily/patchwork-gc):
#!/bin/sh
exec /usr/bin/pw admin gc