--- title: "Cómo instalar un servidor MLflow en Ubuntu 24.04" description: "Despliega MLflow en Ubuntu 24.04 con PostgreSQL, artefactos locales, systemd y Nginx con HTTPS, y registra tu primer experimento y modelo desde Python." category: "Infraestructura de IA y ML" language: es source: https://cubepath.com/es/docs/infraestructura-de-ia-y-ml/instalacion-de-mlflow-para-ciclo-de-vida-ml updated: 2026-09-25 --- # Cómo instalar un servidor MLflow en Ubuntu 24.04 MLflow es una plataforma open source para gestionar el ciclo de vida de proyectos de machine learning: registra los parámetros, métricas y artefactos de cada entrenamiento, permite compararlos desde una interfaz web y mantiene un registro versionado de modelos. En este tutorial desplegarás un servidor de seguimiento de MLflow en Ubuntu 24.04 con PostgreSQL como base de datos, artefactos en disco local, un servicio systemd y Nginx con HTTPS y autenticación básica delante. Al final registrarás un experimento y un modelo desde un script de Python en tu equipo. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM y espacio en disco para los artefactos (los modelos pueden ocupar varios GB). - Un usuario no root con privilegios `sudo`. - Un nombre de dominio con un registro A apuntando a la IP del servidor. En esta guía se usa `mlflow.your_domain`. - Los puertos 22, 80 y 443 abiertos en el firewall. - En tu equipo local, Python 3.10 o superior para ejecutar el experimento de ejemplo. ## Paso 1: Instalar PostgreSQL y crear la base de datos MLflow guarda los metadatos (experimentos, ejecuciones, parámetros, métricas y registro de modelos) en una base de datos SQL. PostgreSQL es la opción más robusta para varios usuarios. Instálalo junto con las herramientas de Python: ```bash sudo apt update sudo apt install postgresql python3-venv ``` Genera una contraseña aleatoria para el usuario de base de datos. Usa una hexadecimal para que no contenga caracteres que haya que escapar en la URI de conexión: ```bash openssl rand -hex 16 ``` Copia el valor y úsalo en lugar de `your_db_password` en los siguientes comandos. Crea el usuario y la base de datos: ```bash sudo -u postgres psql -c "CREATE USER mlflow WITH PASSWORD 'your_db_password';" sudo -u postgres createdb -O mlflow mlflow ``` Comprueba que puedes conectarte con ese usuario: ```bash psql "postgresql://mlflow:your_db_password@127.0.0.1/mlflow" -c "SELECT current_user;" ``` ```output current_user -------------- mlflow (1 row) ``` ## Paso 2: Instalar MLflow en un entorno virtual Ubuntu 24.04 no permite instalar paquetes con `pip` en el Python del sistema, y además conviene aislar MLflow para poder actualizarlo sin afectar a nada más. Crea un usuario de sistema y un entorno virtual en `/opt/mlflow`: ```bash sudo useradd --system --home-dir /var/lib/mlflow --create-home --shell /usr/sbin/nologin mlflow sudo python3 -m venv /opt/mlflow/venv sudo /opt/mlflow/venv/bin/pip install --upgrade pip sudo /opt/mlflow/venv/bin/pip install mlflow psycopg2-binary ``` `psycopg2-binary` es el driver que usa MLflow para hablar con PostgreSQL. Verifica la instalación: ```bash /opt/mlflow/venv/bin/mlflow --version ``` ```output mlflow, version 3.4.0 ``` Crea el directorio donde se guardarán los artefactos (modelos, gráficos, ficheros) y dáselo al usuario `mlflow`: ```bash sudo mkdir -p /var/lib/mlflow/artifacts sudo chown -R mlflow:mlflow /var/lib/mlflow ``` ## Paso 3: Crear el servicio systemd Guarda la cadena de conexión en un archivo de entorno aparte para que la contraseña no aparezca en la unidad de systemd ni en `ps`: ```bash sudo mkdir -p /etc/mlflow sudo nano /etc/mlflow/mlflow.env ``` ```ini MLFLOW_BACKEND_STORE_URI=postgresql://mlflow:your_db_password@127.0.0.1:5432/mlflow ``` Restringe los permisos para que solo root y el grupo `mlflow` puedan leerlo: ```bash sudo chown root:mlflow /etc/mlflow/mlflow.env sudo chmod 640 /etc/mlflow/mlflow.env ``` Crea la unidad del servicio: ```bash sudo nano /etc/systemd/system/mlflow.service ``` ```ini [Unit] Description=MLflow tracking server After=network-online.target postgresql.service Wants=network-online.target [Service] Type=simple User=mlflow Group=mlflow WorkingDirectory=/var/lib/mlflow EnvironmentFile=/etc/mlflow/mlflow.env ExecStart=/opt/mlflow/venv/bin/mlflow server \ --backend-store-uri ${MLFLOW_BACKEND_STORE_URI} \ --artifacts-destination /var/lib/mlflow/artifacts \ --host 127.0.0.1 \ --port 5000 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target ``` Estas son las opciones clave: - `--backend-store-uri`: base de datos de metadatos. En el primer arranque MLflow crea las tablas automáticamente. - `--artifacts-destination`: dónde guarda el servidor los artefactos. Los clientes los suben a través del propio servidor HTTP, así que no necesitan acceso al disco ni credenciales de almacenamiento. - `--host 127.0.0.1`: MLflow solo escucha en local; el acceso externo pasará por Nginx con TLS y contraseña. Carga la unidad y arranca el servicio: ```bash sudo systemctl daemon-reload sudo systemctl enable --now mlflow ``` Comprueba su estado y el endpoint de salud: ```bash systemctl status mlflow --no-pager curl http://127.0.0.1:5000/health ``` ```output OK ``` El primer arranque tarda unos segundos mientras se crean las tablas. Si `curl` falla, revisa los logs con `sudo journalctl -u mlflow -n 50 --no-pager`. ## Paso 4: Publicar MLflow con Nginx, HTTPS y autenticación El servidor de MLflow no protege la interfaz ni la API con contraseña. Nginx se encargará del TLS y de la autenticación básica. Instala Nginx, Certbot y la utilidad `htpasswd`: ```bash sudo apt install nginx certbot python3-certbot-nginx apache2-utils ``` Crea un usuario para el acceso. El comando pide la contraseña de forma interactiva: ```bash sudo htpasswd -c /etc/nginx/.htpasswd-mlflow your_user ``` Crea el bloque de servidor: ```bash sudo nano /etc/nginx/sites-available/mlflow ``` ```nginx server { listen 80; listen [::]:80; server_name mlflow.your_domain; client_max_body_size 1G; location / { auth_basic "MLflow"; auth_basic_user_file /etc/nginx/.htpasswd-mlflow; proxy_pass http://127.0.0.1:5000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300s; } } ``` `client_max_body_size` permite subir artefactos grandes como modelos serializados. No se reenvía la cabecera `Host` original: MLflow recibe `127.0.0.1:5000`, que es el host en el que escucha. Activa el sitio, valida la configuración y recarga Nginx: ```bash sudo ln -s /etc/nginx/sites-available/mlflow /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx ``` Abre los puertos web en UFW y obtén el certificado. Certbot modifica el bloque de servidor para añadir HTTPS y la redirección desde HTTP: ```bash sudo ufw allow 'Nginx Full' sudo certbot --nginx -d mlflow.your_domain ``` Comprueba que el acceso sin credenciales se rechaza y con ellas funciona: ```bash curl -I https://mlflow.your_domain/health curl -u your_user https://mlflow.your_domain/health ``` ```output HTTP/1.1 401 Unauthorized ... OK ``` Abre `https://mlflow.your_domain` en el navegador, introduce las credenciales y verás la interfaz de MLflow con el experimento `Default` vacío. ## Paso 5: Registrar un experimento desde Python Los clientes de MLflow se configuran con variables de entorno. `MLFLOW_TRACKING_USERNAME` y `MLFLOW_TRACKING_PASSWORD` hacen que el cliente envíe las credenciales de autenticación básica que exige Nginx. En tu equipo local, crea un entorno virtual con MLflow y scikit-learn: ```bash python3 -m venv ~/mlflow-client ~/mlflow-client/bin/pip install mlflow scikit-learn ``` Exporta la configuración del servidor en la sesión actual: ```bash export MLFLOW_TRACKING_URI=https://mlflow.your_domain export MLFLOW_TRACKING_USERNAME=your_user export MLFLOW_TRACKING_PASSWORD=your_password ``` Crea el script de entrenamiento: ```bash nano entrenar_iris.py ``` ```python import mlflow import mlflow.sklearn from sklearn.datasets import load_iris from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, f1_score from sklearn.model_selection import train_test_split mlflow.set_experiment("clasificacion-iris") params = {"n_estimators": 100, "max_depth": 5, "random_state": 42} X, y = load_iris(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=params["random_state"] ) with mlflow.start_run(run_name="random-forest-base") as run: mlflow.log_params(params) modelo = RandomForestClassifier(**params) modelo.fit(X_train, y_train) predicciones = modelo.predict(X_test) mlflow.log_metric("accuracy", accuracy_score(y_test, predicciones)) mlflow.log_metric("f1", f1_score(y_test, predicciones, average="weighted")) mlflow.sklearn.log_model( sk_model=modelo, name="modelo", input_example=X_test[:2], registered_model_name="IrisClassifier", ) print(f"Run ID: {run.info.run_id}") ``` El script registra los hiperparámetros, dos métricas y el modelo entrenado. Con `registered_model_name`, MLflow además crea (o incrementa) una versión del modelo `IrisClassifier` en el registro. Ejecútalo: ```bash ~/mlflow-client/bin/python entrenar_iris.py ``` ```output Successfully registered model 'IrisClassifier'. Created version '1' of model 'IrisClassifier'. Run ID: 3f2b8c1d9e7a4b5c8d6e1f0a2b3c4d5e ``` En la interfaz web, abre el experimento `clasificacion-iris`: verás la ejecución con sus parámetros y métricas, y en la pestaña de artefactos el modelo serializado. Cambia `max_depth` o `n_estimators`, vuelve a ejecutar el script y usa el botón de comparación para ver las ejecuciones lado a lado. En el servidor, confirma que el artefacto se ha guardado en disco: ```bash sudo find /var/lib/mlflow/artifacts -name MLmodel ``` ## Paso 6: Gestionar versiones con aliases en el registro de modelos Los antiguos estados `Staging` y `Production` están obsoletos en MLflow. La forma actual de marcar qué versión se usa en cada entorno son los aliases: nombres móviles que apuntan a una versión concreta. Crea un script para asignar el alias `champion` a la versión 1: ```bash nano promover.py ``` ```python from mlflow import MlflowClient client = MlflowClient() client.set_registered_model_alias("IrisClassifier", "champion", 1) version = client.get_model_version_by_alias("IrisClassifier", "champion") print(f"champion -> versión {version.version}") ``` ```bash ~/mlflow-client/bin/python promover.py ``` ```output champion -> versión 1 ``` Cualquier aplicación puede cargar ahora el modelo por su alias, sin conocer el número de versión: ```python import mlflow.pyfunc modelo = mlflow.pyfunc.load_model("models:/IrisClassifier@champion") print(modelo.predict([[5.1, 3.5, 1.4, 0.2]])) ``` Cuando entrenes una versión mejor, basta con mover el alias a la nueva versión: las aplicaciones que cargan `@champion` pasan a usarla sin cambios de código. ## Paso 7: Hacer copias de seguridad Todo el estado de MLflow está en dos sitios: la base de datos y el directorio de artefactos. Ambos deben copiarse juntos para que las referencias sean coherentes. Un volcado de PostgreSQL y un archivo de los artefactos son suficientes: ```bash sudo mkdir -p /var/backups/mlflow sudo -u postgres pg_dump -Fc mlflow | sudo tee /var/backups/mlflow/mlflow-$(date +%F).dump > /dev/null sudo tar -czf /var/backups/mlflow/artifacts-$(date +%F).tar.gz -C /var/lib/mlflow artifacts ``` Comprueba que los archivos existen con `ls -lh /var/backups/mlflow` y cópialos fuera del servidor, por ejemplo a un almacenamiento de objetos. ## Solución de problemas **El servicio no arranca y el log muestra `password authentication failed for user "mlflow"`.** La contraseña de `/etc/mlflow/mlflow.env` no coincide con la de PostgreSQL. Cámbiala con `sudo -u postgres psql -c "ALTER USER mlflow WITH PASSWORD 'your_db_password';"` y reinicia con `sudo systemctl restart mlflow`. **`502 Bad Gateway` en el navegador.** Nginx no llega a MLflow. Comprueba que el servicio está activo y escuchando con `sudo ss -tlnp | grep 5000`. **`413 Request Entity Too Large` al registrar un modelo.** El artefacto supera `client_max_body_size`. Aumenta el valor en el bloque de Nginx y recarga con `sudo systemctl reload nginx`. **El cliente devuelve `401` o pide credenciales.** Las variables `MLFLOW_TRACKING_USERNAME` y `MLFLOW_TRACKING_PASSWORD` no están exportadas en la sesión que ejecuta el script. Compruébalo con `env | grep MLFLOW`. ## Conclusión Tienes un servidor de MLflow en Ubuntu 24.04 con PostgreSQL para los metadatos, artefactos servidos por el propio servidor, un servicio systemd y acceso protegido con HTTPS y contraseña. Tu equipo ya puede registrar experimentos y versionar modelos en un único sitio. Como siguientes pasos, programa las copias de seguridad con un timer de systemd, mueve los artefactos a un almacenamiento compatible con S3 si el disco se queda corto y sirve el modelo `@champion` con `mlflow models serve` o en tu propia API.