Create a Systemd Entry
sudo nano /etc/systemd/system/myapp.service
[Unit]
# After=network.service
Description=My App
[Service]
Type=simple
# WorkingDirectory=/code/python/myapp
ExecStart=/code/scripts/myapp.sh
# User=do-user
[Install]
WantedBy=multi-user.target
# WantedBy=default.target
NOTE: Use After=network.service
if you require network.
Create Bash Script
nano /code/scripts/myapp.sh
#!/bin/bash# cd /code/python/myapppython3 /code/python/myapp/run.py >> /code/logs/myapp.log 2>&1
mkdir /code/logs
Create Python Script
nano /code/python/myapp/run.py
import signalimport timeimport datetimeis_shutdown = Falsedef stop(sig, frame): print(f"SIGTERM at {datetime.datetime.now()}") global is_shutdown is_shutdown = Truedef ignore(sig, frsma): print(f"SIGHUP at {datetime.datetime.now()}")signal.signal(signal.SIGTERM, stop)signal.signal(signal.SIGHUP, ignore)print(f"START at {datetime.datetime.now()}")while not is_shutdown: print('.', end='', flush=True) time.sleep(1)print(f"END at {datetime.datetime.now()}")
Test Systemd
Set file permission
sudo chmod 744 /code/scripts/myapp.shsudo chmod 664 /etc/systemd/system/myapp.service
Enable Service
sudo systemctl daemon-reloadsudo systemctl enable myapp.service
Test Service
sudo systemctl start myapp.service
Check Status
sudo systemctl start status.service
Check Log
tail -f /code/logs/myapp.log
Stop Service
sudo systemctl stop myapp.service
Restart server to test if the service started on reboot
sudo reboot
Anaconda
Systemd is run as root
by default. If you are using Anaconda
(or maybe pyenv
), current user might not run the same python version/environment as root.
NOTE: I tried changing the user via Service.User
, but it still uses the system default python interpreter
python -Vsudo python -V
You can find the python interpreter path using which python
or python -c "import sys; print(sys.executable)"
which pythonsudo which python
Edit the bash script to use the correct python interpreter
/opt/conda/bin/python3 /code/python/myapp/run.py >> /code/logs/myapp.log 2>&1