version: "3.7"

services:
  headscale:
    image: "${HEADSCALE_IMAGE:-ghcr.io/juanfont/headscale:0.29.3}"
    container_name: headscale
    command: serve
    restart: unless-stopped
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    tmpfs:
      - /var/run/headscale:mode=0770,size=1m
    environment:
      HEADSCALE_SERVER_URL: "https://${HEADSCALE_DOMAIN}"
      HEADSCALE_DNS_BASE_DOMAIN: "${HEADSCALE_BASE_DOMAIN}"
    volumes:
      - ./config:/etc/headscale:ro
      - ./data:/var/lib/headscale
    # DSM's reverse proxy connects to this loopback-only host port.
    ports:
      - "127.0.0.1:8080:8080"
    healthcheck:
      test: ["CMD", "headscale", "health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    stop_grace_period: 30s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"
    networks:
      - backend

  headplane:
    image: "${HEADPLANE_IMAGE:-ghcr.io/tale/headplane:0.7.0}"
    container_name: headplane
    restart: unless-stopped
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    environment:
      HEADPLANE_SERVER__COOKIE_SECRET: "${HEADPLANE_COOKIE_SECRET:?Set HEADPLANE_COOKIE_SECRET in .env}"
    ports:
      - "127.0.0.1:8081:3000"
    volumes:
      - ./headplane/config.yaml:/etc/headplane/config.yaml:ro
      - ./headplane/data:/var/lib/headplane
      - ./config:/etc/headscale:ro
    healthcheck:
      test: ["CMD", "/bin/hp_healthcheck"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    depends_on:
      - headscale
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"
    networks:
      - backend

networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.80.0/24
