Tutorial

Apache Airflow 3 en un VPS: guía completa y CVE-2026-58076

Automatización10 min de lectura7 pasos

Apache Airflow es la referencia de código abierto para orquestar pipelines de datos en forma de DAG escritos en Python. Con Airflow 3, publicado en abril 2025, la arquitectura se ha rediseñado a fondo: las tareas ya no acceden directamente a la base de metadatos y se comunican mediante una API de ejecución dedicada. Autoalojado en un VPS, Airflow se convierte en tu orquestador central, sin depender de un entorno gestionado facturado por hora.

Contenido· Por qué autoalojar Apache Airflow en un VPS1/10
  1. 01Por qué autoalojar Apache Airflow en un VPS
  2. 02Beneficios concretos del autoalojamiento
  3. 03Airflow 2 o Airflow 3: qué versión elegir en 2026
  4. 04Requisitos técnicos
  5. 05Desplegar Apache Airflow 3 con Docker Compose
  6. 06CVE-2026-58076: corregir la RCE de deserialización (Airflow 3.0.0 → 3.3.0)
  7. 07Migrar de Airflow 2 a Airflow 3: qué se rompe
  8. 08Solución de problemas: mensajes de error habituales
  9. 09Supervisión y mantenimiento de la pila Airflow
  10. 10LocalExecutor frente a CeleryExecutor: cuál elegir

Por qué autoalojar Apache Airflow en un VPS

Airflow es la herramienta que eligen los equipos de datos cuando quieren describir sus pipelines en Python puro: cada DAG es un archivo .py que define tareas, sus dependencias y su planificación. El ecosistema de providers es inmenso (bases SQL, S3, BigQuery, dbt, Spark…) y la comunidad, enorme. Los servicios gestionados facturan caro el entorno por hora; al autoalojar Airflow en un VPS obtienes el mismo motor por el coste de un servidor, y tus DAG se ejecutan cerca de tus fuentes de datos internas. También es una cuestión de control: versiones de los providers, dependencias Python propias, variables y conexiones, todo queda en tus manos. Airflow 3, versión vigente desde abril 2025 (3.3.0 en julio 2026, 3.3.1 en agosto 2026), aporta una arquitectura orientada a API: los workers ya no acceden a PostgreSQL directamente.

Beneficios concretos del autoalojamiento

  • DAG en Python puro, versionados en Git, con dependencias y providers bajo control.
  • Enorme ecosistema de operadores: SQL, cloud, dbt, Spark, HTTP, Kubernetes y más.
  • Scheduler robusto: cron, dependencias entre tareas, backfill y catchup nativos.
  • Workers Celery escalables para absorber cientos de tareas en paralelo.
  • Ejecución cerca de tus bases internas, sin tránsito por una nube de terceros.
  • Coste de un VPS en lugar de un entorno gestionado facturado por hora.
  • Control total de las versiones: quédate en Airflow 2.x o migra a 3 a tu ritmo.

Airflow 2 o Airflow 3: qué versión elegir en 2026

Airflow 3.0 introdujo rupturas importantes. Se han retirado los atributos schedule_interval, los SubDAGs y execution_date; los providers exigen Airflow 3.1 como mínimo desde mayo 2026. Si empiezas un proyecto nuevo, instala Airflow 3 directamente: el archivo docker-compose.yaml oficial ya está adaptado. Si mantienes DAG existentes que usan schedule_interval, execution_date o SubDAGs, quédate en la última versión 2.x y planifica la migración: la documentación oficial ofrece una guía de actualización desde Airflow 2.7 como mínimo. La imagen Docker sigue el mismo esquema: apache/airflow:3.3.1 para la rama estable actual, apache/airflow:2.11.0 para mantenerte en la rama 2.

Requisitos técnicos

Airflow es la pila más exigente de esta serie en configuración CeleryExecutor, porque ejecuta a la vez webserver, scheduler, worker(s), triggerer, un servidor de API interno, Redis y PostgreSQL. La documentación oficial recomienda 4 GB de RAM como mínimo, pero en la práctica cuenta con 4 vCPU y 8 GB para una carga cómoda. Prevé 16 GB si tus DAG cargan pandas o grandes volúmenes. Opta por el modo LocalExecutor (sin Celery ni Redis) si empiezas en un VPS de 4 GB: la pila se reduce a la mitad. También necesitarás Docker 24+ y Docker Compose v2 (no el antiguo docker-compose v1), 40 GB de disco SSD y un dominio apuntando a tu servidor.

Desplegar Apache Airflow 3 con Docker Compose

  1. Preparar las carpetas y descargar el compose oficial

    Crea el directorio de trabajo y descarga el archivo de referencia: mkdir -p /opt/airflow && cd /opt/airflow && curl -LfO 'https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml'. Crea después las subcarpetas que esperan los volúmenes montados: mkdir -p ./dags ./logs ./plugins ./config.

  2. Ajustar el UID y los permisos (paso crítico)

    Airflow exige que los volúmenes montados pertenezcan al mismo UID que el usuario interno del contenedor. Genera el archivo de entorno: echo "AIRFLOW_UID=$(id -u)" > .env. Sin este archivo, el scheduler no puede escribir sus logs y falla al arrancar.

  3. Inicializar la base de datos

    Airflow debe aplicar primero sus migraciones sobre PostgreSQL y crear la cuenta de administrador. Ejecuta: docker compose up airflow-init. El contenedor aplica las migraciones, crea el usuario airflow con contraseña airflow y termina con código 0. Espera ese código 0 antes de continuar.

  4. Arrancar la pila completa

    Lanza todos los servicios en segundo plano: docker compose up -d. Comprueba el estado con docker compose ps — todos los contenedores deben pasar a healthy en 1 a 3 minutos. Si uno se queda en starting, consulta sus logs: docker compose logs airflow-scheduler. El webserver escucha por defecto en el puerto 8080.

  5. Montar el proxy inverso HTTPS

    No expongas nunca el puerto 8080 directamente: la interfaz de Airflow muestra conexiones, variables y logs potencialmente sensibles. Instala Caddy: apt install -y caddy. Crea /etc/caddy/Caddyfile con: airflow.tudominio.com { reverse_proxy localhost:8080 }. Recarga: systemctl reload caddy.

  6. Desplegar tu primer DAG

    Coloca un archivo Python en ./dags/. Un DAG mínimo compatible con Airflow 3 usa schedule en lugar de schedule_interval (eliminado en 3.0): from airflow.sdk import DAG, task, luego with DAG('hello', schedule='@daily', start_date=datetime(2025, 1, 1), catchup=False). El scheduler lo detecta en unos segundos.

  7. Construir una imagen propia para tus dependencias Python

    Para providers o bibliotecas propias (pandas, sqlalchemy, boto3…), no las instales en tiempo de ejecución: construye tu propia imagen. Crea un Dockerfile: FROM apache/airflow:3.3.1, luego USER airflow (obligatorio — los paquetes instalados como root son inaccesibles para el usuario airflow) y RUN pip install --no-cache-dir apache-airflow-providers-amazon==9.0.0 pandas==2.2.0. En docker-compose.yaml, sustituye image: apache/airflow:3.3.1 por build: .. Reconstruye con docker compose build && docker compose up -d.

CVE-2026-58076: corregir la RCE de deserialización (Airflow 3.0.0 → 3.3.0)

Si has seguido los pasos anteriores con una imagen anterior a 3.3.1, estás afectado. CVE-2026-58076 (CVSS 8.8) afecta a Apache Airflow desde 3.0.0 hasta 3.3.0 incluida; la corrección está en 3.3.1. La capa de serialización reconstruía los nodos de excepción (airflow_exc_ser / base_exc_ser) importando una clase cuyo nombre procede del propio blob serializado y luego instanciándola con argumentos de esos mismos datos, sin restricción útil sobre lo que podía importarse. El executor_config de un operador alcanza esa ruta: un autor de DAG puede hacer que se cargue y ejecute un callable arbitrario. El scheduler pasa por ese código en su bucle normal al reconstruir los DAG serializados; el servidor de API pasa por él en una lectura autenticada, por ejemplo al mostrar el detalle de un DAG. La corrección de 3.3.1 restringe la clase importada a subclases de BaseException.

Para actualizar: cambia la etiqueta a apache/airflow:3.3.1 en tu docker-compose.yaml *y* en el FROM de tu imagen propia, después docker compose pull && docker compose up -d. Verifica con docker compose exec airflow-apiserver airflow version.

⚠️ Una actualización hecha por CVE-2026-33264 no basta: ese aviso cubría solo la rama trigger del mismo deserializador — es un punto de entrada distinto y su corrección no cierra este.

⚠️ El vector es el autor del DAG, no un visitante anónimo. Actualizar es necesario; la pregunta añadida es *quién puede dejar un archivo en ./dags y quién tiene cuenta en la interfaz*.

Migrar de Airflow 2 a Airflow 3: qué se rompe

Si tienes DAG existentes, revisa estos puntos antes de actualizar la imagen. schedule_interval se ha eliminado: sustitúyelo por schedule. execution_date ya no está disponible en el contexto de las tareas: usa logical_date. Los SubDAGs se han retirado: migra a TaskGroups o a dynamic task mapping. Los XComs en pickle están desactivados por defecto: tus XComs deben ser tipos serializables en JSON. El acceso directo a la base de metadatos desde el código de tarea (vía Session o settings.engine) ya no funciona: pasa por los hooks oficiales de Airflow. El comando airflow db upgrade sustituye a airflow db init para actualizar un esquema existente.

Solución de problemas: mensajes de error habituales

PermissionError: [Errno 13] Permission denied: '/opt/airflow/logs/scheduler' — falta el archivo .env o AIRFLOW_UID no coincide con el UID del propietario de las carpetas montadas. Corrige con sudo chown -R $(id -u):0 ./dags ./logs ./plugins ./config y reinicia. The scheduler does not appear to be running (banner naranja en la interfaz) — comprueba que el contenedor airflow-scheduler está healthy (docker compose ps); si el banner persiste pero desaparece al recargar, es un falso positivo documentado en el tracker de Airflow, sin impacto funcional. error: invalid command 'webserver' — una dependencia Python instalada ha introducido un conflicto de importación al arrancar: reconstruye la imagen fijando las versiones.

No pongas nunca lógica pesada directamente en el archivo del DAG: el scheduler analiza todos los .py a intervalos regulares (min_file_process_interval, 30 s por defecto), y un import costoso a nivel de módulo ralentiza todo el orquestador. Mantén ligero el código de parsing y traslada el trabajo a las tareas. Con Airflow 3, prefiere el decorador @task (TaskFlow API) a los operadores clásicos: el código es más legible y los XComs se gestionan solos. Activa catchup=False en cada DAG en desarrollo para evitar cientos de ejecuciones retroactivas en el primer arranque. Purga con regularidad la carpeta ./logs.

Supervisión y mantenimiento de la pila Airflow

Airflow 3 expone de forma nativa trazas OpenTelemetry: actívalas con AIRFLOW__METRICS__OTEL_ON=True y apunta a tu colector (Grafana Tempo, Jaeger). Para un panel rápido, Airflow también expone métricas Prometheus mediante el plugin airflow-exporter. Configura docker compose con una política de reinicio (restart: unless-stopped) para que la pila vuelva sola tras reiniciar el VPS. Mantén PostgreSQL actualizado por separado. Purga con regularidad los metadatos antiguos con docker compose exec airflow-scheduler airflow db clean --clean-before-timestamp 2025-01-01 para evitar el crecimiento de la base.

LocalExecutor frente a CeleryExecutor: cuál elegir

Desplace la tabla

CriterioLocalExecutorCeleryExecutor
RAM recomendada4 GB8 GB (16 GB ideal)
Servicios Docker adicionalesNinguno (+ PostgreSQL)Redis + worker(s) Celery
Paralelismo de tareasLimitado al VPSEscalable horizontalmente
Adecuado paraPipelines ligeros, equipos individualesCargas grandes, multi-worker
Complejidad operativaBajaMedia
Comando para activarlo`AIRFLOW__CORE__EXECUTOR=LocalExecutor`Por defecto en el compose oficial

Despliega Airflow en un VPS ServOrbit

VPS con Docker preinstalado, snapshots y ancho de banda incluido: la base adecuada para una pila Airflow en producción.

¿Necesita ayuda?

Consulte nuestro centro de ayuda y nuestra FAQ, o contacte con nuestro equipo: llamada, WhatsApp o correo electrónico. Soporte en francés, inglés y árabe.

Escribir por WhatsAppse abre en una pestaña nueva