Bart Simons

Bart Simons


Thoughts, stories and ideas.

Bart Simons
Author

Share


Tags


Twitter


Gunicorn as a SystemD service

Beautiful, you have just finished your Python web application, framework or API. You have chosen to use Gunicorn as your web server gateway interface, a solid c…

Bart SimonsBart Simons

Beautiful, you have just finished your Python web application, framework or API. You have chosen to use Gunicorn as your web server gateway interface, a solid choice. Now, you want to make your app manageable and so you want to integrate it with your init system. But the question is: how? This article contains all the information you need to make your Gunicorn-based app manageable with SystemD.

Creating a starting point

At first, we need a sample application that runs behind Gunicorn. The falcon framework is another great and lightweight Python framework to build a test application with. So, here's my example code file called sample.py:

import falcon
import json

class RootPage:
    def on_get(self, req, resp):
        resp.body = "Hello, it works!"

app = falcon.API()
app.add_route('/', RootPage())

Make sure to place this file in a directory called /opt/sampleapp which needs to be created first with mkdir:

adduser --shell=/bin/false --no-create-home --disabled-password
mkdir /opt/sampleapp
chown -R sampleapp:sampleapp /opt/sampleapp

This piece of code can be brought to life with the following command:

gunicorn sample:app -b 0.0.0.0:8000

Your terminal output should look like this:

Gunicorn in action

Integration with SystemD

So now that we got my demo working, let's make it manageable with SystemD! To accomplish that, we first need to know how to daemonize the Gunicorn process and all it's subprocesses. Luckily, we can all do that inside a SystemD service file. Create a file in /etc/systemd/system/ called sampleapp.service and put the following content in it:

[Unit]
Description = SampleApp
After = network.target

[Service]
PermissionsStartOnly = true
PIDFile = /run/sampleapp/sampleapp.pid
User = sampleapp
Group = sampleapp
WorkingDirectory = /opt/sampleapp
ExecStartPre = /bin/mkdir /run/sampleapp
ExecStartPre = /bin/chown -R sampleapp:sampleapp /run/sampleapp
ExecStart = /usr/bin/env gunicorn sample:app -b 0.0.0.0:8000 --pid /run/sampleapp/sampleapp.pid
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID
ExecStopPost = /bin/rm -rf /run/sampleapp
PrivateTmp = true

[Install]
WantedBy = multi-user.target

Don't forget to apply the right permissions on the service file! (chmod 755 sampleapp.service)

Don't forget to execute these commands to make your changes effective:

chmod 755 /etc/systemd/system/sampleapp.service
systemctl daemon-reload

You can now manage your service with one of the following commands listed here:

# Start your service
systemctl start sampleapp.service

# Obtain your services' status
systemctl status sampleapp.service

# Stop your service
systemctl stop sampleapp.service

# Restart your service
systemctl restart sampleapp.service

I got my sample app service started successfully! Here it is:
Sample service in working state

And the web service itself works as well:

Web service in working state

Awesome! So this is how Gunicorn could be managed through and integrated with SystemD. Good luck with your project 🙂

Bart Simons
Author

Bart Simons

Comments