⚠️ Headplane dado de baja (jul 2026). Ver nota en
Docker/Headscale.md.
Headscale¶
Servidor de coordinación self-hosted para Tailscale/WireGuard mesh VPN. Reemplazo de Tailscale SaaS — los clientes Tailscale siguen funcionando, solo cambian el
--login-servera este servidor.
📁 Rutas y configs¶
| Qué | Dónde |
|---|---|
| Compose | /opt/docker/headscale/compose.yaml |
| Config | /opt/docker/headscale/config/config.yaml |
| Data (DB, claves) | /opt/docker/headscale/data/ |
| Compose backup | /opt/docker/headscale/compose.yaml.bak |
Contenedores: headscale (API, puerto 8528) + headplane (Web UI, puerto 8530)
Red: headscale_net (bridge)
Imagen: headscale/headscale:0.29.1 (distroless) + ghcr.io/tale/headplane:latest
Subdominio: https://headscale.matias7235.com.ar (API) + https://headplane.matias7235.com.ar (UI)
Compose¶
services:
headscale:
image: headscale/headscale:0.29.1
container_name: headscale
restart: unless-stopped
command: ["serve"]
ports:
- "127.0.0.1:8528:8080"
volumes:
- ./config:/etc/headscale:ro
- ./data:/var/lib/headscale
environment:
- TZ=America/Argentina/Buenos_Aires
networks:
- headscale_net
healthcheck:
test: ["CMD", "headscale", "health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
logging:
driver: json-file
options:
max-size: 10m
max-file: 3
headplane:
image: ghcr.io/tale/headplane:latest
container_name: headplane
restart: unless-stopped
ports:
- "127.0.0.1:8530:3000"
volumes:
- ./config:/etc/headplane:ro
- ./data:/var/lib/headplane
- /opt/docker/headscale/config/config.yaml:/etc/headscale/config.yaml:rw
environment:
- TZ=America/Argentina/Buenos_Aires
- HEADPLANE_CONFIG_PATH=/etc/headplane/config.yaml
networks:
- headscale_net
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
logging:
driver: json-file
options:
max-size: 10m
max-file: 3
networks:
headscale_net:
name: headscale_net
driver: bridge
Notas sobre permisos y seguridad¶
- NO usar
read_only: trueen el contenedorheadscale: el binario genera claves Noise en/var/lib/headscale/en el primer arranque. Conread_only: truefalla conpermission deniedal escribirnoise_private.key. cap_drop: [ALL]no se aplica aheadscale: el binario distroless corre como root y necesita acceso completo al bind mount.headplaneSÍ admitecap_drop: [ALL]+security_opt: no-new-privileges: es una app Node.js que escribe a su propia DB en/var/lib/headplane.- Permisos del bind mount de data: la primera vez que se inicia con éxito, los archivos en
/opt/docker/headscale/data/quedan conowner=root(UID 0). El subdirectorio/opt/docker/headscale/data/queda conowner=65532:65532(UID del usuario nonroot del binario distroless) si se hizochown 65532:65532antes del primer arranque. Una vez headscale corre, los archivos de estado (DB, claves) son de root. No modificar. - Headplane requiere
integration.agent.pre_authkey: aunque el agent esté deshabilitado, el campo debe estar presente (puede ser string vacío).