--- title: "Cómo hacer despliegues canary con Nginx en Ubuntu 24.04" description: "Configura un despliegue canary con Nginx en Ubuntu 24.04: envía parte del tráfico a la nueva versión, mide errores y promociónala o revierte en segundos." category: "CI/CD DevOps" language: es source: https://cubepath.com/es/docs/ci-cd-devops/estrategia-de-implementacion-canaria-en-linux updated: 2026-09-25 --- # Cómo hacer despliegues canary con Nginx en Ubuntu 24.04 Un despliegue canary publica una versión nueva de tu aplicación solo para una pequeña parte de los usuarios, por ejemplo el 5 %, mientras el resto sigue en la versión estable. Si la nueva versión se comporta bien, aumentas el porcentaje hasta el 100 %; si falla, devuelves todo el tráfico a la versión estable sin que la mayoría de usuarios lo note. En este tutorial configurarás Nginx en Ubuntu 24.04 para repartir el tráfico entre dos versiones de una aplicación con la directiva `split_clients`, forzarás la versión canary con una cookie para hacer pruebas, registrarás qué versión atiende cada petición para comparar errores y latencia, y crearás un pequeño comando para cambiar el porcentaje o revertir de forma segura. ## Requisitos previos - Un servidor con Ubuntu 24.04, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Nginx instalado (`sudo apt install nginx`). - Dos versiones de tu aplicación escuchando en puertos distintos del mismo servidor o de tu red privada. En esta guía la versión estable escucha en `127.0.0.1:8081` y la canary en `127.0.0.1:8082`. Si usas Docker, publica cada contenedor en uno de esos puertos. - Un dominio apuntando al servidor. Usaremos `tu_dominio` como marcador. ## Cómo funciona el reparto de tráfico Nginx ofrece dos piezas que encajan bien para un canary sin módulos adicionales: | Pieza | Qué hace | |-------|----------| | `split_clients` | Calcula un hash de una clave (por ejemplo IP + User-Agent) y asigna un valor según porcentajes. El mismo cliente cae siempre en el mismo grupo, así que no salta de versión entre peticiones. | | `map` | Permite sobrescribir ese resultado, por ejemplo con una cookie `canary=always` para que tu equipo pruebe la versión nueva antes de abrirla a usuarios. | El valor final es el nombre de un bloque `upstream`, que Nginx usa en `proxy_pass`. Cambiar el porcentaje es editar un archivo pequeño y recargar Nginx, lo que no corta conexiones activas. ## Paso 1: Preparar dos versiones de prueba (opcional) Si todavía no tienes tu aplicación desplegada en dos puertos, crea dos servidores de prueba con Python para seguir el tutorial. Cada uno devuelve un texto que identifica la versión: ```bash sudo mkdir -p /srv/app-stable /srv/app-canary echo "version estable v1" | sudo tee /srv/app-stable/index.html echo "version canary v2" | sudo tee /srv/app-canary/index.html ``` Arráncalos como unidades temporales de systemd para que sigan en marcha al cerrar la sesión: ```bash sudo systemd-run --unit=app-stable python3 -m http.server 8081 --bind 127.0.0.1 --directory /srv/app-stable sudo systemd-run --unit=app-canary python3 -m http.server 8082 --bind 127.0.0.1 --directory /srv/app-canary ``` Comprueba que responden: ```bash curl -s http://127.0.0.1:8081/ curl -s http://127.0.0.1:8082/ ``` ```output version estable v1 version canary v2 ``` > Nota: Estos servidores son solo para practicar. Cuando termines, elimínalos con `sudo systemctl stop app-stable app-canary`. ## Paso 2: Crear el archivo con el porcentaje canary Guarda la regla de reparto en un archivo propio. Así el porcentaje se cambia sin tocar el resto de la configuración y es fácil automatizarlo. ```bash sudo nano /etc/nginx/canary-split.conf ``` Empieza enviando el 5 % del tráfico a la versión canary: ```nginx split_clients "${remote_addr}${http_user_agent}" $canary_split { 5% app_canary; * app_stable; } ``` La clave combina la IP y el User-Agent del cliente. El asterisco recoge el resto del tráfico. ## Paso 3: Configurar el sitio en Nginx Ahora crea el sitio que define los dos `upstream`, la anulación por cookie, un formato de log que registra la versión y el proxy. ```bash sudo nano /etc/nginx/sites-available/app ``` ```nginx upstream app_stable { server 127.0.0.1:8081 max_fails=3 fail_timeout=10s; } upstream app_canary { server 127.0.0.1:8082 max_fails=3 fail_timeout=10s; # Si la canary cae, las peticiones pasan a la estable server 127.0.0.1:8081 backup; } include /etc/nginx/canary-split.conf; # La cookie canary=always fuerza la versión nueva, canary=never la estable map $cookie_canary $app_upstream { "always" app_canary; "never" app_stable; default $canary_split; } log_format canary '$time_iso8601 $app_upstream $status $request_time ' '$upstream_addr "$request"'; server { listen 80; listen [::]:80; server_name tu_dominio; access_log /var/log/nginx/canary_access.log canary; location / { proxy_pass http://$app_upstream; proxy_http_version 1.1; proxy_set_header Host $host; 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; # Cabecera para comprobar qué versión respondió add_header X-App-Upstream $app_upstream always; } } ``` Puntos importantes de esta configuración: - `proxy_pass http://$app_upstream;` funciona sin resolver DNS porque el valor coincide con el nombre de un `upstream` definido. - `max_fails` y `fail_timeout` retiran temporalmente un backend que devuelve errores de conexión. - El servidor `backup` del grupo canary evita que los usuarios del 5 % vean errores si la versión nueva no arranca. Desactiva el sitio por defecto si ocupa el puerto 80 con el mismo nombre, activa el nuevo y valida la sintaxis: ```bash sudo rm -f /etc/nginx/sites-enabled/default sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app sudo nginx -t ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Recarga Nginx: ```bash sudo systemctl reload nginx ``` ## Paso 4: Verificar el reparto Simula 1000 clientes distintos variando el User-Agent y cuenta qué versión responde a cada uno: ```bash for i in $(seq 1 1000); do curl -s -A "cliente-$i" -H "Host: tu_dominio" http://127.0.0.1/ done | sort | uniq -c ``` El resultado debe rondar el 95 % / 5 %: ```output 52 version canary v2 948 version estable v1 ``` Comprueba ahora que el mismo cliente siempre recibe la misma versión y que la cookie fuerza la canary: ```bash curl -sI -A "cliente-7" -H "Host: tu_dominio" http://127.0.0.1/ | grep -i x-app-upstream curl -s -H "Host: tu_dominio" --cookie "canary=always" http://127.0.0.1/ ``` ```output X-App-Upstream: app_stable version canary v2 ``` Para que tu equipo pruebe la versión nueva desde el navegador, basta con crear la cookie `canary` con valor `always` para `tu_dominio` desde las herramientas de desarrollo. ## Paso 5: Crear un comando para cambiar el porcentaje Editar el archivo a mano en cada fase funciona, pero es fácil dejar un error de sintaxis y recargar Nginx con él. Este script reescribe `canary-split.conf`, valida la configuración y solo recarga si `nginx -t` pasa; si falla, restaura el archivo anterior. ```bash sudo nano /usr/local/sbin/canary-weight ``` ```bash #!/usr/bin/env bash set -euo pipefail conf=/etc/nginx/canary-split.conf pct="${1:-}" if [[ ! "$pct" =~ ^[0-9]+$ ]] || (( pct > 100 )); then echo "Uso: canary-weight <0-100>" >&2 exit 1 fi backup="$(mktemp)" trap 'rm -f "$backup"' EXIT cp "$conf" "$backup" { echo 'split_clients "${remote_addr}${http_user_agent}" $canary_split {' if (( pct == 0 )); then echo ' * app_stable;' elif (( pct == 100 )); then echo ' * app_canary;' else echo " ${pct}% app_canary;" echo ' * app_stable;' fi echo '}' } > "$conf" if nginx -t -q; then systemctl reload nginx echo "Tráfico canary: ${pct}%" else cp "$backup" "$conf" echo "La configuración no es válida, se ha restaurado la anterior" >&2 exit 1 fi ``` Hazlo ejecutable y pruébalo subiendo al 25 %: ```bash sudo chmod 755 /usr/local/sbin/canary-weight sudo canary-weight 25 ``` ```output Tráfico canary: 25% ``` Repite la prueba del paso 4: ahora alrededor de 250 de las 1000 peticiones deberían llegar a la versión canary. ## Paso 6: Comparar errores y latencia por versión La decisión de avanzar o revertir debe basarse en datos. El log `canary_access.log` registra en cada línea el upstream, el código HTTP y el tiempo de respuesta, así que un solo `awk` compara ambas versiones. Este comando analiza las últimas 50 000 peticiones: ```bash sudo tail -n 50000 /var/log/nginx/canary_access.log | awk ' { n[$2]++ t[$2] += $4 if ($3 >= 500) e[$2]++ } END { for (u in n) printf "%-11s peticiones=%-7d 5xx=%-5d (%.2f%%) latencia_media=%.3fs\n", u, n[u], e[u], 100 * e[u] / n[u], t[u] / n[u] }' ``` ```output app_stable peticiones=37412 5xx=18 (0.05%) latencia_media=0.041s app_canary peticiones=12588 5xx=9 (0.07%) latencia_media=0.044s ``` Si la canary muestra una tasa de 5xx o una latencia claramente superior a la estable, revierte. Si usas Prometheus o otra herramienta de observabilidad, aplica el mismo criterio con las métricas de tu aplicación, separadas por versión. ## Paso 7: Promocionar o revertir Un plan de avance razonable es: | Fase | Tráfico canary | Tiempo mínimo | Criterio para avanzar | |------|----------------|---------------|-----------------------| | 1 | 5 % | 15-30 min | 5xx y latencia similares a la estable | | 2 | 25 % | 30 min | Sin errores nuevos en los logs de la aplicación | | 3 | 50 % | 1 h | Métricas de negocio sin cambios | | 4 | 100 % | - | Promoción completa | **Revertir** es inmediato: devuelve todo el tráfico a la versión estable. ```bash sudo canary-weight 0 ``` **Promocionar** requiere que la versión nueva pase a ser la estable. El proceso seguro es: 1. Envía el 100 % a la canary con `sudo canary-weight 100`. 2. Despliega la versión nueva en el puerto de la estable (`8081`) y comprueba que responde con `curl -s http://127.0.0.1:8081/`. 3. Devuelve el tráfico a la estable con `sudo canary-weight 0`. La versión canary queda libre para el siguiente despliegue. > Consejo: Si tu aplicación usa sesiones o cambios de esquema de base de datos, asegúrate de que ambas versiones son compatibles con los mismos datos mientras conviven. Un canary no protege frente a una migración de base de datos destructiva. ## Solución de problemas **`nginx -t` falla con `"split_clients" directive is not allowed here`.** El `include` de `canary-split.conf` debe estar fuera del bloque `server`, al nivel de los `upstream` y el `map`. **Aparecen errores 502 en el log.** Uno de los backends no responde. Comprueba cuál con `curl -s http://127.0.0.1:8081/` y `curl -s http://127.0.0.1:8082/`, y revisa `/var/log/nginx/error.log`. Si es la canary, revierte con `sudo canary-weight 0` mientras lo investigas. **Todas las peticiones van a la estable aunque el porcentaje sea alto.** Si las pruebas salen siempre desde la misma IP con el mismo User-Agent, el hash da siempre el mismo resultado. Varía el User-Agent como en el paso 4 o usa la cookie `canary=always`. **Los usuarios detrás de un balanceador llegan con la misma IP.** Configura el módulo `realip` de Nginx (`set_real_ip_from` y `real_ip_header`) para que `$remote_addr` sea la IP real del cliente; si no, el reparto es muy desigual. ## Conclusión Has configurado un despliegue canary con Nginx en Ubuntu 24.04: un porcentaje ajustable de usuarios recibe la versión nueva de forma estable, tu equipo puede forzarla con una cookie, cada petición queda registrada con la versión que la atendió y un único comando cambia el porcentaje o revierte con validación previa. Como siguientes pasos, puedes añadir HTTPS con Certbot (`sudo certbot --nginx -d tu_dominio`), llamar a `canary-weight` desde tu pipeline de CI/CD en cada fase, y exportar las métricas por versión a Prometheus para automatizar la decisión de avanzar o revertir.