- highly customizable
- ability to bind to ports smaller than 1024 with the
AmbientCapabilities=CAP_NET_BIND_SERVICE
setting - boring technology
- less intuitive configuration than Supervisor
# start your application on boot
sudo systemctl enable ${appName}
# start your application
sudo systemctl start ${appName}
# restart application
sudo systemctl restart ${appName}
# view application logs
journalctl -u ${appName}
Create a ${appName}.service
file inside /etc/systemd/system/
that uses the ".env" and "run" file to launch the application:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
EnvironmentFile=/srv/${appName}/.env
WorkingDirectory=/srv/${appName}/
ExecStart=/srv/${appName}/run
AmbientCapabilities=CAP_NET_BIND_SERVICE
User=${appUser}
Group=${appGroup}
[Install]
WantedBy=multi-user.target
- The
[Unit]
section is used to specify metadata and dependencies. It has a description and an instruction to start after the network is up. - The
[Service]
section specifies your service configuration./srv
is the recommended location, according to the Filesystem Hierarchy Standard- The
run
file is a bash script that executes gunicorn - AmbientCapabilities allows you to use ports below 1024
- The
[Install]
section tells Systemd at which moment during the boot process this service should be started.
I like the idea of creating a single executable file to keep all instructions for starting the application in one place. Here is an example:
#! /bin/bash
set -a
source .env
set +a
export PYTHONPATH="/patho/to/repo/src:$PYTHONPATH"
export VIRTUAL_ENV="/path/to/virtualenv"
exec $VIRTUAL_ENV/bin/gunicorn project.wsgi
set -a
,source .env
,set +a
allows to read the environment variables from a .env file (see StackOverflow)- By specifying the environment variable
PYTHONPATH
to point to the application's directory, you can specify the path to yourwsgi.py
as a python module path. - The
$VIRTUAL_ENV
environment variable points to the folder where your python dependencies are installed exec
is required, so the program does not daemonize itself. This implies thatexec
will replace the current shell with the command, so any instructions after that line will never be executed. Read this post for more information.
The run
file needs to be marked as executable with:
chmod +x run