Categoría: Sistemas operativos

  • Diagnóstico y configuración de un Cloudflare Tunnel paso a paso

    Cloudflare Tunnel (cloudflared) permite exponer un servicio interno a internet sin abrir puertos en el router ni depender de una IP pública — el túnel establece una conexión saliente desde el servidor hacia la red de Cloudflare, y Cloudflare enruta el tráfico entrante hacia esa conexión. Este es un caso real de diagnóstico cuando el servicio falla al arrancar.

    Problema inicial

    El servicio cloudflared fallaba continuamente con este error:

    Tunnel credentials file '/root/.cloudflared/<tunnel-uuid>.json' doesn't exist or is not a file

    Causa

    El archivo de configuración /etc/cloudflared/config.yml tenía placeholders (texto de ejemplo) en lugar del UUID real del túnel — un error común al copiar una configuración de plantilla sin reemplazar los valores genéricos por los datos reales generados al crear el túnel.

    ¿Qué es cada pieza de la configuración?

    • UUID del túnel — identificador único que Cloudflare asigna al crear el túnel (cloudflared tunnel create nombre). Es lo que conecta la configuración local con el túnel registrado en la cuenta de Cloudflare.
    • Archivo de credenciales (.json) — se genera automáticamente en el mismo momento que el UUID, y contiene la clave privada que autentica al servidor ante Cloudflare como el dueño legítimo de ese túnel específico.
    • Ingress rules — las reglas que determinan a qué servicio local se debe redirigir cada hostname que llega a través del túnel.

    Solución aplicada

    1. Editar el archivo de configuración

    vi /etc/cloudflared/config.yml

    Contenido correcto (con el UUID real reemplazando el placeholder):

    tunnel: TUNNEL-UUID-REAL
    credentials-file: /root/.cloudflared/TUNNEL-UUID-REAL.json
    ingress:
      - hostname: subdominio.tudominio.com
        service: http://localhost:8443
      - service: http_status:404

    La última línea (service: http_status:404) es obligatoria en cualquier configuración de ingress: actúa como regla de respaldo, devolviendo un 404 a cualquier hostname que llegue por el túnel y no coincida con ninguna regla anterior — sin ella, cloudflared no arranca.

    2. Verificar permisos del archivo de credenciales

    chmod 600 /root/.cloudflared/TUNNEL-UUID-REAL.json

    El archivo de credenciales contiene una clave privada — permisos 600 (solo lectura/escritura para el propietario) son necesarios tanto por seguridad como porque algunas versiones de cloudflared se niegan a cargar el archivo si los permisos son demasiado permisivos.

    3. Reiniciar el servicio

    systemctl restart cloudflared
    systemctl status cloudflared

    Configuración DNS en Cloudflare

    Además de la configuración local, el túnel necesita un registro DNS que apunte hacia él. Se crea como un CNAME apuntando al dominio especial de Cloudflare Tunnels (cfargotunnel.com), nunca a una IP directa:

    CampoValor
    TypeCNAME
    Namesubdominio
    TargetTUNNEL-UUID-REAL.cfargotunnel.com
    Proxy statusProxied

    El estado Proxied (la nube naranja en el panel de Cloudflare) es lo que hace que el tráfico pase por la red de Cloudflare y llegue al túnel — si se deja en modo «DNS only», el CNAME resuelve a la URL de cfargotunnel.com directamente, lo cual no funciona como se espera para el usuario final.

    Comandos de verificación

    Estado del túnel

    systemctl status cloudflared
    journalctl -u cloudflared -f
    cloudflared tunnel info TUNNEL-UUID-REAL
    cloudflared tunnel list

    Probar conectividad desde el servidor

    # Servicio local, sin pasar por el túnel
    curl -I http://localhost:8443
    
    # A través del túnel, desde afuera
    curl -I https://subdominio.tudominio.com
    curl https://subdominio.tudominio.com

    Probar primero localhost aísla el problema: si el servicio local no responde, el problema es de la aplicación en sí, no del túnel. Si localhost responde pero el dominio público no, el problema está en la configuración del túnel o del DNS.

    Verificar DNS

    # Consulta general, usando el DNS configurado en el sistema
    nslookup subdominio.tudominio.com
    
    # Consulta directa a los nameservers de Cloudflare (evita cachés intermedias)
    dig @ns1.cloudflare.com subdominio.tudominio.com
    nslookup subdominio.tudominio.com ns1.cloudflare.com
    
    # Limpiar la caché DNS local (Linux con systemd-resolved)
    sudo systemd-resolve --flush-caches
    sudo systemd-resolve --statistics

    Consultar directamente a los nameservers de Cloudflare, en vez del resolver local, descarta que el problema sea una caché DNS local desactualizada mostrando un resultado viejo.

    Probar desde Windows

    # PowerShell nativo
    Invoke-WebRequest -Uri https://subdominio.tudominio.com
    
    # curl real de Windows (no el alias de PowerShell)
    curl.exe -I https://subdominio.tudominio.com
    
    # Test de conectividad a nivel de puerto TCP
    Test-NetConnection -ComputerName subdominio.tudominio.com -Port 443
    # Desde CMD
    curl -I https://subdominio.tudominio.com

    Resultado

    • Túnel configurado y funcionando correctamente.
    • Conexiones establecidas con los edge servers de Cloudflare más cercanos.
    • DNS configurado correctamente, resolviendo hacia el túnel.

    Nota importante: las VPNs corporativas pueden bloquear el acceso a dominios detrás de Cloudflare Tunnel, dependiendo de las políticas de firewall/proxy de esa red. Si un usuario reporta que no puede acceder estando conectado a la VPN de su empresa, conviene probar primero desde una conexión sin VPN (o datos móviles) antes de asumir que el problema es del túnel.

    Archivos involucrados

    • Config: /etc/cloudflared/config.yml
    • Credenciales: /root/.cloudflared/TUNNEL-UUID-REAL.json
    • Certificado: /root/.cloudflared/cert.pem
    • Servicio: /etc/systemd/system/cloudflared.service
  • Diagnóstico de bloqueos de apt: locks, debconf y deadlocks de systemd

    Un apt upgrade que se queda colgado rara vez tiene una sola causa — suele ser una cadena de bloqueos que se van destapando uno tras otro. Este es un caso real donde tres problemas distintos se encadenaron: un lock de dpkg, un bloqueo de debconf, y finalmente un deadlock real entre dos servicios de systemd provocado por needrestart.

    Cómo se encadenó el problema

    1. apt.systemd.daily tenía tomado el lock inicialmente — el timer automático de actualizaciones de Ubuntu/Debian corriendo en segundo plano, compitiendo por el mismo recurso que el apt upgrade manual.
    2. Al liberarse ese lock, apareció un bloqueo real en debconf, con el mensaje /var/cache/debconf/config.dat is locked by another process.
    3. Al actualizar libc6 (una librería base que usan prácticamente todos los procesos del sistema), needrestart intentó reiniciar automáticamente los servicios que dependían de ella — y quedó colgado a mitad de ese proceso.
    4. Esto generó un deadlock real entre Zabbix y MySQL: zabbix-server.service estaba en estado restart (running), mientras mysql.service quedó en start (waiting) — cada uno esperando indefinidamente al otro, sin que ninguno pudiera avanzar por sí solo.
    5. Cancelar manualmente los jobs colgados de systemd liberó el bloqueo, y apt pudo terminar correctamente.
    6. El sistema quedó estable, solo pendiente de un reinicio para cargar el nuevo kernel instalado durante la actualización.

    Por qué pasa esto: el rol de needrestart

    needrestart es una herramienta que, tras actualizar paquetes, detecta qué servicios en ejecución siguen usando versiones antiguas de librerías ya reemplazadas (típicamente detectando referencias a archivos .so borrados en memoria), y ofrece reiniciarlos automáticamente para que carguen las versiones nuevas. Es útil en general, pero cuando el paquete actualizado es algo tan fundamental como libc6, la lista de servicios a reiniciar puede ser larga — y si dos de esos servicios tienen una dependencia circular entre sí a nivel de arranque (como Zabbix, que necesita a MySQL corriendo, mientras MySQL en este caso quedó esperando por un recurso que Zabbix tenía tomado), el reinicio automático masivo puede desencadenar exactamente el tipo de deadlock que ocurrió aquí.

    Diagnóstico: ver quién tiene el lock

    sudo lsof /var/lib/dpkg/lock-frontend
    sudo lsof /var/lib/dpkg/lock
    sudo lsof /var/cache/debconf/config.dat

    lsof (list open files) muestra qué proceso tiene abierto un archivo específico — en este caso, los archivos de lock que usan dpkg y debconf para evitar que dos instancias se ejecuten simultáneamente y corrompan el estado de paquetes instalados. Si el comando devuelve un PID, ese es el proceso responsable del bloqueo.

    Detener los procesos automáticos de APT

    sudo systemctl stop apt-daily.service
    sudo systemctl stop apt-daily-upgrade.service
    sudo systemctl stop apt-daily.timer
    sudo systemctl stop apt-daily-upgrade.timer

    Ubuntu y Debian ejecutan actualizaciones automáticas de índices de paquetes (y opcionalmente de seguridad) en segundo plano mediante estos timers. Si uno de ellos está corriendo justo cuando se intenta un apt upgrade manual, ambos procesos compiten por el mismo lock — deteniendo estos servicios temporalmente se elimina esa competencia.

    Limpiar procesos colgados

    sudo kill -9 <PID>

    Último recurso cuando un proceso relacionado con apt/dpkg queda genuinamente colgado (no avanza ni responde) — kill -9 lo termina de forma forzosa, sin darle oportunidad de limpiar sus propios recursos. Debe usarse con cuidado, solo tras confirmar con lsof o ps que el proceso realmente está detenido y no simplemente trabajando lento.

    Reparar el estado de dpkg

    sudo dpkg --configure -a
    sudo apt -f install

    dpkg --configure -a retoma y completa la configuración de cualquier paquete que haya quedado a medias (por una interrupción, un lock forzado a matar, etc.). apt -f install («fix broken») resuelve dependencias rotas que hayan quedado como resultado.

    Ver y cancelar jobs pendientes en systemd

    # Listar jobs de systemd en curso o en espera
    systemctl list-jobs
    
    # Cancelar jobs específicos por su número de job (no PID de proceso)
    sudo systemctl cancel 2421271 2421892

    Esto fue lo que realmente destrabó el problema en este caso. Un «job» de systemd es una operación de cambio de estado en curso sobre una unidad (arrancar, detener, reiniciar) — cuando dos jobs quedan esperándose mutuamente (como el restart de Zabbix esperando el start de MySQL, y viceversa por otra dependencia), systemctl list-jobs los muestra con su estado (running o waiting), y cancel con el número de job los elimina de la cola sin necesidad de matar procesos a nivel de sistema operativo.

    Reiniciar servicios manualmente si hace falta

    sudo systemctl restart mysql
    sudo systemctl restart zabbix-server

    Tras romper el deadlock cancelando los jobs colgados, conviene reiniciar los servicios afectados manualmente, en el orden correcto de dependencia (la base de datos primero, el servicio que depende de ella después) para asegurar que ambos queden arriba de forma limpia.

    Validar el estado final

    sudo dpkg --configure -a
    sudo apt -f install
    sudo apt upgrade

    Repetir estos comandos confirma que ya no quedan paquetes a medio configurar ni dependencias rotas, y permite completar la actualización que originalmente se había colgado.

    Revisar servicios fallidos

    systemctl --failed

    Lista únicamente las unidades que quedaron en estado failed tras todo el proceso — un chequeo final rápido para confirmar que ningún otro servicio quedó afectado colateralmente por el deadlock o por los reinicios forzados.

    Reiniciar para cargar el kernel nuevo

    sudo reboot

    Cuando la actualización incluye un kernel nuevo (común en actualizaciones de libc6 y paquetes base), el sistema sigue corriendo con el kernel anterior en memoria hasta el próximo reinicio. No es urgente hacerlo de inmediato si el sistema está estable — se puede programar para una ventana de mantenimiento sin prisa.

    # Confirmar el kernel cargado después del reinicio
    uname -r

    Resumen del flujo de diagnóstico

    1. Si apt no avanza: verificar locks con lsof sobre los archivos de dpkg y debconf.
    2. Detener los timers automáticos de apt-daily si están compitiendo por el lock.
    3. Si un proceso está genuinamente colgado (no solo lento), terminarlo con kill -9 tras confirmarlo.
    4. Reparar con dpkg --configure -a y apt -f install.
    5. Si el problema persiste tras esto, revisar systemctl list-jobs — puede haber un deadlock real entre servicios provocado por needrestart, especialmente tras actualizar librerías base como libc6.
    6. Cancelar los jobs colgados con systemctl cancel, reiniciar manualmente los servicios afectados en el orden correcto de dependencia, y validar con systemctl --failed.