Posted on:February 4, 2026 at 12:00 AM

Tailscale VPN 접근 설정 가이드

Tailscale VPN 접근 설정 가이드

Tailscale VPN 접근 설정 가이드

날짜: 2026-02-04 목표: 앱 접근을 Tailscale VPN 사용자만으로 제한

현재 구성

  • 도메인: myapp.example.com (Cloudflare 경유)
  • 인프라: NGINX Ingress가 있는 GKE 클러스터
  • 서비스: NextJS 프론트엔드, FastAPI 백엔드, RQ Dashboard
  • 현재 접근 제어: IP 화이트리스트 (203.0.113.10/32)
  • Tailscale 플랜: Enterprise 체험판 (2026년 2월 13일 만료)

설정 완료 후

  • Tailscale VPN에 연결된 경우에만 앱 접근 가능
  • 커스텀 도메인 myapp.example.com 사용 (또는 Tailscale MagicDNS)
  • 자동 HTTPS (Tailscale 경유)
  • 공개 인터넷에서 완전히 차단

결정: 커스텀 도메인 vs MagicDNS

옵션 A: MagicDNS (추천 - 먼저 시작)

  • 접근 URL: https://myapp.your-tailnet.ts.net
  • 장점: 자동 HTTPS, 간단한 설정, 즉시 사용 가능
  • 단점: 커스텀 도메인이 아님

옵션 B: 커스텀 도메인

  • 접근 URL: https://myapp.example.com
  • 장점: 기존 도메인 사용
  • 단점: 더 복잡한 설정, Split-Horizon DNS 필요

추천: 옵션 A(MagicDNS)로 시작하고, 필요하면 나중에 커스텀 도메인을 추가하세요.


Part 1: Tailscale Kubernetes Operator 설치

Step 1: OAuth 클라이언트 생성

  1. Tailscale OAuth Clients로 이동
  2. “Generate OAuth client” 클릭
  3. 설정:
    • 설명: k8s-operator-my-app
    • 스코프: devices:write 선택 (필수)
    • 태그: tag:k8s
  4. Client ID와 Client Secret 복사 및 저장

Step 2: Helm으로 Operator 설치

helm repo add tailscale https://pkgs.tailscale.com/helmcharts
helm repo update

helm upgrade --install \
  tailscale-operator \
  tailscale/tailscale-operator \
  --namespace=tailscale \
  --create-namespace \
  --set-string oauth.clientId="<YOUR_OAUTH_CLIENT_ID>" \
  --set-string oauth.clientSecret="<YOUR_OAUTH_CLIENT_SECRET>" \
  --wait

Step 3: 설치 확인

kubectl get pods -n tailscale

Part 2: 앱을 Tailscale에 노출

단일 NGINX 프록시를 만들어 모든 서비스(NextJS, FastAPI, RQ Dashboard)로 라우팅합니다.

Step 1: Tailscale Ingress 매니페스트 생성

k8s/charts/my-app/templates/tailscale-ingress.yaml 파일 생성:

{{- if .Values.tailscale.enabled -}}
apiVersion: v1
kind: Service
metadata:
  name: app-tailscale-ingress
  namespace: {{ .Release.Namespace }}
  annotations:
    tailscale.com/expose: "true"
    tailscale.com/hostname: "myapp"
    tailscale.com/tags: "tag:k8s"
spec:
  type: LoadBalancer
  loadBalancerClass: tailscale
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector:
    app: app-nginx-proxy
{{- end }}

Step 2: values.yaml 업데이트

tailscale:
  enabled: false # 배포 준비가 되면 true로 변경
  hostname: "myapp"

Step 3: 배포

helm upgrade my-app ./k8s/charts/my-app \
  -f path/to/values-orbit.yaml \
  --namespace my-app

Part 3: 확인 및 테스트

Tailscale 디바이스 확인

  1. Tailscale Machines로 이동
  2. “myapp” 디바이스 찾기
  3. Tailscale IP(100.x.x.x)와 MagicDNS 이름 확인

접근 테스트

# Tailscale 연결
tailscale up

# MagicDNS로 접근 테스트
curl http://myapp.your-tailnet.ts.net

# 브라우저에서 열기
open https://myapp.your-tailnet.ts.net

Part 4: 커스텀 도메인 설정 (선택)

myapp.example.com를 MagicDNS 호스트명 대신 사용하려면 Split-Horizon DNS를 사용합니다.

Tailscale DNS 오버라이드 설정

ACL 파일에 DNS 설정 추가:

{
  "dns": {
    "extraRecords": [
      {
        "name": "myapp.example.com",
        "type": "A",
        "value": "100.x.x.x"
      }
    ]
  }
}

Cloudflare DNS 설정

옵션 A: 공개 DNS 레코드 삭제 (추천)

Cloudflare에서 myapp A/CNAME 레코드를 삭제합니다. myapp.example.com가 공개적으로 해석되지 않고 Tailscale 사용자만 접근할 수 있게 됩니다.

옵션 B: “VPN 필요” 페이지로 안내

DNS 레코드를 유지하되 정적 “VPN 필요” 페이지를 가리킵니다.

테스트

# Tailscale 연결 상태에서
nslookup myapp.example.com
# 100.x.x.x (Tailscale IP)를 반환해야 함

curl http://myapp.example.com
# 앱이 로드되어야 함

Part 5: 접근 제어 설정

Tailscale ACL 설정

{
  "acls": [
    {
      "action": "accept",
      "src": ["autogroup:members"],
      "dst": ["tag:k8s:*"]
    }
  ],
  "tagOwners": {
    "tag:k8s": ["autogroup:admin"]
  }
}

팀원 초대

  1. Tailscale Users에서 사용자 초대
  2. 사용자가 Tailscale 설치: https://tailscale.com/download

트러블슈팅

도메인이 해석되지 않음

# DNS 캐시 초기화
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

# 직접 Tailscale IP 테스트
curl http://100.x.x.x

빠른 참조

접근 URL

MagicDNS (추천):

  • 메인 앱: https://myapp.your-tailnet.ts.net
  • FastAPI: https://myapp.your-tailnet.ts.net/fastapi
  • RQ Dashboard: https://myapp.your-tailnet.ts.net/rqdash

커스텀 도메인 (설정 시):

  • 메인 앱: http://myapp.example.com
  • FastAPI: http://myapp.example.com/fastapi
  • RQ Dashboard: http://myapp.example.com/rqdash

참고 문서