--- title: "Cómo gestionar procesos con Supervisor en Ubuntu 24.04" description: "Instala Supervisor en Ubuntu 24.04 y úsalo para ejecutar una app Python con Gunicorn y varios workers con reinicio automático, logs rotados y supervisorctl." category: "Despliegue de Aplicaciones" language: es source: https://cubepath.com/es/docs/despliegue-de-aplicaciones/configuracion-de-supervisor-para-gestion-de-procesos updated: 2026-09-25 --- # Cómo gestionar procesos con Supervisor en Ubuntu 24.04 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`. > Nota: si solo necesitas mantener vivo un proceso y no quieres otra dependencia, una unidad de systemd con `Restart=on-failure` hace el mismo trabajo. Supervisor aporta un formato más simple, grupos de procesos, varias instancias de un mismo programa con `numprocs` y un cliente (`supervisorctl`) que puede usar un usuario sin tocar systemd. ## Paso 1: Instalar Supervisor Supervisor está en los repositorios oficiales de Ubuntu. Instálalo con apt: ```bash sudo apt update sudo apt install supervisor ``` El paquete crea el servicio `supervisor` y lo deja habilitado y en marcha. Compruébalo: ```bash systemctl status supervisor ``` ```output ● 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: ```bash supervisord --version ``` ```output 4.2.5 ``` Los ficheros que vas a usar son estos: | Ruta | Uso | |------|-----| | `/etc/supervisor/supervisord.conf` | Configuración principal del demonio | | `/etc/supervisor/conf.d/*.conf` | Un 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.sock` | Socket 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`: ```ini [include] files = /etc/supervisor/conf.d/*.conf ``` > Nota: en Rocky Linux 9 el paquete `supervisor` viene de EPEL (`sudo dnf install epel-release` y después `sudo dnf install supervisor`). Allí el servicio se llama `supervisord`, hay que activarlo con `sudo systemctl enable --now supervisord` y los programas van en `/etc/supervisord.d/*.ini`. ## 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: ```bash 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: ```bash 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: ```bash sudo -u myapp nano /opt/myapp/app.py ``` ```python 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: ```bash cd /opt/myapp && sudo -u myapp /opt/myapp/venv/bin/gunicorn --bind 127.0.0.1:8000 app:app ``` ```output [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: ```bash sudo nano /etc/supervisor/conf.d/myapp.conf ``` ```ini [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: ```bash 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: ```bash sudo supervisorctl reread sudo supervisorctl update ``` ```output myapp: available myapp: added process group ``` Comprueba el estado: ```bash sudo supervisorctl status ``` ```output myapp RUNNING pid 2480, uptime 0:00:12 ``` Y que la aplicación responde: ```bash curl http://127.0.0.1:8000/ ``` ```output 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: ```bash 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: ```bash 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`: ```bash sudo kill -9 $(sudo supervisorctl pid myapp) sleep 6 sudo supervisorctl status myapp ``` ```output 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: ```bash sudo tail -n 3 /var/log/supervisor/supervisord.log ``` ```output 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: ```bash sudo -u myapp nano /opt/myapp/worker.py ``` ```python 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: ```bash sudo nano /etc/supervisor/conf.d/myapp-workers.conf ``` ```ini [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: ```bash sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl status ``` ```output 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: ```bash 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: ```bash sudo nano /etc/supervisor/supervisord.conf ``` Añade esta sección, sustituyendo `your_strong_password` por una contraseña robusta: ```ini [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: ```bash sudo systemctl restart supervisor ``` Desde tu equipo local, abre un túnel hacia el servidor, cambiando `your_user` y `your_server_ip`: ```bash 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`.