Supervisor es un gestor de procesos que arranca tus aplicaciones, las vuelve a levantar si se caen y guarda su salida en ficheros de log, todo desde un formato de configuración INI muy sencillo. Es habitual para servir aplicaciones Python, Node.js o PHP y para mantener workers de colas en marcha. En este tutorial instalarás Supervisor en Ubuntu 24.04, ejecutarás con él una pequeña aplicación web con Gunicorn y un grupo de workers, y aprenderás a controlarlos con supervisorctl.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Conocimientos básicos de la línea de comandos y de un editor como nano.

Paso 1: Instalar Supervisor

Supervisor está en los repositorios oficiales de Ubuntu. Instálalo con apt:

sudo apt update
sudo apt install supervisor

El paquete crea el servicio supervisor y lo deja habilitado y en marcha. Compruébalo:

systemctl status supervisor
● supervisor.service - Supervisor process control system for UNIX
     Loaded: loaded (/usr/lib/systemd/system/supervisor.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-09-25 10:12:03 UTC; 8s ago

Consulta también la versión instalada:

supervisord --version
4.2.5

Los ficheros que vas a usar son estos:

RutaUso
/etc/supervisor/supervisord.confConfiguración principal del demonio
/etc/supervisor/conf.d/*.confUn fichero por programa (se cargan automáticamente)
/var/log/supervisor/Log del demonio y logs de los programas si no indicas otra ruta
/var/run/supervisor.sockSocket UNIX por el que supervisorctl habla con el demonio

En la configuración principal no hace falta cambiar nada. La sección [include] ya carga todos los ficheros de conf.d:

[include]
files = /etc/supervisor/conf.d/*.conf

Paso 2: Preparar una aplicación de ejemplo

Para tener algo real que supervisar, crea una aplicación Flask servida con Gunicorn. Es buena práctica que la aplicación se ejecute con un usuario propio sin privilegios. Crea el usuario de sistema myapp con su directorio:

sudo useradd --system --create-home --home-dir /opt/myapp --shell /usr/sbin/nologin myapp

Instala el soporte de entornos virtuales de Python y crea uno para la aplicación:

sudo apt install python3-venv
sudo -u myapp python3 -m venv /opt/myapp/venv
sudo -u myapp /opt/myapp/venv/bin/pip install flask gunicorn

Crea el código de la aplicación:

sudo -u myapp nano /opt/myapp/app.py
import os
from flask import Flask

app = Flask(__name__)


@app.route("/")
def index():
    return f"Hola desde el proceso {os.getpid()}\n"

Antes de meterla en Supervisor, comprueba que arranca a mano:

cd /opt/myapp && sudo -u myapp /opt/myapp/venv/bin/gunicorn --bind 127.0.0.1:8000 app:app
[2026-09-25 10:15:41 +0000] [2311] [INFO] Starting gunicorn 23.0.0
[2026-09-25 10:15:41 +0000] [2311] [INFO] Listening at: http://127.0.0.1:8000 (2311)

Detenla con Ctrl+C. Si falla aquí, fallará igual dentro de Supervisor, así que conviene resolverlo antes.

Paso 3: Crear la configuración del programa

Cada programa se define en una sección [program:nombre]. Crea el fichero para la aplicación web:

sudo nano /etc/supervisor/conf.d/myapp.conf
[program:myapp]
command=/opt/myapp/venv/bin/gunicorn --workers 2 --bind 127.0.0.1:8000 app:app
directory=/opt/myapp
user=myapp
environment=HOME="/opt/myapp",FLASK_ENV="production"
autostart=true
autorestart=true
startsecs=5
startretries=3
stopsignal=TERM
stopwaitsecs=30
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/myapp/myapp.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5

Qué hace cada opción importante:

  • command: el comando a ejecutar, con ruta absoluta. El proceso debe quedarse en primer plano; no uses opciones que lo manden a segundo plano (como --daemon en Gunicorn), o Supervisor pensará que ha terminado.
  • directory y user: directorio de trabajo y usuario con el que corre el proceso.
  • environment: variables de entorno. Supervisor no cambia HOME al cambiar de usuario, por eso se define aquí.
  • autorestart=true: vuelve a lanzar el proceso siempre que termine. Con unexpected solo lo relanzaría si sale con un código no esperado.
  • startsecs=5: el proceso tiene que seguir vivo 5 segundos para considerarse arrancado. Si muere antes, cuenta como intento fallido; tras startretries intentos pasa a estado FATAL.
  • stopasgroup y killasgroup: envían la señal a todo el grupo de procesos, de modo que los workers hijos de Gunicorn también se detienen.
  • redirect_stderr=true junto con stdout_logfile: un solo log con la salida estándar y la de errores, rotado por Supervisor al llegar a 10 MB y con 5 copias.

Crea el directorio de logs. Supervisor escribe los logs como root, así que basta con que exista:

sudo mkdir -p /var/log/myapp

Paso 4: Cargar y arrancar el programa

Supervisor no lee los cambios automáticamente. reread detecta ficheros nuevos o modificados y update aplica los cambios, arrancando los programas nuevos:

sudo supervisorctl reread
sudo supervisorctl update
myapp: available
myapp: added process group

Comprueba el estado:

sudo supervisorctl status
myapp                            RUNNING   pid 2480, uptime 0:00:12

Y que la aplicación responde:

curl http://127.0.0.1:8000/
Hola desde el proceso 2483

Paso 5: Controlar procesos con supervisorctl

Estos son los comandos que usarás a diario. Todos necesitan sudo porque el socket solo es accesible para root:

sudo supervisorctl stop myapp
sudo supervisorctl start myapp
sudo supervisorctl restart myapp
sudo supervisorctl status myapp

Para ver la salida del programa en directo, como un tail -f sobre su log:

sudo supervisorctl tail -f myapp

Si un programa escribe errores en un log separado (sin redirect_stderr), añade stderr al final: sudo supervisorctl tail -f myapp stderr.

Para comprobar que el reinicio automático funciona, mata el proceso principal a propósito. Obtén su PID con status y envíale SIGKILL:

sudo kill -9 $(sudo supervisorctl pid myapp)
sleep 6
sudo supervisorctl status myapp
myapp                            RUNNING   pid 2531, uptime 0:00:05

El PID ha cambiado: Supervisor ha detectado la caída y ha relanzado la aplicación. En el log del demonio verás el evento:

sudo tail -n 3 /var/log/supervisor/supervisord.log
2026-09-25 10:22:10,114 WARN exited: myapp (terminated by SIGKILL; not expected)
2026-09-25 10:22:11,120 INFO spawned: 'myapp' with pid 2531
2026-09-25 10:22:16,127 INFO success: myapp entered RUNNING state, process has stayed up for > than 5 seconds (startsecs)

Paso 6: Ejecutar varios workers y agruparlos

Un caso muy común es tener varias copias de un worker que procesa una cola. Con numprocs Supervisor lanza N instancias del mismo programa; process_name debe incluir %(process_num)s para que cada una tenga un nombre distinto.

Crea un worker de ejemplo que simule trabajo:

sudo -u myapp nano /opt/myapp/worker.py
import os
import time

while True:
    print(f"worker {os.getpid()} procesando tarea", flush=True)
    time.sleep(10)

El flush=True es importante: sin él, Python guarda la salida en buffer y no verás nada en el log hasta mucho después.

Añade el programa y un grupo que reúna la web y los workers:

sudo nano /etc/supervisor/conf.d/myapp-workers.conf
[program:myapp-worker]
command=/opt/myapp/venv/bin/python /opt/myapp/worker.py
directory=/opt/myapp
user=myapp
process_name=%(program_name)s_%(process_num)02d
numprocs=3
autostart=true
autorestart=true
startsecs=3
stopwaitsecs=30
redirect_stderr=true
stdout_logfile=/var/log/myapp/worker_%(process_num)02d.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5

[group:myapp-stack]
programs=myapp,myapp-worker

Aplica los cambios:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status
myapp-stack:myapp                   RUNNING   pid 2602, uptime 0:00:07
myapp-stack:myapp-worker_00         RUNNING   pid 2603, uptime 0:00:07
myapp-stack:myapp-worker_01         RUNNING   pid 2604, uptime 0:00:07
myapp-stack:myapp-worker_02         RUNNING   pid 2605, uptime 0:00:07

Al formar parte de un grupo, los nombres llevan el prefijo del grupo. Ahora puedes actuar sobre todo el grupo o sobre un proceso concreto:

sudo supervisorctl restart myapp-stack:*
sudo supervisorctl stop myapp-stack:myapp-worker_01

Paso 7: Activar la interfaz web (opcional)

Supervisor incluye una pequeña interfaz web para ver el estado y reiniciar procesos. No la expongas a Internet: escúchala solo en localhost y accede mediante un túnel SSH.

Edita la configuración principal:

sudo nano /etc/supervisor/supervisord.conf

Añade esta sección, sustituyendo your_strong_password por una contraseña robusta:

[inet_http_server]
port=127.0.0.1:9001
username=admin
password=your_strong_password

Los cambios en supervisord.conf requieren reiniciar el servicio, lo que reinicia también todos los programas:

sudo systemctl restart supervisor

Desde tu equipo local, abre un túnel hacia el servidor, cambiando your_user y your_server_ip:

ssh -L 9001:127.0.0.1:9001 your_user@your_server_ip

Con el túnel abierto, entra en http://localhost:9001 en tu navegador e inicia sesión con el usuario y la contraseña configurados.

Solución de problemas

FATAL Exited too quickly (process log may have details). El proceso murió antes de startsecs tantas veces como startretries. Mira su log con sudo supervisorctl tail myapp y prueba el command a mano con el mismo usuario (sudo -u myapp ...). Las causas típicas son rutas relativas, un entorno virtual incorrecto o permisos de ficheros.

ERROR (no such process) al arrancar un programa nuevo. Olvidaste reread y update, o el fichero no termina en .conf. Revisa también la sintaxis: sudo supervisorctl reread muestra el error si una sección está mal escrita.

unix:///var/run/supervisor.sock no such file. El demonio no está en marcha. Revisa sudo systemctl status supervisor y sudo journalctl -u supervisor; suele deberse a un error en supervisord.conf.

El proceso aparece como RUNNING pero no hay nada en el log. La aplicación guarda la salida en buffer. En Python usa flush=True o añade PYTHONUNBUFFERED="1" en environment.

stop deja procesos hijos huérfanos. Activa stopasgroup=true y killasgroup=true en el programa.

Conclusión

Has instalado Supervisor en Ubuntu 24.04, has puesto una aplicación Gunicorn y un grupo de workers bajo su control con reinicio automático y logs rotados, y sabes gestionarlos con supervisorctl. Como siguientes pasos, puedes colocar Nginx delante de Gunicorn como proxy inverso con HTTPS, centralizar los logs de /var/log/myapp o sustituir el worker de ejemplo por uno real de Celery o RQ usando la misma plantilla de numprocs.