Autostart python scripts on boot with systemd

Recently I tried to run one of my Python projects on boot, and I was faced with the problem on how to do this elegantly on current Debian based Linux distros. After a bit of googling I found a quick and reliable way by utilizing a systemd service. Never mess again with strangle rc.local files or crontab @reboot solutions. With systemd services you can also reliably access logs and see the status of your process. This is especially useful for Python projects on things like a Raspberry Pi which you use headless and want to start your script as soon as it boots.

How To

Replace <YOUR-NAME> with a name descriptive of your project. Make it memorable because you probably have to remember it at some point.

  1. Find out the path to your python runtime with which

    which python
    

    This will return something like this /usr/bin/python, use this later as <YOUR-PYTHON-PATH>

  2. Create a service via:

    sudo systemctl --force --full edit <YOUR-NAME>.service
    

    And paste

    [Unit]
    Description=<(Optional) Description of your project>
    After=network.target
    
    [Service]
    ExecStart=<YOUR-PYTHON-PATH> <PATH-TO-YOUR-SCRIPT>.py
    
    [Install]
    WantedBy=multi-user.target
    
  3. Save it and reload all Systemd services via

    sudo systemctl daemon-reload
    
  4. Enable autostart on boot of your new service:

    sudo systemctl enable <YOUR-NAME>.service
    

Variations

Time of start

The previous example assumes you want your script to start after the network interfaces were initialized and the OS is ready to use. You can change this behaviour by changing the values of the After= and WantedBy= parameters in the service file.

Virtual Environments

You can also start python scripts utilizing virtual environments this way by explicitly using the path to the python binary of your virtual environment like this:

ExecStart=/home/<PATH-TO-PROJECT>/venv/bin/python <PATH-TO-YOUR-SCRIPT>.py

Changing working directory

You can also change the working directory for your service before you start your script. This is especially useful if you reference relative paths in your code like machine learning models or asset folders. You can do this by adding a WorkingDirectory property to the service. Be aware that you still have to use absolute paths to reference your python executable and your script.

[Service]
WorkingDirectory=/home/user/<PATH-TO-PROJECT>
ExecStart=/home/<PATH-TO-PROJECT>/venv/bin/python <PATH-TO-YOUR-SCRIPT>.py

Execute as user or group

Lastly you can execute your python script as specific Linux user and/or group e.g. as user “pi” if there are some specific permissions requiring this. For this to work you specify a user or group in the service part of the file. This is an example on how to do this for the user pi:

[Unit]
Description=<(Optional) Description of your project>
After=network.target

[Service]
ExecStart=<YOUR-PYTHON-PATH> <PATH-TO-YOUR-SCRIPT>.py
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

Managing the running script

Stop & Restart

You can stop your service by executing:

sudo systemctl stop <YOUR-NAME>.service

The same goes for restarting it via:

sudo systemctl restart <YOUR-NAME>.service

Status & Basic logs

You can check if your service is running or crashed by typing:

sudo systemctl status <YOUR-NAME>.service

This will also show you the last few lines logged by your script (e.g. print statements).

Disable autostart again

You can disable autostart for your new service at any time by typing:

sudo systemctl disable <YOUR-NAME>.service