
Knocker, un servicio de control de acceso basado en knock para tu homelab

Knocker es un servicio autoalojado que proporciona una puerta de enlace de autorización de paquete único (SPA) basada en HTTP de tipo "knock-knock" para tu Homelab, con clientes web, cli + gnome y android. Se puede usar como autenticación para tu proxy inverso como Caddy, o incluso a nivel de firewall usando la integración con FirewallD. Te permite mantener tus servicios completamente privados, abriéndolos bajo demanda solo para direcciones IP autorizadas.
Esto es ideal para entornos de homelab donde quieres exponer servicios a internet sin una conexión VPN persistente, mientras minimizas tu superficie de ataque expuesta públicamente.
Knocker-Web Aplicación web PWA estática que soporta knock (lista blanca) al recargar
Knocker-CLI Una cli escrita en go con soporte para knocks en segundo plano activados opcionalmente por cambios de IP.
Knocker-gnome una extensión de gnome construida sobre Knocker-cli.
Knocker-EXPO Una aplicación Android experimental escrita en React EXPO con soporte para solicitudes de knock en segundo plano
sequenceDiagram
participant User
participant Caddy as Reverse Proxy (Caddy)
participant Knocker
participant Service as Protected Service
User->>Caddy: HTTP request to protected service
Caddy->>Knocker: GET /verify (copies X-Forwarded-For)
Knocker-->>Knocker: check always_allowed_ips / excluded_paths / whitelist
alt IP whitelisted
Knocker-->>Caddy: 200 OK (empty body)
Caddy->>Service: forward request
Service-->>Caddy: 200 OK
Caddy-->>User: 200 OK
else IP not whitelisted
Knocker-->>Caddy: 401 Unauthorized (empty body)
Caddy-->>User: 401 Unauthorized
end
Note over User,Knocker: Performing a "knock" (to add whitelist entry)
User->>Knocker: POST /knock (X-Api-Key, optional ip_address, ttl)
Knocker->>Knocker: validate API key, determine client IP
Knocker->>Knocker: update whitelist.json with expiry
Knocker-->>User: 200 OK (whitelisted_entry, expires_at, expires_in_seconds)
Este proyecto está diseñado para desplegarse como un contenedor Docker usando el archivo docker-compose.yml proporcionado. Utiliza las imágenes docker preconstruidas con soporte para AMD64, ARMv8 y ARMv7
Knocker proporciona diferentes etiquetas de imagen para diferentes casos de uso:
latest Última versión estable (recomendada para producción)v1.2.3 Etiquetas de versión específicas (versiones fijadas)main Rama de desarrollo (actualizaciones continuas, puede ser inestable)Configuración:
knocker.example.yaml a knocker.yaml.knocker.yaml; el ejemplo intencionalmente no contiene valores predeterminados utilizables.trusted_proxies en knocker.yaml: debe contener solo la(s) dirección(es) del propio proxy inverso, no su subred. Debido a que knocker solo confía en X-Forwarded-For de un par listado, una entrada de subred completa (p. ej. 172.16.238.0/24) convierte a cada contenedor en esa red en una autoridad de identidad -- cualquiera de ellos podría reclamar cualquier IP de cliente, o poner en la lista blanca direcciones arbitrarias con una clave normal. Docker no asigna IPs de contenedor estables por defecto, así que fija el proxy con ipv4_address / ipv6_address (ver el servicio caddy comentado en docker-compose.yml) y lista esas direcciones exactas /32 y /128.whitelist.storage_path bajo el directorio de trabajo de la aplicación, /data, o /tmp.firewalld.enabled: true y ajustando la configuración relacionada. Nota: Esto requiere que el contenedor se ejecute como root.Ejecutar el servicio:
docker compose up -d
Esto descargará la imagen preconstruida de knocker e iniciará tanto el servicio knocker como el caddy.
Knocker funciona actuando como una puerta de enlace de autenticación para tu proxy inverso. Ofrece un endpoint de verificación, para comprobar si la IP solicitante está en la lista blanca o no; si no lo está, responderá con un 401 y el proxy inverso rechazará la conexión.
Caddy tiene la directiva forward_auth para comprobar conexiones usando un endpoint de autenticación.
Define un fragmento reutilizable: Es una buena práctica definir un fragmento en tu Caddyfile para la comprobación de autenticación.
Protege tus servicios: Importa el fragmento para cualquier servicio que quieras proteger.
Ejemplo de Caddyfile:
# Caddyfile
# Define a reusable snippet for the knock-knock check.
# It points to the knocker service using Docker's internal DNS.
(knocker_auth) {
forward_auth knocker:8000 {
uri /verify
}
}
# The public endpoint for performing the knock.
# Make sure this domain points to your Caddy server's IP.
knock.your-domain.com {
request_body {
max_size 4KB
}
reverse_proxy knocker:8000
}
# An example protected service.
jellyfin.your-domain.com {
import knocker_auth # Apply the forward_auth check
reverse_proxy jellyfin_service_name:8096
}
Cuando un usuario no está en la lista blanca, la directiva forward_auth de Caddy devolverá una respuesta 401 Unauthorized con un cuerpo vacío.
Nota importante: La directiva handle_errors de Caddy no funciona con las respuestas de forward_auth. La respuesta de error proviene directamente del servicio de autenticación (knocker), no de Caddy en sí, por lo que handle_errors no puede interceptar ni modificar estas respuestas.
Knocker proporciona integración avanzada de firewall a través de firewalld, creando reglas de firewall dinámicas basadas en tiempo que expiran automáticamente según el TTL especificado en las solicitudes de knock. Esta característica opera a nivel de red, permitiéndote usar knocker para servicios no http como ssh o servidores de juegos.