{"captainVersion":4,"services":{"$$cap_appname":{"volumes":["$$cap_appname-data:/var/lib/headscale"],"restart":"always","caproverExtra":{"containerHttpPort":"8080","websocketSupport":"true","dockerfileLines":["FROM debian:bookworm-slim AS headscale-config","RUN mkdir -p /etc/headscale /var/lib/headscale /var/run/headscale","RUN printf '%s\\n' 'server_url: https://$$cap_public_domain' 'listen_addr: 0.0.0.0:8080' 'metrics_listen_addr: 127.0.0.1:9090' 'grpc_listen_addr: 127.0.0.1:50443' 'grpc_allow_insecure: false' '' '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' ' urls:' ' - https://controlplane.tailscale.com/derpmap/default' ' paths: []' ' auto_update_enabled: true' ' update_frequency: 3h' '' 'disable_check_updates: true' 'ephemeral_node_inactivity_timeout: 30m' '' 'database:' ' type: sqlite' ' debug: false' ' gorm:' ' prepare_stmt: true' ' parameterized_queries: true' ' skip_err_record_not_found: true' ' slow_threshold: 1000' ' 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: \"\"' '' 'dns:' ' magic_dns: true' ' base_domain: $$cap_tailnet_domain' ' override_local_dns: true' ' nameservers:' ' global:' ' - 1.1.1.1' ' - 1.0.0.1' ' split: {}' ' search_domains: []' ' extra_records: []' '' 'unix_socket: /var/run/headscale/headscale.sock' 'unix_socket_permission: \"0770\"' '' 'logtail:' ' enabled: false' '' 'randomize_client_port: false' '' 'taildrop:' ' enabled: true' > /etc/headscale/config.yaml","FROM headscale/headscale:$$cap_headscale_version","USER 0","COPY --from=headscale-config /etc/headscale/config.yaml /etc/headscale/config.yaml","COPY --from=headscale-config /var/run/headscale /var/run/headscale","COPY --from=headscale-config /var/lib/headscale /var/lib/headscale","EXPOSE 8080","CMD [\"serve\"]"]}}},"caproverOneClickApp":{"variables":[{"id":"$$cap_headscale_version","label":"Headscale version","defaultValue":"v0.28.0","description":"Headscale Docker image tag. See https://github.com/juanfont/headscale/releases","validRegex":"/^v?[0-9]+(\\.[0-9]+){2}.*$/"},{"id":"$$cap_public_domain","label":"Public Headscale domain","defaultValue":"$$cap_appname.$$cap_root_domain","description":"Public HTTPS domain for Headscale. This must exactly match the CapRover app domain.","validRegex":"/^[a-zA-Z0-9.-]+$/"},{"id":"$$cap_tailnet_domain","label":"MagicDNS base domain","defaultValue":"tailnet.local","description":"Internal MagicDNS base domain. It must be different from the public Headscale domain.","validRegex":"/^[a-zA-Z0-9.-]+$/"}],"instructions":{"start":"Deploy Headscale, an open-source Tailscale control server, behind CapRover HTTPS.\n\nUse a public HTTPS domain for $$cap_public_domain, then enable HTTPS for this app after deployment.\nThis template uses SQLite storage in a persistent volume and external Tailscale DERP relays.","end":"Headscale is deployed.\n\nNext steps:\n1. Enable HTTPS for https://$$cap_public_domain in CapRover.\n2. Verify WebSocket support is enabled for this app in CapRover.\n3. Verify https://$$cap_public_domain/health returns OK.\n4. Create a user:\n docker exec -it /ko-app/headscale users create pi\n5. Find the numeric user ID:\n docker exec -it /ko-app/headscale users list\n6. Create a preauth key with the numeric user ID:\n docker exec -it /ko-app/headscale preauthkeys create --user \n7. Connect a client:\n tailscale up --login-server https://$$cap_public_domain --auth-key "},"displayName":"Headscale","isOfficial":true,"description":"Self-hosted Tailscale control server with SQLite persistence.","documentation":"https://headscale.net/stable/setup/install/container/"}}