VPNSmith
Ferramenta gratuita - servidor Headscale

Gerador de configuração Headscale

Indique o seu domínio, escolha Docker ou o pacote .deb e como o HTTPS é tratado: o gerador escreve o config.yaml, o ficheiro compose ou o script de instalação, o ficheiro do proxy reverso, uma política opcional de exit node e os comandos para criar o primeiro utilizador e ligar um dispositivo. Feito a partir dos ficheiros oficiais do Headscale 0.29.5. Nada sai do seu navegador.

Tudo é gerado no seu navegador. Nada é enviado nem guardado.

Um nome DNS cujo registo A (e AAAA) aponta para o VPS, por exemplo headscale.example.com.

Os dispositivos passam a ser nome.dominio-base. Tem de ser diferente do domínio acima; não precisa de existir publicamente.

Criado com headscale users create. Também é o dono da tag na política de exit node.

Usado pelo certbot ou pelo Headscale para avisos de expiração. O Caddy funciona sem ele.

Método de instalação
HTTPS

O Caddy é o caminho mais curto. Escolha o nginx se já corre no servidor, o TLS integrado se o VPS só corre o Headscale.

DNS de origem para o MagicDNS
Opções
  • Crie o registo DNS do domínio antes de arrancar: o pedido de certificado falha se o nome ainda não apontar para o VPS.

Gerado para https://headscale.example.com · Headscale 0.29.5 · 6 ficheiros

/opt/headscale/config/config.yaml
---
# Headscale 0.29.5: /etc/headscale/config.yaml
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
trusted_proxies: []
noise:
  private_key_path: /var/lib/headscale/noise_private.key
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48
  allocation: sequential
derp:
  server:
    enabled: false
    region_id: 999
    region_code: "headscale"
    region_name: "Headscale Embedded DERP"
    verify_clients: true
    stun_listen_addr: "0.0.0.0:3478"
    private_key_path: /var/lib/headscale/derp_server_private.key
    automatically_add_embedded_derp_region: true
  urls:
    - https://controlplane.tailscale.com/derpmap/default
  paths: []
  auto_update_enabled: true
  update_frequency: 3h
disable_check_updates: false
node:
  expiry: 0
  ephemeral:
    inactivity_timeout: 30m
database:
  type: sqlite
  sqlite:
    path: /var/lib/headscale/db.sqlite
    write_ahead_log: true
    wal_autocheckpoint: 1000
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""
log:
  level: info
  format: text
policy:
  mode: file
  path: "/etc/headscale/policy.json"
dns:
  magic_dns: true
  base_domain: ts.example.com
  override_local_dns: true
  nameservers:
    global:
      - 1.1.1.1
      - 1.0.0.1
      - 2606:4700:4700::1111
      - 2606:4700:4700::1001
    split: {}
  search_domains: []
  extra_records: []
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
  enabled: false
taildrop:
  enabled: true
/opt/headscale/docker-compose.yaml
services:
  headscale:
    image: docker.io/headscale/headscale:0.29.5
    container_name: headscale
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /var/run/headscale
    ports:
      - "127.0.0.1:8080:8080"
      - "127.0.0.1:9090:9090"
    volumes:
      - /opt/headscale/config:/etc/headscale:ro
      - /opt/headscale/lib:/var/lib/headscale
    command: serve
    healthcheck:
      test: ["CMD", "headscale", "health"]

  caddy:
    image: docker.io/library/caddy:2
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - /opt/headscale/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - headscale

volumes:
  caddy_data:
  caddy_config:
/opt/headscale/Caddyfile
http://headscale.example.com {
	# Tailscale captive portal detection
	handle /generate_204 {
		respond 204
	}

	handle * {
		redir https://{host}{uri}
	}
}

headscale.example.com {
	reverse_proxy headscale:8080 {
		header_up True-Client-IP {remote_host}
		header_up X-Real-IP {remote_host}
	}
}
/opt/headscale/config/policy.json
{
  "tagOwners": {
    "tag:exit": [
      "admin@"
    ]
  },
  "autoApprovers": {
    "exitNode": [
      "tag:exit"
    ]
  }
}
setup-headscale.sh
#!/usr/bin/env bash
set -euo pipefail

# 1. Instalar o Docker se faltar (script oficial)
command -v docker >/dev/null || curl -fsSL https://get.docker.com | sudo sh

# 2. Pastas para a configuração e os dados
sudo mkdir -p /opt/headscale/config /opt/headscale/lib
cd /opt/headscale

# 3. Guarde primeiro os ficheiros gerados nestes caminhos
for f in config/config.yaml docker-compose.yaml Caddyfile config/policy.json; do
  [ -f "$f" ] || { echo "Missing /opt/headscale/$f"; exit 1; }
done

# 4. Arrancar o Headscale
sudo docker compose up -d
sleep 5

# 5. Verificação: deve mostrar um estado de saúde em JSON
curl -fsS http://127.0.0.1:8080/health
first-steps.sh
# Criar o primeiro utilizador
sudo docker exec headscale headscale users create admin

# Anotar o ID numérico do utilizador
sudo docker exec headscale headscale users list

# Criar uma chave pré-autenticada (vale 1 hora, uso único por omissão)
sudo docker exec headscale headscale preauthkeys create --user <USER_ID>

# Em cada dispositivo: autenticar-se no seu servidor Headscale
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY>

# No VPS exit node: autenticar-se com a tag para a aprovação automática
sudo tailscale up --login-server https://headscale.example.com --authkey <YOUR_AUTH_KEY> \
  --advertise-exit-node --advertise-tags=tag:exit

# Depois de editar o policy.json: recarregar o Headscale
sudo docker kill --signal=HUP headscale

# Autenticação pelo navegador: aprovar o dispositivo com o Auth ID que mostra
sudo docker exec headscale headscale auth register --user admin --auth-id <AUTH_ID>

# Listar os dispositivos ligados
sudo docker exec headscale headscale nodes list

O Headscale precisa de um servidor sempre ligado

Um VPS pequeno com IPv4 e IPv6 públicos corre estes ficheiros tal como estão, e a mesma máquina pode ser o exit node da sua tailnet.

Link de afiliado: podemos receber uma comissão, sem custo extra para si. O gerador continua gratuito e não depende disso.

Ver o VPS da Contabo

O que fazem os ficheiros gerados

O Headscale é o substituto open source do servidor de controlo da Tailscale: os seus dispositivos continuam a usar as apps oficiais da Tailscale, mas autenticam-se no seu próprio servidor com --login-server. Precisa de três coisas: um endereço HTTPS público na porta 443 igual ao server_url, um base_domain MagicDNS diferente desse endereço e um proxy reverso que deixe passar os upgrades WebSocket se o Headscale não tratar ele próprio do TLS.

O config.yaml é o ficheiro de exemplo completo da versão 0.29.5 com os seus valores: todas as chaves estão presentes e nada depende de um valor por omissão não documentado. Em Docker, o contentor escuta em 0.0.0.0 na sua própria rede e as portas só são publicadas em 127.0.0.1, exceto 80 e 443 quando é o Headscale a terminar o TLS. Atrás de um proxy reverso na mesma máquina, trusted_proxies aponta para localhost para que os IP reais dos clientes apareçam nos registos.

Vários comandos mudaram nas últimas versões, e é por isso que muitos tutoriais falham: as chaves pré-autenticadas criam-se agora com o ID numérico do utilizador (mostrado por headscale users list), e um dispositivo que se autentica pelo navegador é aprovado com headscale auth register e o seu Auth ID. O bloco dos primeiros passos usa a sintaxe 0.29.

Caddy, nginx ou TLS integrado?

Três formas de servir o Headscale em HTTPS, todas documentadas pelo projeto. A escolha certa depende do que já corre no servidor.

HTTPS tratado porCertificadoIdeal quandoAtenção
Caddy (proxy reverso)Automático, renovado pelo CaddyQuer a instalação mais curta ou outros sites no mesmo VPSAs portas 80 e 443 têm de chegar ao Caddy; o WebSocket funciona sem linhas extra
nginx (proxy reverso)certbot, renovado pelo seu temporizadorO nginx já serve outros sites na máquinaOs cabeçalhos Upgrade e Connection são obrigatórios, senão os clientes nunca ligam
Let's Encrypt integrado no HeadscaleAutomático, renovado pelo HeadscaleO VPS só corre o HeadscaleO Headscale ocupa as portas 80 e 443; nenhum outro serviço web nesse IP

Perguntas frequentes

Qual é o config.yaml mínimo do Headscale?
O Headscale lê /etc/headscale/config.yaml. Os valores a mudar são server_url (o seu endereço HTTPS público), listen_addr e dns.base_domain, que tem de ser um domínio diferente do de server_url. O ponto de partida mais seguro é o ficheiro de exemplo da sua versão exata com esses valores editados, que é o que este gerador produz, porque algumas chaves mudam de nome entre versões.
Porque é que o tailscale up fica parado ou falha com o meu servidor Headscale?
Na maioria dos casos o proxy reverso não passa o upgrade WebSocket (nginx sem os cabeçalhos Upgrade e Connection), o server_url não corresponde ao endereço usado pelos clientes ou o certificado não é de confiança. Teste curl https://seu-dominio/health a partir de fora do servidor e depois leia os registos do Headscale. Uma porta diferente de 443 é possível, mas o cliente Tailscale assume 443 em alguns casos.
Como crio uma chave pré-autenticada no Headscale 0.29?
Crie um utilizador com headscale users create <nome>, leia o seu ID numérico com headscale users list e execute headscale preauthkeys create --user <ID>. Por omissão a chave vale uma hora e só pode ser usada uma vez. No dispositivo: tailscale up --login-server https://seu-dominio --authkey <chave>.
Preciso do servidor DERP embutido?
Não. Por omissão o Headscale dá aos clientes os relays DERP públicos da Tailscale, usados apenas quando uma ligação direta é impossível. Ative o DERP embutido se quiser relays sob o seu controlo: é preciso abrir o UDP 3478 e indicar o IPv4 público (e o IPv6, se existir) do servidor.
Que tamanho de VPS precisa o Headscale?
Muito pouco: o servidor de controlo só coordena chaves e rotas, o tráfego passa diretamente entre os dispositivos. Os planos mais pequenos chegam para uma casa ou uma equipa pequena. O que importa é um IPv4 público, idealmente também IPv6, e um fornecedor que deixe abertas as portas 80, 443 e 3478. A mesma máquina pode servir também de exit node.