headscale-tailscale-replace.../INSTALLATION_GUIDE.md
시골약사 6e8a7b81fb 📚 Update documentation with Headplane UI access and configuration
- Update INSTALLATION_GUIDE.md:
  * Add Headplane configuration section with proper config.yaml
  * Update docker-compose.yml example with simplified environment variables
  * Add Headplane login instructions and API key information
  * Update troubleshooting section for cookie_secret validation errors
- Update CLIENT_CONNECTION_TEST.md:
  * Add Headplane web UI access information
  * Include external access URL (192.168.0.151:3000/admin/)
  * Add login credentials and API key details
- Update start.sh:
  * Include Headplane UI URLs in installation summary
  * Add external access information for network environments

All documentation now reflects the working Headplane UI configuration
and provides complete setup instructions for both local and external access.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-09 15:12:54 +09:00

8.4 KiB

🚀 Headscale + Headplane 완전 설치 가이드

📋 프로젝트 개요

  • 목표: Tailscale을 완전히 대체하는 자체 호스팅 VPN 솔루션 구축
  • 기술 스택: Docker, Docker Compose, Headscale, Headplane
  • 환경: Ubuntu 24.04 LTS, Docker 27.2.0

🛠️ 사전 요구사항

  • Docker 및 Docker Compose 설치
  • 8070, 3000 포트 사용 가능
  • root 권한 또는 sudo 권한

📁 프로젝트 구조

headscale-setup/
├── docker-compose.yml      # Docker Compose 설정
├── .env                    # 환경변수 (API 키 포함)
├── .env.example           # 환경변수 템플릿
├── config/
│   └── config.yaml        # Headscale 최신 설정
├── headplane-config/
│   └── config.yaml        # Headplane 설정
├── data/                  # SQLite 데이터베이스 (자동 생성)
├── run/                   # 런타임 파일 (자동 생성)
└── start.sh              # 자동 설치 스크립트

🔧 상세 설치 과정

1단계: 환경 준비

# 작업 디렉토리 생성
mkdir -p headscale-setup
cd headscale-setup

# 필요한 하위 디렉토리 생성
mkdir -p config data run headplane-config

2단계: Docker Compose 설정

docker-compose.yml 작성

version: '3.8'

services:
  headscale:
    image: headscale/headscale:latest
    container_name: headscale
    restart: unless-stopped
    command: serve
    environment:
      - TZ=Asia/Seoul
    volumes:
      - ./config:/etc/headscale
      - ./data:/var/lib/headscale
      - ./run:/var/run/headscale
    ports:
      - "8070:8080"     # 외부:내부 (포트 충돌 방지)
      - "9090:9090"     # 메트릭스
    networks:
      - headscale-net
    healthcheck:
      test: ["CMD-SHELL", "nc -z localhost 8080 || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

  headplane:
    image: ghcr.io/tale/headplane:latest
    container_name: headplane
    restart: unless-stopped
    environment:
      - TZ=Asia/Seoul
      - HEADSCALE_URL=http://headscale:8080
      - HEADSCALE_API_KEY=${HEADSCALE_API_KEY}
    volumes:
      - ./headplane-config:/etc/headplane
    ports:
      - "3000:3000"
    depends_on:
      - headscale
    networks:
      - headscale-net

networks:
  headscale-net:
    driver: bridge

3단계: Headscale 설정 파일

config/config.yaml (최신 형식)

---
server_url: http://localhost:8070
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090

private_key_path: /var/lib/headscale/private.key
noise:
  private_key_path: /var/lib/headscale/noise_private.key

# 최신 형식: prefixes 사용
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48

derp:
  server:
    enabled: false
  urls:
    - https://controlplane.tailscale.com/derpmap/default

disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m

database:
  type: sqlite3
  sqlite:
    path: /var/lib/headscale/db.sqlite

# 최신 DNS 설정 형식
dns:
  override_local_dns: true
  nameservers:
    global:
      - 1.1.1.1
      - 8.8.8.8
  search_domains: []
  magic_dns: true
  base_domain: headscale.local

# 최신 정책 설정
policy:
  path: ""

log:
  format: text
  level: info

unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"

logtail:
  enabled: false

randomize_client_port: false

# 간소화된 OIDC 설정
oidc:
  only_start_if_oidc_is_available: false
  issuer: ""
  client_id: ""
  client_secret: ""
  scope: ["openid", "profile", "email"]
  extra_params: {}
  allowed_domains: []
  allowed_users: []

4단계: Headplane 설정 파일

headplane-config/config.yaml

headscale:
  url: http://headscale:8080
  api_key: YOUR_API_KEY_HERE  # 자동 생성됨
  config_strict: false

server:
  host: 0.0.0.0
  port: 3000
  cookie_secret: headscale-ui-secret-32-chars-key  # 정확히 32자
  cookie_secure: false

settings:
  title: "Headscale 관리 패널"
  favicon_url: ""
  custom_css: ""

중요 설정사항:

  • cookie_secret: 정확히 32자여야 함 (설정 검증 오류 방지)
  • config_strict: false: 설정 검증 완화
  • api_key: 설치 시 자동 생성되어 교체됨
  • 설정 파일은 환경변수보다 우선순위가 높음

5단계: 환경변수 설정

.env.example

# Headscale API Key (설치 후 자동 생성됨)
HEADSCALE_API_KEY=your_api_key_here

# 서버 설정
SERVER_URL=http://localhost:8070
LISTEN_ADDR=0.0.0.0:8080

# 데이터베이스 (SQLite 기본)
DB_TYPE=sqlite3
DB_PATH=/var/lib/headscale/db.sqlite

# Magic DNS
MAGIC_DNS=true
BASE_DOMAIN=headscale.local

# 네트워크 설정
IP_PREFIXES=100.64.0.0/10

# 시간대
TZ=Asia/Seoul

5단계: 설치 실행

환경변수 파일 복사

cp .env.example .env

자동 설치 스크립트 실행

chmod +x start.sh
./start.sh

또는 수동 설치

# 1. Headscale 시작
docker-compose up -d headscale

# 2. API 키 생성 (약 30초 대기 후)
sleep 30
API_KEY=$(docker-compose exec -T headscale headscale apikeys create)
echo "Generated API Key: $API_KEY"

# 3. .env 파일에 API 키 입력
sed -i "s/HEADSCALE_API_KEY=your_api_key_here/HEADSCALE_API_KEY=$API_KEY/" .env

# 4. Headplane 시작
docker-compose up -d headplane

🎯 중요한 설정 변경사항

포트 충돌 해결

  • 기존: 8080:8080 (충돌 발생)
  • 변경: 8070:8080 (외부 8070 포트 사용)

최신 Headscale 설정 형식 적용

  • ip_prefixesprefixes (v4/v6 분리)
  • dns_configdns (구조 변경)
  • acl_policy_pathpolicy.path
  • OIDC strip_email_domain 제거

Docker 헬스체크 개선

  • curlnc (netcat 사용)
  • Headplane 의존성 조건 완화

🔍 설치 확인 및 검증

1. 컨테이너 상태 확인

docker-compose ps

2. Headscale API 테스트

curl -s http://localhost:8070/health
# 응답: {"status":"pass"}

3. 로그 확인

docker-compose logs headscale
docker-compose logs headplane

4. 사용자 생성

docker-compose exec headscale headscale users create myuser

5. 사용자 목록 확인

docker-compose exec headscale headscale users list

6. Pre-auth 키 생성

docker-compose exec headscale headscale preauthkeys create --user 1 --reusable --expiration 24h

🚨 문제 해결

포트 충돌 문제

# 8080 포트 사용 중인 프로세스 확인
lsof -i :8080

# 포트를 8070으로 변경하여 해결

Headplane 설정 파일 문제

# cookie_secret 길이 오류 시 (정확히 32자 필요)
echo "headscale-ui-secret-32-chars-key" | wc -c  # 32자 확인

# 설정 파일 재검증
docker-compose logs headplane --tail 10

# 컨테이너 재시작으로 설정 재로드
docker-compose restart headplane

헬스체크 실패

# wget 대신 netcat 사용
# CMD-SHELL을 사용하여 호환성 개선

📊 최종 설치 결과

접속 정보

생성된 정보

  • 사용자: myuser (ID: 1)
  • API 키: 8qRr1IB.tV95CmA0fLaCiGGIgBfeoN9daHceFkzI (자동 생성됨)
  • Pre-auth 키: fc4f2dc55ee00c5352823d156129b9ce2df4db02f1d76a21 (24시간 유효, 재사용 가능)

🔑 Headplane 로그인

  1. 브라우저에서 http://localhost:3000/admin/ 또는 http://192.168.0.151:3000/admin/ 접속
  2. API Key 필드에 입력: 8qRr1IB.tV95CmA0fLaCiGGIgBfeoN9daHceFkzI
  3. Sign In 버튼 클릭

네트워크 설정

  • IPv4: 100.64.0.0/10
  • IPv6: fd7a:115c:a1e0::/48
  • Magic DNS: headscale.local

🔄 Git 관리

브랜치 전략

# 기능 브랜치 생성
git checkout -b feature/working-headscale-setup

# 변경사항 커밋
git add .
git commit -m "🎉 Working Headscale Setup Complete"

# 원격 저장소 푸시
git push -u origin feature/working-headscale-setup

📈 다음 단계

  1. Tailscale 클라이언트 연결 테스트
  2. HTTPS/TLS 인증서 구성
  3. Headplane 한글화 작업
  4. ACL 보안 규칙 설정
  5. 백업 및 모니터링 구성

🎉 결론

Headscale과 Headplane을 사용한 완전한 자체 호스팅 VPN 솔루션이 성공적으로 구축되었습니다. 이제 Tailscale을 완전히 대체할 수 있는 환경이 준비되었습니다.