Raspberry Pi
La Raspberry Pi actúa como puente de red entre el VPS (donde corre la API) y los dispositivos locales del gimnasio (ControlID IdFace, UniFi Controller). Ejecuta Dokploy (con Traefik), Tailscale para el túnel seguro, y una regla de Traefik para reenviar los callbacks de los dispositivos ControlID hacia la API.
Arquitectura de Red
Section titled “Arquitectura de Red”┌─────────────────────┐ ┌─────────────────────────────────┐│ VPS │ │ GYM (VLAN 30) ││ api.vitality-gym │◄──── Tailscale Tunnel ──────►│ ┌─────────────────────┐ ││ .com │ │ │ Raspberry Pi │ ││ (API Hono) │ │ │ 192.168.30.X │ ││ │ Subnet routing permite │ │ Dokploy + Traefik │ ││ │ al VPS alcanzar la VLAN │ │ Tailscale: 100.x │ ││ │ │ └──────────┬──────────┘ ││ │ │ │ LAN ││ │ │ ┌──────────┴──────────┐ ││ │ │ │ IdFace Turnstile │ ││ │ │ │ 192.168.30.Y │ ││ │ │ ├─────────────────────┤ ││ │ │ │ IdFace Premium │ ││ │ │ │ 192.168.30.Z │ ││ │ │ └─────────────────────┘ │└─────────────────────┘ └─────────────────────────────────┘Flujos de datos
Section titled “Flujos de datos”| Flujo | Dirección | Vía | Propósito |
|---|---|---|---|
| API → ControlID | VPS → Dispositivos | Tailscale Subnet Routing | Crear usuarios, enrolar caras, consultar logs |
| ControlID → API | Dispositivos → RPI → VPS | Traefik (regla dinámica) | Monitor webhook (eventos de acceso en tiempo real) |
| API → UniFi | VPS → Controller | Tailscale directo | Portal cautivo WiFi |
Paso 1: Instalar Tailscale
Section titled “Paso 1: Instalar Tailscale”# Instalar Tailscalecurl -fsSL https://tailscale.com/install.sh | sh
# Iniciar sesiónsudo tailscale upSeguir las instrucciones del enlace que aparece para autenticar.
Paso 2: Habilitar Subnet Routing
Section titled “Paso 2: Habilitar Subnet Routing”Esto permite que el VPS alcance los dispositivos en la VLAN 192.168.30.0/24 a través del túnel Tailscale.
# Habilitar IP forwarding (requerido para subnet routing)echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.confecho 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.confsudo sysctl -p /etc/sysctl.d/99-tailscale.conf
# Reiniciar Tailscale con la ruta de la VLANsudo tailscale up --advertise-routes=192.168.30.0/24Aprobar la ruta en Tailscale Admin
Section titled “Aprobar la ruta en Tailscale Admin”- Ir a https://login.tailscale.com/admin/machines
- Buscar la Raspberry Pi en la lista
- Click en los tres puntos (⋮) → Edit route settings
- Activar la ruta
192.168.30.0/24
Verificar conectividad desde el VPS
Section titled “Verificar conectividad desde el VPS”# Desde el VPS, hacer ping a un dispositivo en la VLANping 192.168.30.Y # IP del IdFacePaso 3: Configurar Traefik para el Proxy de ControlID
Section titled “Paso 3: Configurar Traefik para el Proxy de ControlID”Dokploy ya ejecuta Traefik. Solo necesitamos agregar una regla de enrutamiento dinámica para que Traefik reenvíe las peticiones del monitor ControlID hacia la API pública.
3.1 Localizar la configuración de Traefik
Section titled “3.1 Localizar la configuración de Traefik”Dokploy guarda la configuración de Traefik en /etc/dokploy/traefik/. Verificar que exista el directorio de configuración dinámica:
# Ver la estructura de configuración de Traefikls /etc/dokploy/traefik/
# Verificar que el archivo principal referencia un directorio de dynamic configcat /etc/dokploy/traefik/traefik.ymlSi el archivo traefik.yml no tiene un file provider para configuración dinámica, necesitas agregarlo:
# Crear directorio para configuración dinámica (si no existe)sudo mkdir -p /etc/dokploy/traefik/dynamicY agregar al traefik.yml (si no está ya):
providers: file: directory: /etc/dokploy/traefik/dynamic watch: true3.2 Crear la regla dinámica
Section titled “3.2 Crear la regla dinámica”Crear el archivo de configuración dinámica:
sudo nano /etc/dokploy/traefik/dynamic/controlid-proxy.ymlCon el siguiente contenido:
http: routers: controlid-proxy: rule: "PathPrefix(`/api/v1/access-control/`)" entryPoints: - web service: controlid-api
services: controlid-api: loadBalancer: servers: - url: "https://api.vitality-gym.com" passHostHeader: falseExplicación:
- Router
controlid-proxy: Captura todas las peticiones HTTP que llegan con el path/api/v1/access-control/ - Entry point
web: Puerto 80 (HTTP), que es el que usan los dispositivos ControlID - Service
controlid-api: Reenvía al VPS vía HTTPS passHostHeader: false: Envíaapi.vitality-gym.comcomo Host en lugar de la IP de la RPI
3.3 Verificar
Section titled “3.3 Verificar”Traefik detecta automáticamente el archivo nuevo (si watch: true está habilitado). No es necesario reiniciar.
# Probar desde la RPIcurl -X POST http://localhost/api/v1/access-control/monitor/dao \ -H "Content-Type: application/json" \ -d '{"test": true}'
# Probar desde la VLAN (como lo haría un IdFace)curl -X POST http://192.168.30.X/api/v1/access-control/monitor/dao \ -H "Content-Type: application/json" \ -d '{"test": true}'Si recibes una respuesta de la API (aunque sea un error 4xx), el proxy funciona.
Paso 4: Variables de Entorno en la API
Section titled “Paso 4: Variables de Entorno en la API”Agregar las siguientes variables al .env del VPS:
# ============ CONTROLID ACCESS CONTROL ============
# IP de los dispositivos IdFace (accesibles vía Tailscale Subnet Routing)CONTROLID_TURNSTILE_IP=192.168.30.YCONTROLID_PREMIUM_IP=192.168.30.Z
# Credenciales de acceso a los dispositivos (por defecto admin/admin)CONTROLID_TURNSTILE_LOGIN=adminCONTROLID_TURNSTILE_PASSWORD=adminCONTROLID_PREMIUM_LOGIN=adminCONTROLID_PREMIUM_PASSWORD=admin
# URL del callback — IP de la Raspberry Pi en la VLAN# Los dispositivos hacen POST HTTP aquí, Traefik reenvía a la APICONTROLID_API_CALLBACK_URL=http://192.168.30.XPaso 5: Configurar los Dispositivos ControlID
Section titled “Paso 5: Configurar los Dispositivos ControlID”Una vez que los dispositivos estén conectados a la VLAN y tengas sus IPs:
- Acceder a la interfaz web del IdFace:
http://192.168.30.Y - Configurar IP estática en la VLAN (si no usan DHCP reservado)
- Cambiar contraseñas por defecto de admin
- Desde la interfaz de admin de Vitality Gym, usar la función “Configurar Dispositivo” que ejecuta:
POST /set_configuration.fcgicon el monitor apuntando a la RPI- Esto equivale a
http://192.168.30.X/api/v1/access-control/monitor/dao
Troubleshooting
Section titled “Troubleshooting”El VPS no alcanza los dispositivos
Section titled “El VPS no alcanza los dispositivos”# Verificar que subnet routing está activotailscale status
# Verificar IP forwardingsysctl net.ipv4.ip_forward# Debe ser: net.ipv4.ip_forward = 1
# Verificar rutasip route showLos dispositivos no envían eventos al monitor
Section titled “Los dispositivos no envían eventos al monitor”# Verificar que Traefik tiene la ruta cargada# Revisar el dashboard de Traefik en Dokploy o:curl http://localhost:8080/api/http/routers | jq '.[] | select(.name | contains("controlid"))'
# Ver logs de Traefikdocker logs $(docker ps -q --filter "name=traefik") --tail 50Verificar conectividad entre dispositivos y RPI
Section titled “Verificar conectividad entre dispositivos y RPI”# Desde la RPI, verificar que los dispositivos respondencurl -s http://192.168.30.Y/login.fcgi \ -X POST -H "Content-Type: application/json" \ -d '{"login":"admin","password":"admin"}'Resumen de Puertos y Servicios
Section titled “Resumen de Puertos y Servicios”| Servicio | Puerto | Dirección | Protocolo |
|---|---|---|---|
| Traefik (Dokploy) | 80/443 | Entrada general + proxy ControlID | HTTP/HTTPS |
| ControlID IdFace API | 80 | RPI/VPS → Dispositivos | HTTP |
| Tailscale | 41641/UDP | RPI ↔ VPS | WireGuard |
| UniFi Controller | 8080 | VPS → Controller (vía Tailscale) | HTTP |