Bart Simons

gunicorn

A 1 post collection


Gunicorn as a SystemD service

 •  Filed under gunicorn, 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 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 🙂