Supervisor is a process control system: you describe programs in config files, and Supervisor starts them, restarts them when they crash, captures their output to log files, and lets you control them with supervisorctl. It’s the standard way to run Laravel queue workers, Celery workers, Python bots and other long-running scripts — especially on systems where you’d rather not write systemd units, or inside containers.
Install
sudo apt install -y supervisor # Debian/Ubuntu
sudo dnf install -y supervisor # RHEL family (EPEL)
sudo systemctl enable --now supervisor
Configs go in /etc/supervisor/conf.d/*.conf (Debian/Ubuntu) or /etc/supervisord.d/*.ini (RHEL).
A program definition
/etc/supervisor/conf.d/telegram-bot.conf:
[program:telegram-bot]
command=/home/bot/app/.venv/bin/python /home/bot/app/bot.py
directory=/home/bot/app
user=bot
environment=PYTHONUNBUFFERED="1",BOT_ENV="production"
autostart=true
autorestart=true
startsecs=5
startretries=10
stopsignal=TERM
stopwaitsecs=30
redirect_stderr=true
stdout_logfile=/var/log/supervisor/telegram-bot.log
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=5
Key options:
| Option | Meaning |
|---|---|
command |
Absolute path to the program — Supervisor doesn’t use your shell’s PATH or aliases |
directory |
Working directory |
user |
Run as this user (don’t run apps as root) |
environment |
Environment variables (KEY="value",KEY2="value") |
autostart / autorestart |
Start with Supervisor / restart when it exits |
startsecs |
Must stay up this long to count as started |
stopwaitsecs |
Grace period before SIGKILL |
numprocs + process_name |
Run several copies (workers) |
stdout_logfile* |
Log capture and built-in rotation |
The program must run in the foreground — if it daemonises itself, Supervisor thinks it exited.
Load and control
sudo supervisorctl reread # detect new/changed config files
sudo supervisorctl update # apply: start new, restart changed
sudo supervisorctl status
sudo supervisorctl restart telegram-bot
sudo supervisorctl stop telegram-bot
sudo supervisorctl tail -f telegram-bot
sudo supervisorctl restart all
Multiple worker processes
[program:worker]
command=php /var/www/app/artisan queue:work --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)02d
numprocs=4
user=deploy
autostart=true
autorestart=true
stopwaitsecs=3600
Creates worker_00 … worker_03. Control them together with supervisorctl restart worker:*. See Laravel queues with Supervisor.
Groups
[group:shop]
programs=worker,scheduler,websocket
supervisorctl restart shop:* restarts the whole group — handy in deploy scripts.
Event listeners and the web UI
Supervisor can notify you when a process enters FATAL (crashing too fast to keep running) via event listeners (e.g. the superlance package’s crashmail). A simple web interface can be enabled in supervisord.conf ([inet_http_server]) — bind it to 127.0.0.1 with a username and password, and reach it through an SSH tunnel.
Troubleshooting
FATAL Exited too quickly— the program crashes on start. Read its log (supervisorctl tail program stderr), run the exactcommandmanually as the configureduser.spawn error— wrong path, missing interpreter, permission problems.- Environment missing — Supervisor doesn’t load
.bashrc; set variables inenvironment=or have the program read an env file. - Config changes ignored — run
rereadandupdate. - Processes survive
stop— child processes didn’t get the signal; addstopasgroup=trueandkillasgroup=true.
Supervisor or systemd?
Both supervise processes well.
- systemd — built into the OS, no extra daemon, rich sandboxing and dependency handling, logs in journald. See systemd unit files.
- Supervisor — one simple INI format for many programs,
numprocsfor worker pools, grouped control, works the same inside containers and across distributions.
For new single services, systemd is usually the natural choice; for pools of application workers (especially in PHP/Python projects), Supervisor remains very convenient.
Related: running a Node app with systemd and running a Python app with systemd.