Tailscale 실전 구성: 설치부터 ACL, Docker, Headscale 자체 호스팅까지

Tailscale 설치·CLI 명령어·Subnet Router·Exit Node·ACL·Docker 연동·Headscale 자체 호스팅까지 실무에서 바로 쓰는 구성 절차를 정리한다.

2026-08-12 · 최초 발행 2026-03-13

Tailscale을 실제로 운영에 넣으려면 개념보다 손에 익혀야 할 절차가 많다. 설치부터 초기 설정, CLI 명령어, Subnet Router·Exit Node 구성, ACL 정책, Docker/Kubernetes 연동, 자체 호스팅(Headscale)까지 순서대로 짚는다.

설치

Linux

원라인 설치 스크립트로 시작한다.

# 원라인 설치 스크립트
curl -fsSL https://tailscale.com/install.sh | sh

# 설치 후 Tailscale 시작
sudo tailscale up

# 서비스 자동 시작 등록
sudo systemctl enable --now tailscaled

배포판별 패키지 매니저로 수동 설치할 수도 있다.

# Ubuntu/Debian
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/jammy.tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt-get update
sudo apt-get install tailscale

# RHEL/CentOS/Fedora
sudo dnf config-manager --add-repo https://pkgs.tailscale.com/stable/fedora/tailscale.repo
sudo dnf install tailscale
sudo systemctl enable --now tailscaled

macOS

Tailscale 패키지 서버에서 Standalone 버전을 받는 것이 권장 방식이다. Mac App Store에서 "Tailscale"을 검색해 설치할 수도 있고, CLI만 필요하면 GitHub 릴리스에서 오픈소스 바이너리를 받으면 된다. 최소 요구사항은 macOS 12.0(Monterey) 이상이다.

Windows

Tailscale 다운로드 페이지에서 MSI 설치 파일을 받는다. 설치가 끝나면 시스템 트레이의 Tailscale 아이콘을 눌러 Log in을 선택하고, Google·Microsoft·GitHub 같은 SSO 제공자로 인증한다.

초기 설정과 Tailnet 구성

계정 생성부터 Tailnet이 완성되기까지 흐름은 다음과 같다.

계정 생성login.tailscale.com 디바이스tailscale upSSO 인증IdP 로그인 번째 디바이스tailscale upTailnet 완성자동 메시 구성ACL 정책 설정접근 제어

login.tailscale.com에서 Google·Microsoft·GitHub·Okta 같은 SSO 제공자로 계정을 만든다. 첫 번째 디바이스에서 tailscale up을 실행하면 브라우저로 SSO 인증 화면이 뜨고, 두 번째 디바이스에서 같은 계정으로 다시 tailscale up을 실행하면 두 디바이스가 자동으로 Tailnet(가상 사설 네트워크)을 형성하며 100.x.y.z 대역의 IP가 할당된다.

MagicDNS 켜기

Admin Console의 DNS 설정에서 MagicDNS를 활성화하면 디바이스명으로 접근할 수 있다.

# IP 대신 디바이스명으로 접속
ssh user@my-server              # MagicDNS 활성화 시
ssh user@my-server.tailnet-name.ts.net  # FQDN 형식
ping my-nas                     # 디바이스명으로 ping

CLI로 다루는 일상 작업

연결 관리

# Tailscale 연결 (기본)
sudo tailscale up

# 인증 키로 자동 연결 (서버/CI 환경)
sudo tailscale up --authkey=tskey-auth-xxxxx

# 호스트명 지정
sudo tailscale up --hostname=prod-web-01

# 연결 해제 (노드 유지)
sudo tailscale down

# 완전 로그아웃 (노드 제거)
sudo tailscale logout

상태 확인

# 연결 상태 확인
tailscale status

# 출력 예시:
# 100.64.0.1   my-laptop        user@    linux   idle
# 100.64.0.2   prod-server      user@    linux   active; direct 1.2.3.4:41641
# 100.64.0.3   home-nas         user@    linux   active; relay "tok"

# JSON 형식 상세 정보
tailscale status --json

# 현재 디바이스의 Tailscale IP 확인
tailscale ip
tailscale ip -4   # IPv4만
tailscale ip -6   # IPv6만

relay "tok"처럼 릴레이 경유 여부가 상태 출력에 그대로 드러나기 때문에, 연결 품질을 확인할 때 가장 먼저 보는 명령이다.

네트워크 진단

# 네트워크 상태 진단
tailscale netcheck

# 출력 예시:
# Report:
#   * UDP: true
#   * IPv4: yes, 1.2.3.4:12345
#   * IPv6: yes, [2001:db8::1]:12345
#   * MappingVariesByDestIP: false
#   * HairPinning: true
#   * PortMapping: UPnP, PMP, PCP
#   * Nearest DERP: Tokyo
#   * DERP latency:
#       - tok: 3.2ms  (Tokyo)
#       - sin: 65.4ms (Singapore)
#       - sfo: 120ms  (San Francisco)

# 특정 피어와의 연결 상태 확인
tailscale ping my-server
# pong from my-server (100.64.0.2) via 1.2.3.4:41641 in 5ms

파일 전송 (Taildrop)

# 파일 전송
tailscale file cp ./report.pdf my-server:

# 파일 수신 (수신 대기)
tailscale file get ./downloads/

Subnet Router 구성

Tailscale 클라이언트를 설치할 수 없는 레거시 장비나 사내 네트워크에 접근해야 할 때 Subnet Router를 쓴다.

설정 절차

# (1) IP 포워딩 활성화 (Linux)
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

# (2) Subnet Router로 라우트 광고
sudo tailscale up --advertise-routes=192.168.1.0/24,10.0.0.0/8

# (3) Admin Console에서 해당 노드의 라우트 승인
# 또는 ACL에 autoApprovers 설정으로 자동 승인

# (4) 클라이언트에서 서브넷 라우트 수락
sudo tailscale up --accept-routes

autoApprovers ACL 설정

Admin Console에서 매번 수동 승인하는 대신, ACL에 autoApprovers를 넣으면 지정한 태그·그룹의 라우트를 자동 승인한다.

{
  "autoApprovers": {
    "routes": {
      "192.168.1.0/24": ["tag:server"],
      "10.0.0.0/8": ["group:network-admins"]
    }
  }
}

Exit Node 구성

모든 인터넷 트래픽을 특정 노드로 몰아서 공용 Wi-Fi 환경을 보호하거나 특정 지역 IP로 접속하고 싶을 때 쓴다.

Exit Node 서버 설정

# Exit Node로 광고
sudo tailscale up --advertise-exit-node

# Admin Console에서 Exit Node 승인 필요
# 또는 ACL autoApprovers 설정:
# "exitNode": ["tag:exit-node"]

Exit Node 클라이언트 사용

# 특정 Exit Node 사용
sudo tailscale up --exit-node=prod-vpn-server

# Exit Node 해제
sudo tailscale up --exit-node=

ACL 정책 설정

ACL은 JSON(또는 HuJSON) 형식으로 Admin Console에서 관리하며, GitOps 방식으로도 다룰 수 있다.

기본 ACL 구조

{
  "groups": {
    "group:devs": ["user1@company.com", "user2@company.com"],
    "group:ops": ["admin@company.com"]
  },
  "tagOwners": {
    "tag:server": ["group:ops"],
    "tag:db": ["group:ops"]
  },
  "acls": [
    {
      "action": "accept",
      "src": ["group:devs"],
      "dst": ["tag:server:80,443"]
    },
    {
      "action": "accept",
      "src": ["group:ops"],
      "dst": ["*:*"]
    },
    {
      "action": "accept",
      "src": ["tag:server"],
      "dst": ["tag:db:5432"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["group:ops"],
      "dst": ["tag:server"],
      "users": ["root", "ubuntu"]
    }
  ]
}

자주 쓰는 ACL 패턴

패턴 설명 예시
사용자 → 서버 특정 그룹이 서버의 특정 포트 접근 "src": ["group:devs"], "dst": ["tag:web:80,443"]
서버 → DB 서버 간 내부 통신 허용 "src": ["tag:app"], "dst": ["tag:db:5432"]
전체 허용 운영팀 전체 접근 "src": ["group:ops"], "dst": ["*:*"]
SSH 제어 SSH 접근 사용자 및 대상 제한 "ssh" 섹션에서 별도 정의
자동 승인 라우트/Exit Node 자동 승인 "autoApprovers" 섹션

Docker 환경 구성

전용 컨테이너로 실행

# docker-compose.yml
version: "3.8"
services:
  tailscale:
    image: tailscale/tailscale:latest
    container_name: tailscale
    hostname: docker-node
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxx
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=false
    volumes:
      - tailscale-state:/var/lib/tailscale
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    restart: unless-stopped

volumes:
  tailscale-state:

사이드카 패턴 (다른 컨테이너에 네트워크 공유)

network_mode: "service:tailscale"로 지정하면 다른 컨테이너가 Tailscale 컨테이너의 네트워크 네임스페이스를 그대로 쓴다.

services:
  tailscale:
    image: tailscale/tailscale:latest
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxx
      - TS_SERVE_CONFIG=/config/serve.json
    volumes:
      - tailscale-state:/var/lib/tailscale
    cap_add:
      - NET_ADMIN
    network_mode: host

  my-app:
    image: my-app:latest
    network_mode: "service:tailscale"
    depends_on:
      - tailscale

인증 키 관리

서버, CI/CD 러너, 컨테이너처럼 브라우저로 로그인할 수 없는 환경에서는 인증 키(Auth Key)를 쓴다.

인증 키 유형

유형 설명 용도
일회용 키 한 번만 사용 가능 단일 서버 등록
재사용 키 여러 디바이스 등록 가능 CI/CD 러너, 컨테이너
에피메럴 키 디바이스 종료 시 자동 제거 컨테이너, 임시 환경
태그 키 ACL 태그 자동 적용 자동화된 인프라 프로비저닝

인증 키 생성과 사용

Admin Console의 Settings → Keys → Generate auth key에서 만들 수도 있고, API로 직접 만들 수도 있다.

# Admin Console → Settings → Keys → Generate auth key
# 또는 API로 생성
curl -X POST "https://api.tailscale.com/api/v2/tailnet/-/keys" \
  -u "tskey-api-xxxxx:" \
  -H "Content-Type: application/json" \
  -d '{
    "capabilities": {
      "devices": {
        "create": {
          "reusable": true,
          "ephemeral": true,
          "tags": ["tag:ci-runner"]
        }
      }
    },
    "expirySeconds": 86400
  }'

# 인증 키로 디바이스 등록
sudo tailscale up --authkey=tskey-auth-xxxxx

Tailscale SSH 설정

별도의 SSH 키를 배포하지 않고도 SSO 인증만으로 SSH 접속을 관리할 수 있다.

# SSH 서버 측 설정
sudo tailscale up --ssh

# SSH 접속 (일반 SSH와 동일)
ssh user@my-server     # Tailscale SSH 경유

ACL SSH 정책

{
  "ssh": [
    {
      "action": "check",
      "src": ["group:devs"],
      "dst": ["tag:server"],
      "users": ["ubuntu"],
      "checkPeriod": "12h"
    }
  ]
}

accept는 즉시 허용, check는 주기적 재인증을 요구해 보안을 강화하는 동작이고, checkPeriod로 재인증 주기를 설정한다.

자체 호스팅: Headscale

컨트롤 서버까지 완전히 자체 호스팅하려면 오픈소스 프로젝트 Headscale을 쓴다.

Docker Compose로 배포

# docker-compose.yml
version: "3.8"
services:
  headscale:
    image: headscale/headscale:latest
    container_name: headscale
    volumes:
      - ./config:/etc/headscale
      - headscale-data:/var/lib/headscale
    ports:
      - "8080:8080" # gRPC
      - "443:443" # HTTPS
      - "3478:3478/udp" # STUN
    command: serve
    restart: unless-stopped

volumes:
  headscale-data:

초기 설정

# 사용자(네임스페이스) 생성
docker exec headscale headscale users create my-user

# 인증 키 생성
docker exec headscale headscale preauthkeys create --user my-user --reusable --expiration 24h

# 클라이언트에서 Headscale 서버로 연결
tailscale up --login-server=https://headscale.example.com --authkey=xxxxx

내장 DERP 서버 활성화

Headscale은 내장 DERP 서버를 포함하고 있어, 릴레이 트래픽까지 자체 호스팅할 수 있다.

# config.yaml (Headscale 설정)
derp:
  server:
    enabled: true
    region_id: 999
    region_code: "self"
    region_name: "Self-hosted DERP"
    stun_listen_addr: "0.0.0.0:3478"

트러블슈팅 체크리스트

연결 문제 진단

# (1) Tailscale 서비스 상태 확인
sudo systemctl status tailscaled

# (2) 네트워크 진단
tailscale netcheck

# (3) 특정 피어 연결 테스트
tailscale ping target-device

# (4) 방화벽 확인 사항
# - UDP 41641 (WireGuard direct)
# - UDP 3478 (STUN)
# - TCP 443 (DERP fallback)

# (5) 로그 확인
sudo journalctl -u tailscaled -f

자주 발생하는 문제

증상 원인 해결 방법
relay "tok" 표시 NAT 통과 실패, DERP 릴레이 경유 방화벽에서 UDP 41641 허용
idle 상태 지속 키 만료 또는 인증 실패 tailscale up 재인증
Subnet 접근 불가 라우트 미승인 또는 accept-routes 미설정 Admin Console에서 라우트 승인 + --accept-routes
DNS 해석 실패 MagicDNS 미활성화 Admin Console → DNS에서 MagicDNS 활성화
느린 전송 속도 DERP 릴레이 경유 중 tailscale netcheck으로 직접 연결 여부 확인
TailscaleVPNACLHeadscaleDocker