Files
Docker-Compose-Stacks/headscale-compose.yml

71 lines
2.6 KiB
YAML

# Headscale + Headplane - Standalone Docker Compose Stack
# Headscale: self-hosted Tailscale control server
# Headplane: third-party Headscale web UI
#
# Usage:
# cp headscale.env.example headscale.env
# edit headscale.env
# docker compose --env-file headscale.env -f headscale-compose.yml up -d
#
# Reverse proxy expectation:
# - Proxy the public Headscale hostname to HEADSCALE_HTTP_PORT on this Docker host.
# - Keep Headplane LAN/tailnet-only initially unless explicitly exposed later.
name: headscale
services:
headscale:
container_name: headscale
image: headscale/headscale:${HEADSCALE_VERSION}
restart: unless-stopped
command: serve
labels:
# Required by Headplane's Docker integration so it can locate/restart Headscale.
me.tale.headplane.target: headscale
ports:
# Headscale HTTP API / coordination endpoint. Intended for Pangolin reverse proxy.
- "${HEADSCALE_HTTP_PORT}:8080"
# Metrics/debug listener is bound to localhost in config by default; exposed only on Docker network.
# gRPC is intentionally not published to the host for the initial setup.
volumes:
- ${HEADSCALE_CONFIG_DIR}/config.yaml:/etc/headscale/config.yaml:rw
- ${HEADSCALE_CONFIG_DIR}/dns_records.json:/etc/headscale/dns_records.json:rw
- ${HEADSCALE_DATA_DIR}:/var/lib/headscale:rw
- /etc/localtime:/etc/localtime:ro
healthcheck:
test: ["CMD", "headscale", "version"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
networks:
- headscale-net
headplane:
container_name: headplane
image: ghcr.io/tale/headplane:${HEADPLANE_VERSION}
restart: unless-stopped
depends_on:
headscale:
condition: service_started
ports:
# LAN/tailnet-only admin UI by default. Do not expose publicly until auth/proxy policy is reviewed.
- "${HEADPLANE_HTTP_PORT}:3000"
volumes:
- ${HEADPLANE_CONFIG_DIR}/config.yaml:/etc/headplane/config.yaml:ro
- ${HEADPLANE_SECRETS_DIR}:/run/secrets/headplane:ro
- ${HEADPLANE_DATA_DIR}:/var/lib/headplane:rw
# Shared Headscale config access enables Headplane network/DNS/config management.
- ${HEADSCALE_CONFIG_DIR}/config.yaml:/etc/headscale/config.yaml:rw
- ${HEADSCALE_CONFIG_DIR}/dns_records.json:/etc/headscale/dns_records.json:rw
# Docker socket is read-only; Headplane uses it to find/restart Headscale after config changes.
- /var/run/docker.sock:/var/run/docker.sock:ro
- /etc/localtime:/etc/localtime:ro
networks:
- headscale-net
networks:
headscale-net:
name: headscale-net
driver: bridge