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 클라이언트 생성
- Tailscale OAuth Clients로 이동
- “Generate OAuth client” 클릭
- 설정:
- 설명:
k8s-operator-my-app - 스코프:
devices:write선택 (필수) - 태그:
tag:k8s
- 설명:
- 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 디바이스 확인
- Tailscale Machines로 이동
- “myapp” 디바이스 찾기
- 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"]
}
}
팀원 초대
- Tailscale Users에서 사용자 초대
- 사용자가 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