71 lines
2.6 KiB
YAML
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
|