[SECURITY] Cerrar exposición pública de Coolify (8000) y Realtime (6001–6002) #8

Open
opened 2026-07-30 12:44:13 +00:00 by rafa · 0 comments
Owner

Contexto

Health check read-only del Hetzner (srv1, 30-jul-2026) posterior al incidente de WordPress/Joomla en el hosting antiguo.

No se ha detectado evidencia de compromiso en Hetzner: servicios saludables, sin unidades fallidas, sin cuentas nuevas, sin login SSH ajeno y sin artefactos ejecutables sospechosos. Este issue documenta un hallazgo de hardening preventivo, no una intrusión confirmada.

Hallazgo verificado externamente

Aunque UFW declara DENY IN para el puerto 8000, los puertos Docker publicados siguen accesibles desde Internet:

Puerto Servicio Comprobación
8000/tcp Panel Coolify accesible externamente; responde HTTP 200 / nginx
6001/tcp Coolify Realtime accesible externamente; responde HTTP 200
6002/tcp Coolify Realtime accesible externamente; TCP abierto (HTTP 404)

Mapeos Docker observados:

coolify:          0.0.0.0:8000 -> 8080/tcp
coolify-realtime: 0.0.0.0:6001 -> 6001/tcp
                  0.0.0.0:6002 -> 6002/tcp

Es el comportamiento conocido de Docker: los puertos publicados pueden eludir las reglas convencionales de UFW mediante reglas de forwarding/iptables. La cadena DOCKER-USER está vacía.

Objetivo

Reducir la superficie pública del host. Mantener accesibles solo:

  • 22/tcp — SSH
  • 80/tcp, 443/tcp — proxy/web
  • 22222/tcp — SSH de Gitea

El panel Coolify y los servicios Realtime deben permanecer disponibles solo internamente o a través de un acceso privado deliberado.

Plan cuando se retome

  1. Confirmar cómo se usa actualmente Coolify/Reatime (local, Tailscale, o ambos) para no cortar operaciones.
  2. Aplicar una solución persistente y reversible:
    • preferencia: publicar esos puertos solo en 127.0.0.1; o
    • alternativa: reglas explícitas DOCKER-USER/nftables que bloqueen acceso externo a 8000, 6001, 6002 antes del salto Docker.
  3. Conservar acceso de administración por la vía acordada (SSH tunnel/Tailscale/reverse proxy autenticado).
  4. Verificar desde fuera:
    • 8000, 6001, 6002 deben quedar cerrados o filtrados;
    • 22, 80, 443, 22222 deben seguir accesibles;
    • Coolify, Gitea y despliegues siguen saludables.
  5. Documentar el mecanismo elegido y cómo revertirlo.

Evidencia del health check

  • Host: uptime 31 días; carga ~1; 56 GiB RAM disponibles; disco al 5%; 0 systemd units fallidas.
  • Docker: contenedores activos; servicios con health check en healthy; sin OOM/restarts anómalos detectados.
  • SSH (últimas 48h): accesos exitosos únicamente rafa por clave y root interno de Coolify (10.0.1.5); no hubo logins por contraseña.
  • Fail2ban: activo para SSH; bloquea el ruido de fuerza bruta normal de IP pública.
  • Ficheros: sin nuevos PHP/shells sospechosos; cambios revisados corresponden a caches Laravel, BDs, uploads conocidos y datos de aplicación.

No se han hecho cambios en el servidor durante este health check.

## Contexto Health check read-only del Hetzner (`srv1`, 30-jul-2026) posterior al incidente de WordPress/Joomla en el hosting antiguo. No se ha detectado evidencia de compromiso en Hetzner: servicios saludables, sin unidades fallidas, sin cuentas nuevas, sin login SSH ajeno y sin artefactos ejecutables sospechosos. Este issue documenta un hallazgo de **hardening preventivo**, no una intrusión confirmada. ## Hallazgo verificado externamente Aunque UFW declara `DENY IN` para el puerto 8000, los puertos Docker publicados siguen accesibles desde Internet: | Puerto | Servicio | Comprobación | |---:|---|---| | `8000/tcp` | Panel Coolify | accesible externamente; responde HTTP 200 / nginx | | `6001/tcp` | Coolify Realtime | accesible externamente; responde HTTP 200 | | `6002/tcp` | Coolify Realtime | accesible externamente; TCP abierto (HTTP 404) | Mapeos Docker observados: ```text coolify: 0.0.0.0:8000 -> 8080/tcp coolify-realtime: 0.0.0.0:6001 -> 6001/tcp 0.0.0.0:6002 -> 6002/tcp ``` Es el comportamiento conocido de Docker: los puertos publicados pueden eludir las reglas convencionales de UFW mediante reglas de forwarding/iptables. La cadena `DOCKER-USER` está vacía. ## Objetivo Reducir la superficie pública del host. Mantener accesibles solo: - `22/tcp` — SSH - `80/tcp`, `443/tcp` — proxy/web - `22222/tcp` — SSH de Gitea El panel Coolify y los servicios Realtime deben permanecer disponibles solo internamente o a través de un acceso privado deliberado. ## Plan cuando se retome 1. Confirmar cómo se usa actualmente Coolify/Reatime (local, Tailscale, o ambos) para no cortar operaciones. 2. Aplicar una solución persistente y reversible: - preferencia: publicar esos puertos solo en `127.0.0.1`; o - alternativa: reglas explícitas `DOCKER-USER`/nftables que bloqueen acceso externo a `8000`, `6001`, `6002` antes del salto Docker. 3. Conservar acceso de administración por la vía acordada (SSH tunnel/Tailscale/reverse proxy autenticado). 4. Verificar desde fuera: - `8000`, `6001`, `6002` deben quedar cerrados o filtrados; - `22`, `80`, `443`, `22222` deben seguir accesibles; - Coolify, Gitea y despliegues siguen saludables. 5. Documentar el mecanismo elegido y cómo revertirlo. ## Evidencia del health check - Host: uptime 31 días; carga ~1; 56 GiB RAM disponibles; disco al 5%; 0 systemd units fallidas. - Docker: contenedores activos; servicios con health check en `healthy`; sin OOM/restarts anómalos detectados. - SSH (últimas 48h): accesos exitosos únicamente `rafa` por clave y `root` interno de Coolify (`10.0.1.5`); no hubo logins por contraseña. - Fail2ban: activo para SSH; bloquea el ruido de fuerza bruta normal de IP pública. - Ficheros: sin nuevos PHP/shells sospechosos; cambios revisados corresponden a caches Laravel, BDs, uploads conocidos y datos de aplicación. **No se han hecho cambios en el servidor durante este health check.**
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/server#8