Tutoriales de VPS
Montar Headscale en un VPS (2026): servidor de control Tailscale autoalojado, HTTPS, políticas de acceso y enrutamiento de subredes
Monta en un VPS un servidor de control Headscale autoalojado para Tailscale: HTTPS con Caddy, registro de dispositivos, políticas Grants, enrutamiento de subredes, Exit Node, DERP, copias de seguridad, actualización y resolución de problemas.

Montar Headscale en un VPS (2026): servidor de control Tailscale autoalojado, HTTPS, políticas de acceso y enrutamiento de subredes
Si quieres crear una red con Tailscale pero no quieres entregar la gestión de dispositivos, políticas y nodos a un plano de control alojado, Headscale es básicamente la opción que no puedes evitar.
Pero primero aclaremos un malentendido: Headscale no es un "servicio VPN por el que pasa todo el tráfico a través del VPS". Se encarga del registro de dispositivos, la distribución de claves, las políticas y la coordinación de rutas; cuando dos dispositivos pueden conectarse directamente, los datos reales siguen viajando por WireGuard cifrado punto a punto. Solo cuando falla la conexión directa y se habilita la retransmisión DERP puede que el tráfico pase por un servidor de retransmisión.
Puedes dividirlos en dos capas:
- Headscale: el plano de control que mantienes tú mismo, que decide "quién puede unirse, quién puede acceder a quién";
- Cliente Tailscale: se instala en ordenadores, móviles y servidores y recibe la configuración del plano de control;
- WireGuard: el plano de datos que realmente transporta el tráfico cifrado entre clientes.
Si solo necesitas interconectar tres o cinco máquinas fijas, el tutorial de WireGuard en VPS será más sencillo. Headscale encaja mejor en laboratorios domésticos y equipos pequeños con más dispositivos que necesitan usuarios y etiquetas, enrutamiento de subredes o políticas unificadas.
El coste también es claro: cuando el servidor de control cae, las conexiones existentes no tienen por qué cortarse de inmediato, pero el registro de nuevos dispositivos, las actualizaciones de políticas y la recoordinación de nodos se verán afectados. Las actualizaciones, las copias de seguridad y la renovación del dominio corren de tu cuenta.
Headscale en sí no consume muchos recursos; 1 núcleo, 1 GB de RAM y 10–20 GB de SSD es un punto de partida razonable. Si activas DERP integrado, el ancho de banda de retransmisión puede convertirse en el cuello de botella antes que la CPU y la memoria, así que conviene vigilarlo con monitorización de tráfico de VPS y alertas de exceso.
Prepara un dominio dedicado, por ejemplo headscale.example.com, con un registro A que apunte directamente a la IP pública del VPS.
Si el DNS está alojado en Cloudflare, debes usar la nube gris "solo DNS". El protocolo de control de Headscale actualiza conexiones mediante POST, y el proxy de nube naranja de Cloudflare y Cloudflare Tunnel no admiten esta ruta.
Puertos necesarios:
| Puerto | Uso |
|---|---|
| TCP 22 | Gestión SSH, mejor restringido por origen |
| TCP 80/443 | Emisión de certificados de Caddy y HTTPS |
| UDP 3478 | STUN solo para DERP integrado |
Primero configura SSH y el cortafuegos según la lista de refuerzo de seguridad para VPS, y no te dejes fuera al modificar UFW.
Headscale recomienda actualmente el DEB oficial para Ubuntu 22.04+ o Debian 12+. En el momento de la verificación de este artículo la versión estable era v0.29.2, pero al instalar debes seguir leyendo la última versión estable desde la API de GitHub:
sudo apt update
sudo apt install -y curl jq ca-certificates
headscale_version="$(curl -fsSL https://api.github.com/repos/juanfont/headscale/releases/latest | jq -r '.tag_name | ltrimstr("v")')"
headscale_arch="$(dpkg --print-architecture)"
printf 'version=%s arch=%s\n' "$headscale_version" "$headscale_arch"
curl -fL \
-o /tmp/headscale.deb \
"https://github.com/juanfont/headscale/releases/download/v${headscale_version}/headscale_${headscale_version}_linux_${headscale_arch}.deb"
sudo apt install /tmp/headscale.deb
El paquete oficial crea un usuario dedicado, una configuración de ejemplo y un servicio systemd. No te apresures a abrir puertos; haz una copia de la configuración actual y compárala con el ejemplo completo de la versión actual:
sudo cp /etc/headscale/config.yaml /etc/headscale/config.yaml.before-guide
sudo less /usr/share/doc/headscale/examples/config-example.yaml
sudoedit /etc/headscale/config.yaml
No copies un config.yaml entero de un blog antiguo. Los campos cambian entre versiones; lo más seguro es modificar estas claves en el ejemplo incluido en el paquete:
server_url: https://headscale.example.com
listen_addr: 127.0.0.1:8080
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
trusted_proxies:
- 127.0.0.1/32
- ::1/128
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
policy:
mode: file
path: /etc/headscale/policy.hujson
dns:
magic_dns: true
base_domain: tail.example.net
dns.base_domain no puede usar el mismo dominio que server_url. Mantén listen_addr en la dirección de loopback y expón solo Caddy a internet.
Valida la configuración antes de iniciar:
sudo headscale configtest
sudo systemctl enable --now headscale
sudo systemctl status headscale --no-pager
Para el proceso completo de instalación de Caddy puedes consultar la guía de proxy inverso Caddy en VPS. Tras instalarlo, edita /etc/caddy/Caddyfile:
http://headscale.example.com {
handle /generate_204 {
respond 204
}
handle * {
redir https://{host}{uri}
}
}
headscale.example.com {
reverse_proxy 127.0.0.1:8080 {
header_up True-Client-IP {remote_host}
header_up X-Real-IP {remote_host}
}
}
Comprueba y recarga:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -fsS https://headscale.example.com/health
Cuando el endpoint de salud funcione, confirma que el 8080 no está escuchando en internet:
sudo ss -lntup | grep -E ':443|:8080|:3478'
Crea un usuario en el VPS de Headscale:
sudo headscale users create alice
sudo headscale users list
Instala el cliente oficial de Tailscale en el cliente y luego apúntalo al servidor de control personalizado:
sudo tailscale up --login-server=https://headscale.example.com
El navegador mostrará las instrucciones de registro y un Auth ID. Vuelve al VPS de Headscale para aprobarlo:
sudo headscale auth register --user alice --auth-id AUTH_ID
sudo headscale nodes list
Para el alta automatizada puedes generar una clave de preautenticación de un solo uso:
sudo headscale preauthkeys create --user USER_ID
sudo tailscale up \
--login-server=https://headscale.example.com \
--authkey AUTH_KEY
Por defecto la clave solo se puede usar una vez y es válida durante una hora. Equivale a una credencial temporal; no la escribas en imágenes, repositorios ni en el historial del shell.
Cuando no puedas ejecutar comandos directamente en el móvil, elige usar otro servidor en el menú de cuenta de la app de Tailscale e introduce la https://headscale.example.com completa. El nombre de la entrada puede variar ligeramente entre versiones del cliente, pero la dirección del servidor de control debe coincidir exactamente con server_url. Tras el registro, verifica de inmediato en el servidor el nombre del nodo, el usuario y la última vez en línea; para dispositivos retirados o perdidos, confirma el identificador en la lista de nodos antes de borrarlos, y no te limites a editar Grants en lugar de revocar el dispositivo.
Cuando no hay ninguna política cargada, los nodos de Headscale pueden accederse entre sí por defecto. Primero crea un /etc/headscale/policy.hujson que lo deniegue todo:
{
"grants": []
}
Tras confirmar que la política se carga, añade permisos según sea necesario. Por ejemplo, que los dispositivos personales de Alice se interconecten y que ella pueda acceder a los puertos 22 y 443 de los servidores con la etiqueta tag:server:
{
"tagOwners": {
"tag:server": ["alice@"]
},
"grants": [
{
"src": ["alice@"],
"dst": ["autogroup:self"],
"ip": ["*"]
},
{
"src": ["alice@"],
"dst": ["tag:server"],
"ip": ["22,443"]
}
]
}
Recarga y revisa los registros de análisis:
sudo systemctl reload headscale
sudo journalctl -u headscale -n 100 --no-pager
Cuando una política está mal escrita, no reinicies una y otra vez. Restaura primero la versión anterior del archivo, confirma que los registros no muestran errores de análisis y luego sigue editando.
El enrutamiento de subredes permite que los dispositivos del Tailnet accedan a dispositivos de la LAN que no pueden ejecutar Tailscale; un Exit Node reenvía el tráfico de internet de un cliente a través de un nodo designado. Ambos requieren que el nodo de reenvío los anuncie activamente y que Headscale los apruebe.
En el nodo de reenvío, activa primero el reenvío IP:
printf 'net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\n' |
sudo tee /etc/sysctl.d/99-tailscale.conf
sudo sysctl --system
Anuncia la ruta de la LAN y apruébala:
sudo tailscale set --advertise-routes=192.168.50.0/24
sudo headscale nodes list-routes
sudo headscale nodes approve-routes \
--identifier NODE_ID \
--routes 192.168.50.0/24
El cliente acepta la ruta:
sudo tailscale set --accept-routes
El proceso del Exit Node es similar:
sudo tailscale set --advertise-exit-node
sudo headscale nodes list-routes
sudo headscale nodes approve-routes \
--identifier NODE_ID \
--routes 0.0.0.0/0
sudo tailscale set --exit-node EXIT_NODE_NAME
Aprobar una ruta solo significa que puede usarse; Grants debe seguir limitando qué usuarios pueden acceder a la subred correspondiente o a internet.
Los dispositivos intentan primero la conexión directa UDP. Solo detrás de NAT simétrico, cortafuegos estrictos o redes de operador complejas pueden recurrir a DERP.
Headscale no activa DERP integrado por defecto y seguirá proporcionando a los clientes la lista pública de DERP de Tailscale. Si de verdad quieres autoalojar un repetidor, actívalo en derp.server de config.yaml, mantén verify_clients: true, introduce la IP pública real del VPS y abre UDP 3478.
No vacíes de entrada el DERP público urls. Dejar solo un DERP autoalojado crea un punto único de fallo, y la velocidad de retransmisión está limitada por el ancho de banda y la ruta del VPS.
Comprueba la conexión:
tailscale ping PEER_NAME
tailscale netcheck
tailscale debug derp-map
tailscale debug derp headscale
Que tailscale ping muestre direct significa conexión punto a punto; que muestre via DERP no significa que el cifrado haya fallado, solo que el tráfico da un salto extra.
curl -Iv https://headscale.example.com/health
sudo journalctl -u headscale -n 200 --no-pager
sudo journalctl -u caddy -n 100 --no-pager
Revisa sobre todo si el dominio sigue con la nube naranja de Cloudflare, si la hora del sistema es correcta, si el certificado de Caddy se emitió correctamente y si server_url está configurado con la dirección HTTPS final.
sudo headscale nodes list
tailscale status
sudo systemctl status tailscaled --no-pager
Si el lado de control está en línea pero el cliente está desconectado, lo más probable es un problema del servicio del cliente, DNS, proxy o cortafuegos; sigue revisando con la lista de comprobación de resolución DNS en VPS.
Comprueba primero si Headscale cargó Grants correctamente y luego verifica usuarios, etiquetas, puertos de destino y si las rutas están aprobadas. No vuelvas a poner la política en allow-all permanente solo para "que funcione primero".
Lo esencial que hay que respaldar es SQLite, las claves privadas Noise/DERP, la configuración, las políticas y el Caddyfile. La forma sencilla más fiable es detener brevemente el servicio de control y luego empaquetar:
backup_date="$(date +%F)"
sudo systemctl stop headscale
sudo tar -C / -czf "/root/headscale-backup-${backup_date}.tar.gz" \
etc/headscale \
var/lib/headscale \
etc/caddy/Caddyfile
sudo systemctl start headscale
sudo tar -tzf "/root/headscale-backup-${backup_date}.tar.gz" | head
curl -fsS https://headscale.example.com/health
sudo headscale nodes list
Esto provoca una breve interrupción del plano de control; las conexiones directas existentes suelen continuar, pero no lo hagas durante un registro masivo de dispositivos. Antes de una actualización formal, haz otro simulacro de copia y restauración en VPS.
Orden de actualización:
- Anota el
headscale versionactual; - Haz la copia de seguridad y verifica el archivo comprimido;
- Descarga el nuevo DEB oficial;
- Compara con el
config-example.yamlde la nueva versión; - Ejecuta
headscale configtest; - Tras reiniciar, comprueba health, la lista de nodos, Grants, las rutas y un peer ping real.
Si la actualización falla, instala el DEB de la versión original y restaura la base de datos y la configuración de esa misma copia; no sigas intentándolo con varias versiones sobre un estado roto.
Que la web de health devuelva éxito solo demuestra que el servicio de control es accesible, no que toda la red privada ya funcione. Desde al menos una red externa, completa estas comprobaciones:
- Un dispositivo nuevo puede registrarse por HTTPS y pertenece al usuario correcto en
headscale nodes list; - Dos dispositivos autorizados a comunicarse se resuelven por nombre de host y conectan, y los puertos no autorizados se deniegan de verdad;
tailscale pingdistingue la conexión directa de DERP, y las transferencias se completan de forma estable incluso con retransmisión;- Un cliente con enrutamiento de subredes puede acceder a la dirección de la LAN de destino, y el acceso desaparece al desactivar
--accept-routes; - Si se activa Exit Node, la IP de salida cambia al acceder a internet y vuelve a la salida local al deseleccionarlo;
- Tras reiniciar Headscale y Caddy, los nodos, las políticas y las rutas siguen existiendo;
- Descomprime la copia de seguridad en otra máquina y confirma que la base de datos, las políticas y los archivos de clave privada están realmente incluidos.
Por último, configura monitorización para la renovación del certificado del dominio, el espacio en disco y las anomalías del servicio. El plano de control suele estar tranquilo; lo realmente peligroso es un certificado caducado, un disco lleno y copias de seguridad irrecuperables que pasan desapercibidos mucho tiempo.
- Si quieres tranquilidad y tienes pocos dispositivos: usa directamente el plano de control alojado de Tailscale;
- Si quieres controlar tú mismo los dispositivos y las políticas y puedes asumir el mantenimiento: usa Headscale;
- Si solo tienes unos pocos nodos fijos y no necesitas gestión de usuarios, etiquetas y rutas: usa WireGuard nativo.
El verdadero valor de Headscale no es "Tailscale gratis", sino el control. Solo cuando también gestionas DNS, Grants, copias de seguridad y actualizaciones ese control deja de convertirse en un nuevo punto único de fallo.