본문 바로가기
  • AI 시대에 적응하는 현대인을 위한 지식 공간
  • AI를 위한 데이터를 과학으로 역어본다
AI 코딩

Tailscale 완벽 가이드 (2편) - 설치부터 Zero Trust 네트워크 구축

by 피크나인 2026. 2. 7.

설치부터 Zero Trust 네트워크 구축, Cloudflare와의 복합 활용까지

1편에서는 Tailscale의 개념과 아키텍처, 그리고 다양한 활용 사례를 살펴보았습니다. 이번 2편에서는 실전으로 넘어갑니다.

 

Tailscale을 실제로 설치하고 설정하는 방법부터, Zero Trust 네트워크와 도메인 서비스 구축, 그리고 Cloudflare Tunnel과의 차이점 분석 및 두 서비스를 함께 활용하는 하이브리드 전략까지 다룹니다.

특히 Mac Mini 홈서버와 Synology NAS 환경에서의 Docker 기반 프로덕션 설정에 초점을 맞추어, 단순한 설치 가이드를 넘어 실무에서 바로 사용할 수 있는 구성을 제공합니다. 이 글을 끝까지 따라하시면, Cloudflare와 Tailscale을 조합한 견고한 홈 인프라를 완성할 수 있습니다. 

(i)참고 : Tailscale 완벽 가이드 (1편)에서 이미 설치가이드를 제공해 드렸지만, 2편에서는 좀더 상세한설명을 곁들여서 설치 및 설정을 안내합니다. 이점 참고 바랍니다.

Tailscale과 Cloudflare를 함께 활용하면 보안과 성능 두 마리 토끼를 잡을 수 있습니다
Tailscale과 Cloudflare를 함께 활용하면 보안과 성능 두 마리 토끼를 잡을 수 있습니다



1. Tailscale 설치와 설정  |  간단 버전

Tailscale의 가장 큰 장점 중 하나는 설치가 놀라울 정도로 간단하다는 점입니다. 전통적인 VPN 솔루션에서는 서버 설정, 인증서 발급, 클라이언트 설정 파일 배포 등 복잡한 과정을 거쳐야 했지만, Tailscale은 대부분의 플랫폼에서 한두 줄의 명령어만으로 설치와 연결이 완료됩니다. 이 섹션에서는 주요 플랫폼별로 가장 빠르게 Tailscale을 시작하는 방법을 안내합니다.

macOS 설치

macOS에서는 두 가지 설치 방법이 있습니다.

  • 첫 번째는 Mac App Store에서 공식 앱을 설치하는 방법으로, GUI 기반의 메뉴바 앱이 함께 제공되어 직관적으로 사용할 수 있습니다.
  • 두 번째는 Homebrew를 사용하는 CLI 설치 방법으로, 서버 환경이나 자동화가 필요한 경우에 적합합니다. Mac Mini와 같은 홈서버 용도로는 CLI 설치를 권장하는데, 사용자가 로그아웃 상태에서도 백그라운드에서 안정적으로 동작하기 때문입니다.
# Homebrew를 이용한 설치
brew install tailscale

# Tailscale 데몬 시작
sudo tailscaled &

# Tailscale 로그인 및 네트워크 연결
tailscale up

 

위 명령어를 실행하면 브라우저 창이 열리면서 Tailscale 로그인 페이지가 나타납니다. Google, Microsoft, GitHub 등의 계정으로 로그인하면 해당 Mac이 자동으로 Tailnet(테일넷)에 등록됩니다. 이후 tailscale status 명령어로 연결 상태를 확인할 수 있으며, Tailnet에 등록된 다른 디바이스들의 IP 주소도 함께 표시됩니다.

tailscale & 백그라운드 실행이 실패하는 경우의 조치

+ 32914 suspended (tty input)  sudo tailscaled

 

명령어 뒤에 &를 붙여 백그라운드로 실행하려 했으나, sudo가 비밀번호 입력을 요구하면서 터미널 입력(tty input)을 기다리게 되어 프로세스가 일시 중단(suspended)된 상태로 떨어지는 경우입니다.

 

이를 해결하고 Tailscale CLI(데몬)를 정상적으로 실행하는 방법은 다음과 같습니다:

일단 이미 실행한 명령어는 무시하시고 다음 순서로 진행하세요.

 

CLI 설치 및 실행 방법

macOS에서 데몬(tailscaled)을 수동으로 띄우기보다, 시스템 서비스(launchd)로 등록하는 것이 훨씬 안정적입니다.

데몬을 백그라운드 서비스로 등록하면 재부팅 시에도 자동 실행됩니다.

sudo tailscaled install-system-daemon

# 이 명령어는 /Library/LaunchDaemons/에 설정 파일을 생성하고 서비스를 시작합니다.
 

 

Homebrew 사용 시
Homebrew로 설치했다면 다음 명령어로 간단히 관리할 수 있습니다.

sudo brew services start tailscale

Linux (Ubuntu/Debian) 설치

Linux 서버에서의 설치는 Tailscale이 제공하는 공식 스크립트를 사용하면 가장 간편합니다. 이 스크립트는 현재 운영체제와 아키텍처를 자동으로 감지하여 적절한 패키지를 설치해 줍니다. VPS(Virtual Private Server)나 클라우드 인스턴스에서 특히 유용한 방법이며, ARM64 아키텍처도 자동으로 지원합니다.

# 공식 설치 스크립트 (권장)
curl -fsSL https://tailscale.com/install.sh | sh

# 서비스 시작 및 로그인
sudo tailscale up

# 연결 상태 확인
tailscale status

 

설치가 완료되면 tailscaled 서비스가 systemd에 자동으로 등록됩니다. 따라서 서버가 재부팅되더라도 Tailscale이 자동으로 다시 연결되므로, 별도의 자동 시작 설정이 필요하지 않습니다. 상태 확인 시 direct 또는 relay 표시를 통해 현재 P2P 직접 연결이 되어 있는지, 아니면 DERP 중계 서버를 경유하고 있는지 확인할 수 있습니다.

Windows 설치

Windows에서는 Tailscale 공식 웹사이트에서 설치 파일을 다운로드하여 실행하면 됩니다. 설치 후 시스템 트레이에 Tailscale 아이콘이 나타나며, 클릭하면 로그인 및 각종 설정을 할 수 있습니다. Windows에서의 Tailscale은 GUI 중심으로 동작하지만, PowerShell이나 명령 프롬프트에서도 tailscale CLI를 사용할 수 있습니다.

# PowerShell에서 연결 상태 확인
tailscale status

# 특정 노드에 ping 테스트
tailscale ping <디바이스명>

모바일 (iOS/Android) 설치

iOS와 Android 모두 각 앱스토어에서 "Tailscale"을 검색하여 공식 앱을 설치할 수 있습니다. 앱을 실행하면 웹 브라우저를 통한 로그인이 진행되고, 인증이 완료되면 해당 모바일 기기가 Tailnet에 자동으로 등록됩니다. 모바일에서 Tailscale을 활성화하면, 카페 Wi-Fi나 모바일 데이터 네트워크에서도 집의 서버에 안전하게 접근할 수 있습니다. 특히 Exit Node 기능을 함께 사용하면 모든 인터넷 트래픽을 집 네트워크를 통해 라우팅할 수 있어, 공공 Wi-Fi의 보안 위험을 효과적으로 줄일 수 있습니다.

Synology NAS 설치

Synology NAS에서의 Tailscale 설치는 두 가지 방법이 있습니다.

  • 첫 번째는 Synology 패키지 센터를 통한 공식 패키지 설치이고,
  • 두 번째는 Docker를 활용한 설치입니다.

패키지 센터 방식은 가장 간단하지만, Subnet Router나 Exit Node 같은 고급 기능 설정에 제약이 있을 수 있습니다. Docker 방식은 더 유연한 설정이 가능하며, 이에 대한 상세 설정은 다음 섹션의 프로덕션 버전에서 다룹니다.

 

패키지 센터를 통한 설치 절차는 다음과 같습니다. DSM에 로그인한 후 패키지 센터를 열고, "Tailscale" 을 검색합니다. 공식 Tailscale 패키지가 검색되면 "설치"를 클릭하고, 설치 완료 후 Tailscale 앱을 열어 브라우저 인증을 진행합니다. 인증이 완료되면 NAS가 Tailnet에 등록되며, MagicDNS를 통해 nas-name.tailnet-name.ts.net 형태의 도메인으로 접근할 수 있게 됩니다.


2. Tailscale 설치와 설정  |  프로덕션 버전

간단 버전으로 빠르게 시작할 수 있지만, 홈서버나 실무 환경에서는 보다 세밀한 설정이 필요합니다. 프로덕션 버전에서는 Docker Compose를 활용한 컨테이너화된 배포, Auth Key를 이용한 자동 인증, Subnet Router와 Exit Node 설정, 그리고 상태 영속성(State Persistence) 관리까지 다룹니다. 이 설정을 완료하면 서버 재부팅이나 컨테이너 재시작 시에도 자동으로 Tailnet에 재연결되는 안정적인 환경을 구축할 수 있습니다.

Auth Key 생성

프로덕션 환경에서는 브라우저를 통한 대화식 로그인 대신, Auth Key(인증 키)를 사용하여 자동 인증을 설정합니다. Tailscale Admin Console에서 Settings > Keys 메뉴로 이동하여 "Generate auth key" 버튼을 클릭합니다. 키 생성 시 다음 옵션들을 설정할 수 있으며, 프로덕션 환경에 맞는 설정을 선택해야 합니다.

옵션 설명 프로덕션 권장값
Reusable 하나의 키로 여러 디바이스를 등록할 수 있는지 여부입니다. Docker 환경에서 컨테이너를 여러 번 재생성해야 하는 경우 활성화합니다. 활성화
Ephemeral 등록된 노드가 오프라인이 되면 자동으로 Tailnet에서 제거되는 옵션입니다. 일시적인 테스트 노드에만 사용합니다. 비활성화
Pre-approved 노드가 등록될 때 관리자의 수동 승인 없이 자동으로 승인되는 옵션입니다. 자동화 환경에서 필수적입니다. 활성화
Tags 노드에 태그를 자동으로 부여하여 ACL 정책에서 활용할 수 있습니다. 역할별로 태그를 구분하면 관리가 편리합니다. tag:server 등 설정
Expiration 키의 유효 기간을 설정합니다. 최대 90일까지 가능하며, 태그가 부여된 노드는 키 만료 후에도 연결이 유지됩니다. 90일 (최대)
[!] 중요: Auth Key는 생성 직후 한 번만 표시됩니다. 반드시 안전한 곳에 저장해 두시기 바랍니다. 키를 분실한 경우 새로운 키를 생성해야 합니다.

Docker Compose - 기본 구성

Docker를 이용하면 호스트 시스템에 직접 설치하지 않고도 Tailscale을 운영할 수 있습니다. 특히 Synology NAS처럼 패키지 관리가 제한적인 환경에서 유용하며, 컨테이너 격리를 통해 시스템 안정성도 확보할 수 있습니다. 아래는 Tailscale을 Docker로 운영하기 위한 기본 Docker Compose 설정입니다.

# docker-compose.yml - Tailscale 기본 구성
services:
  tailscale:
    container_name: tailscale
    image: tailscale/tailscale:latest
    restart: unless-stopped
    network_mode: host
    privileged: true
    environment:
      - TS_HOSTNAME=homelab-server
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=false
      - TS_AUTH_ONCE=true
    volumes:
      - ./tailscale-data:/var/lib
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - NET_RAW
# .env 파일
TS_AUTHKEY=tskey-auth-XXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXX

 

이 구성에서 주요 설정 항목을 하나씩 살펴보겠습니다.

  • network_mode: host는 컨테이너가 호스트의 네트워크 스택을 직접 사용하도록 설정하는 것으로, Subnet Router나 Exit Node 기능을 사용하려면 반드시 필요합니다.
  • TS_STATE_DIR은 Tailscale의 인증 상태를 영구적으로 저장할 디렉토리를 지정하며, 이를 Docker 볼륨으로 마운트하면 컨테이너를 재시작해도 재인증 없이 자동으로 연결됩니다.
  • TS_USERSPACE=false는 커널 모드 네트워킹을 사용하겠다는 설정으로, 유저스페이스 모드보다 성능이 우수합니다.

Docker Compose - Subnet Router + Exit Node 구성

실무 환경에서 가장 많이 사용되는 구성은 Subnet Router와 Exit Node를 함께 설정하는 것입니다.

Subnet Router를 활성화하면 Tailscale 클라이언트가 설치되지 않은 로컬 네트워크의 다른 기기(프린터, IP 카메라, IoT 장비 등)에도 Tailnet을 통해 접근할 수 있습니다. Exit Node는 모든 인터넷 트래픽을 이 서버를 통해 라우팅하도록 설정하는 것으로, 외부에서 집 네트워크의 IP로 인터넷을 사용할 수 있게 합니다.

# docker-compose.yml - Subnet Router + Exit Node 프로덕션 구성
services:
  tailscale:
    container_name: tailscale
    image: tailscale/tailscale:latest
    restart: unless-stopped
    network_mode: host
    privileged: true
    environment:
      - TS_HOSTNAME=homelab-server
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=false
      - TS_AUTH_ONCE=true
      - TS_ACCEPT_DNS=true
      - TS_ROUTES=192.168.1.0/24
      - TS_EXTRA_ARGS=--advertise-exit-node --accept-routes
    volumes:
      - ./tailscale-data:/var/lib
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - NET_RAW
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv6.conf.all.forwarding=1

 

위 구성에서 TS_ROUTES=192.168.1.0/24는 로컬 네트워크 대역을 Tailnet에 광고(advertise)하겠다는 설정입니다. 이 값은 실제 로컬 네트워크의 서브넷 대역에 맞게 수정해야 합니다. 예를 들어, 공유기의 IP 대역이 10.0.0.0/24라면 해당 값으로 변경하면 됩니다. --advertise-exit-node은 이 서버를 Exit Node로 사용할 수 있도록 광고하는 옵션입니다. sysctls 섹션의 IP 포워딩 설정은 Subnet Router가 트래픽을 올바르게 전달하기 위해 반드시 필요한 커널 파라미터입니다.

[!] 참고: Docker Compose에서 sysctls를 설정해도 호스트의 커널 파라미터가 변경되지 않는 환경이 있습니다. 이 경우 호스트에서 직접 sysctl 명령어로 설정해야 합니다.
# 호스트에서 직접 IP 포워딩 활성화 (영구 설정)
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

Admin Console에서 라우트 승인

Docker Compose로 Tailscale 컨테이너를 실행하면, Subnet Route와 Exit Node 광고가 시작됩니다. 하지만 보안을 위해 이 광고들은 관리자가 Admin Console에서 수동으로 승인해야 활성화됩니다.

Tailscale Admin Console(https://login.tailscale.com/admin/machines)에 접속하여 해당 디바이스 옆의 세 점 메뉴를 클릭하고 "Edit route settings..."를 선택합니다. 여기에서 Subnet Routes(예: 192.168.1.0/24)를 활성화하고, 필요한 경우 "Use as exit node"도 활성화합니다.

 

ACL 정책 파일에서 autoApprovers를 설정하면 이 수동 승인 과정을 자동화할 수 있습니다. 이 방법은 태그를 사용하여 특정 태그가 부여된 노드가 광고하는 라우트를 자동으로 승인하도록 설정합니다. 프로덕션 환경에서 여러 대의 서버를 운영하는 경우에 특히 유용합니다.

{
  "autoApprovers": {
    "routes": {
      "192.168.1.0/24": ["tag:server"],
      "10.0.0.0/24": ["tag:server"]
    },
    "exitNode": ["tag:server"]
  }
}

Sidecar 패턴 - 특정 Docker 컨테이너를 Tailnet에 노출

모든 트래픽을 호스트 네트워크로 라우팅하는 대신, 특정 Docker 컨테이너만 Tailnet에 노출하고 싶은 경우가 있습니다. 예를 들어, n8n 워크플로우 자동화 서비스만 외부에서 접근 가능하게 하고 싶다면, Tailscale을 Sidecar 컨테이너로 구성하여 해당 서비스에만 Tailnet 접근을 제공할 수 있습니다. 이 방식은 network_mode: host를 사용하지 않기 때문에 보안적으로도 더 우수합니다.

Docker내 사이드카 설정
Docker내 사이드카 설정

# docker-compose.yml - Sidecar 패턴 예시 (n8n 서비스)
services:
  tailscale-n8n:
    container_name: ts-n8n
    image: tailscale/tailscale:latest
    restart: unless-stopped
    environment:
      - TS_HOSTNAME=n8n-service
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/serve.json
      - TS_USERSPACE=true
    volumes:
      - ./ts-n8n-data:/var/lib
      - ./serve-config:/config

  n8n:
    container_name: n8n
    image: n8nio/n8n:latest
    restart: unless-stopped
    network_mode: "service:tailscale-n8n"
    volumes:
      - ./n8n-data:/home/node/.n8n
    environment:
      - N8N_HOST=0.0.0.0
      - N8N_PORT=5678
// serve-config/serve.json
{
  "TCP": {
    "443": {
      "HTTPS": true
    }
  },
  "Web": {
    "n8n-service.tailnet-name.ts.net:443": {
      "Handlers": {
        "/": {
          "Proxy": "http://127.0.0.1:5678"
        }
      }
    }
  }
}

 

이 구성에서 핵심은 n8n 컨테이너의 network_mode: "service:tailscale-n8n" 설정입니다. 이렇게 하면 n8n 컨테이너가 자체 네트워크 스택 대신 Tailscale 컨테이너의 네트워크를 사용하게 됩니다. 결과적으로 n8n은 Tailnet을 통해서만 접근 가능하고, 공용 인터넷에는 전혀 노출되지 않습니다. TS_SERVE_CONFIG를 통해 Tailscale Serve 기능을 활용하면, Tailnet 내에서 HTTPS로 안전하게 서비스에 접근할 수 있습니다.


3. Tailscale을 이용한 Zero Trust 네트워크 구축

Zero Trust(제로 트러스트)는 "아무것도 신뢰하지 않고, 항상 검증한다"는 보안 철학입니다. 전통적인 네트워크 보안이 방화벽이라는 성벽 안쪽을 신뢰하는 방식이었다면, Zero Trust는 네트워크 내부에 있든 외부에 있든 모든 접근을 동일하게 검증합니다. Tailscale은 이러한 Zero Trust 원칙을 비교적 간단하게 구현할 수 있는 도구를 제공하며, 특히 ACL(Access Control List) 정책과 태그 시스템을 통해 세밀한 접근 제어가 가능합니다.

ACL 정책 파일 기본 이해

Tailscale의 접근 제어는 정책 파일(Policy File)을 통해 관리됩니다. 이 파일은 huJSON(Human JSON) 형식으로 작성되며, 일반 JSON에 주석을 추가할 수 있어 가독성이 좋습니다. 기본적으로 Tailscale은 "허용 목록이 없으면 거부(deny-by-default)" 원칙을 따르지만, 최초 생성 시에는 모든 디바이스 간 통신을 허용하는 기본 정책이 적용됩니다. Zero Trust를 구현하려면 이 기본 정책을 수정하여, 필요한 통신만 명시적으로 허용해야 합니다.

// Tailscale ACL 정책 파일 - Zero Trust 홈랩 예시
{
  // 그룹 정의: 역할별로 사용자를 분류합니다
  "groups": {
    "group:admin": ["user@gmail.com"],
    "group:family": ["family-member@gmail.com"]
  },

  // 태그 소유자: 누가 어떤 태그를 디바이스에 부여할 수 있는지 정의합니다
  "tagOwners": {
    "tag:server":  ["group:admin"],
    "tag:nas":     ["group:admin"],
    "tag:iot":     ["group:admin"],
    "tag:monitor": ["group:admin"]
  },

  // 접근 제어 규칙
  "acls": [
    {
      // 관리자는 모든 서버에 대한 모든 포트 접근 가능
      "action": "accept",
      "src":    ["group:admin"],
      "dst":    ["tag:server:*", "tag:nas:*"]
    },
    {
      // 가족 구성원은 NAS의 미디어 서비스 포트만 접근 가능
      "action": "accept",
      "src":    ["group:family"],
      "dst":    ["tag:nas:8096", "tag:nas:32400"]
    },
    {
      // 서버 간 통신 허용 (모니터링, 백업 등)
      "action": "accept",
      "src":    ["tag:server"],
      "dst":    ["tag:server:*", "tag:nas:*"]
    },
    {
      // IoT 디바이스는 모니터링 서버에만 접근 가능
      "action": "accept",
      "src":    ["tag:iot"],
      "dst":    ["tag:monitor:8086"]
    }
  ],

  // Tailscale SSH 규칙
  "ssh": [
    {
      "action": "accept",
      "src":    ["group:admin"],
      "dst":    ["tag:server", "tag:nas"],
      "users":  ["autogroup:nonroot", "root"]
    }
  ]
}

위 정책을 단계별로 살펴보겠습니다. 먼저 groups 섹션에서 사용자들을 역할별로 분류합니다. 여기서는 관리자(admin)와 가족(family) 두 그룹을 정의했습니다. tagOwners에서는 admin 그룹만이 서버, NAS, IoT 장비에 태그를 부여할 수 있도록 설정합니다. 가장 핵심인 acls 섹션에서는 네 가지 규칙을 통해 접근을 제어합니다. 관리자는 모든 서버와 NAS에 접근할 수 있지만, 가족 구성원은 NAS의 미디어 서비스(Jellyfin 8096, Plex 32400) 포트에만 접근할 수 있습니다. 서버 간에는 자유롭게 통신할 수 있도록 허용하고, IoT 장비는 모니터링 서버의 특정 포트에만 접근이 가능합니다.

Grants - 차세대 접근 제어

Tailscale은 기존 ACL에 더해, Grants라는 차세대 접근 제어 문법을 도입했습니다. Grants는 ACL의 모든 기능을 포함하면서도 애플리케이션 레이어의 접근 제어까지 확장할 수 있는 통합 문법입니다. ACL에서는 반드시 "action": "accept"를 명시해야 했지만, Grants에서는 기본적으로 접근 허용만 가능하므로(deny-by-default 원칙) action 필드가 필요 없습니다. 또한 목적지(dst)와 포트(port)를 분리하여 표현하므로 가독성이 더 좋습니다.

{
  "grants": [
    {
      // 관리자의 서버 SSH 접근
      "src": ["group:admin"],
      "dst": ["tag:server"],
      "ip":  ["tcp:22"]
    },
    {
      // 가족의 미디어 서비스 접근
      "src": ["group:family"],
      "dst": ["tag:nas"],
      "ip":  ["tcp:8096", "tcp:32400"]
    },
    {
      // 관리자의 Tailscale SSH 접근 + 파일 전송 허용
      "src": ["group:admin"],
      "dst": ["tag:server"],
      "app": {
        "tailscale.com/cap/ssh": [{
          "users":      ["root", "ubuntu"],
          "checkPeriod": "12h"
        }]
      }
    }
  ]
}

Grants의 진정한 강점은 app 필드를 통한 애플리케이션 레이어 접근 제어입니다. 위 예시에서 세 번째 규칙은 SSH 접근에 대해 12시간마다 재인증을 요구하는 설정입니다. 이런 세밀한 제어는 기존 ACL 문법으로는 불가능했습니다. Tailscale은 기존 ACL을 계속 지원하지만, 새로운 기능 추가는 Grants에 집중할 예정이므로 새로운 설정을 작성할 때는 Grants 문법 사용을 권장합니다.

Tailscale SSH - 키 관리 없는 SSH

전통적인 SSH는 공개키/개인키 쌍을 생성하고, 공개키를 각 서버에 배포하며, 키의 순환(rotation)과 폐기를 관리해야 하는 번거로움이 있습니다. Tailscale SSH는 이런 키 관리 부담을 완전히 제거합니다. Tailscale의 인증 체계를 SSH 인증에 통합하여, Tailscale에 로그인한 상태이면 별도의 SSH 키 없이도 서버에 접속할 수 있습니다. 접근 권한은 위에서 설명한 ACL/Grants 정책으로 제어됩니다.

# Tailscale SSH 사용 (별도의 키 불필요)
ssh user@homelab-server.tailnet-name.ts.net

# 또는 MagicDNS 짧은 이름 사용
ssh user@homelab-server

 

Tailscale SSH를 활성화하려면 서버 측에서 다음 명령어를 실행합니다. 이후에는 Tailscale이 SSH 연결을 관리하며, 기존의 OpenSSH는 비활성화하거나 Tailnet 내부에서만 접근 가능하도록 설정하는 것이 보안상 좋습니다.

# 서버에서 Tailscale SSH 활성화
sudo tailscale set --ssh

4. Tailscale 도메인 서비스 활용

Tailscale은 자체적으로 DNS와 도메인 관련 기능을 제공하며, 이를 통해 IP 주소를 기억할 필요 없이 직관적인 이름으로 서비스에 접근할 수 있습니다. 특히 MagicDNS, HTTPS 인증서 자동 발급, Split DNS, 그리고 Tailscale Serve/Funnel 기능은 홈랩 운영에서 매우 유용한 도구들입니다.

MagicDNS

MagicDNS는 Tailnet에 등록된 모든 디바이스에 자동으로 DNS 이름을 부여하는 기능입니다.

별도의 DNS 서버를 운영하거나 hosts 파일을 수정할 필요 없이, 디바이스 이름만으로 접근이 가능합니다. MagicDNS는 Admin Console의 DNS 설정에서 활성화할 수 있으며, 활성화 후에는 두 가지 형태의 도메인 이름을 사용할 수 있습니다.

# 짧은 이름 (같은 Tailnet 내에서만 동작)
ping homelab-server

# 정규화된 도메인 이름 (FQDN)
ping homelab-server.tailnet-name.ts.net

 

짧은 이름은 같은 Tailnet에 속한 디바이스끼리만 해석(resolve)되므로, 외부 DNS와 충돌할 위험이 없습니다. 정규화된 도메인 이름(FQDN)은 <hostname>.<tailnet-name>.ts.net 형태이며, Tailscale이 공식적으로 관리하는 도메인입니다. 이 FQDN은 HTTPS 인증서 발급에도 활용됩니다.

HTTPS 인증서 자동 발급

Tailscale은 .ts.net 도메인에 대한 HTTPS 인증서를 Let's Encrypt를 통해 자동으로 발급하고 갱신해 줍니다. 이를 통해 Tailnet 내부의 서비스도 브라우저에서 "안전한 연결"로 접근할 수 있습니다. HTTPS 인증서 기능은 Admin Console의 DNS 설정에서 "Enable HTTPS"를 활성화하면 사용할 수 있습니다.

# HTTPS 인증서 발급
tailscale cert homelab-server.tailnet-name.ts.net

# 인증서 파일 확인
ls -la homelab-server.tailnet-name.ts.net.*
# homelab-server.tailnet-name.ts.net.crt  (인증서)
# homelab-server.tailnet-name.ts.net.key  (개인키)

 

발급된 인증서를 Nginx, Caddy 등의 리버스 프록시에 설정하면, Tailnet 내부에서 HTTPS로 서비스에 접근할 수 있습니다. 다만 이 인증서는 .ts.net 도메인에 대해서만 발급되므로, 커스텀 도메인(예: n8n.yourdomain.com)에는 사용할 수 없습니다. 커스텀 도메인에 대한 HTTPS는 Cloudflare와의 복합 활용 전략에서 다룹니다.

Split DNS

Split DNS는 특정 도메인에 대한 DNS 쿼리를 지정된 DNS 서버로 라우팅하는 기능입니다. 예를 들어, *.internal.company.com에 대한 DNS 조회는 회사 내부 DNS 서버로 보내고, 나머지는 공용 DNS(예: 8.8.8.8)를 사용하도록 설정할 수 있습니다. 홈랩 환경에서는 Pi-hole이나 AdGuard Home과 연동하여 광고 차단 DNS를 Tailnet 전체에 적용하는 데 주로 활용됩니다.

 

Admin Console에서 DNS > Nameservers로 이동하여 "Add nameserver"를 선택하고, "Restrict to domain" 옵션을 활성화하여 특정 도메인을 지정할 수 있습니다. 이렇게 설정하면 해당 도메인에 대한 DNS 쿼리만 지정된 DNS 서버로 전달되고, 나머지 도메인은 글로벌 DNS 설정을 따릅니다.

Split DNS를 활용한 커스텀 내부 도메인의 설정
Split DNS를 활용한 커스텀 내부 도메인의 설정

Tailscale Serve와 Funnel

Tailscale Serve는 로컬에서 실행 중인 서비스를 Tailnet 내부에 HTTPS로 안전하게 노출하는 기능입니다. Tailscale Funnel은 한 단계 더 나아가 Tailnet 외부, 즉 공용 인터넷에서도 접근할 수 있도록 합니다. 두 기능 모두 Tailscale이 리버스 프록시 역할을 대신하므로, 별도의 Nginx나 Caddy 설정 없이도 서비스를 노출할 수 있습니다.

# Tailscale Serve: Tailnet 내부에서만 접근 가능
tailscale serve https / http://localhost:5678

# Tailscale Funnel: 공용 인터넷에서도 접근 가능
tailscale funnel https / http://localhost:5678

# 현재 설정 확인
tailscale serve status

 

Serve를 설정하면 https://homelab-server.tailnet-name.ts.net으로 Tailnet 내부에서 접근할 수 있고, Funnel을 설정하면 같은 URL로 인터넷 어디서든 접근할 수 있습니다. 다만 Funnel은 ACL 정책에서 해당 노드에 대해 Funnel을 허용해야 하며, Cloudflare Tunnel과 같은 목적으로 사용할 수 있지만 대역폭과 기능 면에서 차이가 있으므로 상황에 맞게 선택해야 합니다.

flowchart LR
    subgraph internet["Public Internet"]
        USER[External User]
    end

    subgraph tailnet["Tailnet (Private)"]
        ADMIN[Admin Device]
        PHONE[Mobile Device]
    end

    subgraph server["Home Server"]
        TS[Tailscale]
        SVC[n8n :5678]
    end

    ADMIN -->|"Serve (HTTPS)"| TS
    PHONE -->|"Serve (HTTPS)"| TS
    USER  -->|"Funnel (HTTPS)"| TS
    TS -->|"proxy"| SVC

    style TS fill:#4a90d9,stroke:#4a90d9,stroke-width:2
    style USER fill:#4a90d9,stroke:#f0a030,stroke-width:1.5

5. Tailscale vs Cloudflare Tunnel 특장점 비교

Tailscale과 Cloudflare Tunnel은 모두 "포트 포워딩 없이 안전하게 서비스를 노출한다"는 공통된 목적을 가지고 있지만, 설계 철학과 접근 방식이 근본적으로 다릅니다. Tailscale은 디바이스 간의 P2P 메시 네트워크를 구축하는 데 초점을 맞추고, Cloudflare Tunnel은 서비스를 Cloudflare의 글로벌 에지 네트워크를 통해 안전하게 노출하는 데 초점을 맞춥니다. 각각의 강점과 한계를 정확히 이해하면, 두 도구를 상황에 맞게 활용하거나 조합하여 최적의 인프라를 구성할 수 있습니다.

핵심 차이점 비교표

비교 항목 Tailscale Cloudflare Tunnel
핵심 목적 디바이스 간 사설 네트워크(VPN) 구축 서비스를 인터넷에 안전하게 노출
프로토콜 WireGuard (P2P 메시) QUIC/HTTP2 (클라이언트-서버)
트래픽 경로 디바이스 간 직접 연결 (P2P) Cloudflare 에지 네트워크 경유
지연시간 (Latency) 매우 낮음 (P2P 직접 연결 시) 중간 (에지 네트워크 경유)
대역폭 사실상 무제한 (P2P) Cloudflare 정책에 따른 제한 가능
도메인 요구 불필요 (MagicDNS 자동 제공) 필수 (Cloudflare에 등록된 도메인)
HTTPS .ts.net 도메인에 자동 발급 자동 발급 및 관리 (커스텀 도메인)
DDoS 보호 미제공 (사설 네트워크이므로 불필요) 기본 제공 (Cloudflare 인프라)
CDN/캐싱 미제공 기본 제공 (글로벌 CDN)
WAF 미제공 기본 제공 (Web Application Firewall)
접근 주체 Tailscale 클라이언트 설치 필수 아무나 (브라우저만 있으면 접근 가능)
클라이언트 설치 모든 접속 디바이스에 필요 서버 측만 설치 (cloudflared)
무료 플랜 100 디바이스, 3 사용자 50 사용자 (Zero Trust)
네트워크 접근 전체 서브넷 라우팅 가능 서비스 단위 노출 (개별 설정)
SSH 접근 Tailscale SSH (키 관리 불필요) Cloudflare Access + 브라우저 기반 SSH
설정 복잡도 매우 낮음 중간 (도메인, DNS, 터널 설정 필요)

Tailscale과 Cloudflare Tunnel의 네트워크 흐름 비교
Tailscale과 Cloudflare Tunnel의 네트워크 흐름 비교

Tailscale이 더 적합한 경우

Tailscale은 "내가 소유한 디바이스들을 서로 안전하게 연결하는" 시나리오에서 압도적인 강점을 발휘합니다. 다음과 같은 경우에 Tailscale을 선택하는 것이 더 적합합니다.

  • 첫째, 관리 목적의 원격 접속이 필요한 경우입니다. SSH로 서버를 관리하거나, Portainer/Grafana 같은 관리 도구에 접근하거나, 데이터베이스에 직접 연결하는 등의 작업은 일반 사용자에게 공개할 필요가 없습니다. 이런 관리 인터페이스는 Tailnet 내부에서만 접근 가능하도록 설정하는 것이 가장 안전합니다. Tailscale을 설치한 디바이스에서만 접근이 가능하므로, 별도의 인증 레이어 없이도 높은 수준의 보안이 보장됩니다.
  • 둘째, 전체 네트워크에 대한 VPN 접근이 필요한 경우입니다. Subnet Router를 통해 로컬 네트워크의 모든 기기에 접근할 수 있으므로, Tailscale 클라이언트가 설치되지 않은 프린터, IP 카메라, IoT 장비에도 접근할 수 있습니다. Cloudflare Tunnel은 개별 서비스 단위로만 노출할 수 있어, 이런 네트워크 수준의 접근에는 적합하지 않습니다.
  • 셋째, 낮은 지연시간과 높은 대역폭이 중요한 경우입니다. 파일 전송, 미디어 스트리밍, 원격 데스크톱 등 대용량 트래픽이 오가는 작업에서는 P2P 직접 연결이 훨씬 유리합니다. Tailscale은 NAT traversal을 통해 대부분의 환경에서 P2P 직접 연결을 달성하므로, LAN에 가까운 속도를 기대할 수 있습니다.

Cloudflare Tunnel이 더 적합한 경우

Cloudflare Tunnel은 "서비스를 불특정 다수에게 안전하게 공개하는" 시나리오에서 강점을 발휘합니다. 다음과 같은 경우에 Cloudflare를 선택하는 것이 더 적합합니다.

  • 첫째, 웹사이트/API 등 공개 서비스를 운영하는 경우입니다. 블로그, 포트폴리오, API 서버 등 인터넷에서 누구나 접근해야 하는 서비스는 Cloudflare Tunnel이 적합합니다. Tailscale은 클라이언트 설치가 필수이므로, 불특정 다수에게 서비스를 제공하는 용도로는 사용할 수 없습니다(Funnel 기능이 있지만 제약이 있습니다).
  • 둘째, DDoS 보호와 CDN이 필요한 경우입니다. Cloudflare의 글로벌 에지 네트워크는 DDoS 공격을 자동으로 완화하고, 정적 콘텐츠를 캐싱하여 원본 서버의 부하를 줄여줍니다. 홈서버 환경에서 외부 공개 서비스를 운영할 때 이런 보호는 필수적입니다.
  • 셋째, 커스텀 도메인과 HTTPS가 필요한 경우입니다. Cloudflare는 등록된 도메인에 대해 자동으로 SSL/TLS 인증서를 관리하며, 다양한 보안 헤더와 WAF 규칙을 적용할 수 있습니다. blog.yourdomain.com, api.yourdomain.com 같은 전문적인 도메인으로 서비스를 노출하려면 Cloudflare가 필수적입니다.

보안 모델 비교

두 서비스의 보안 모델은 근본적으로 다른 접근 방식을 취합니다. Tailscale은 네트워크 레벨의 제로 트러스트를 구현합니다. 모든 통신이 WireGuard로 암호화되며, Tailscale 클라이언트가 설치되고 인증된 디바이스만 네트워크에 참여할 수 있습니다. 접근 제어는 ACL/Grants 정책으로 관리하며, 모든 디바이스에서 로컬로 정책이 적용됩니다. 서비스가 인터넷에 전혀 노출되지 않으므로, 공격 표면(attack surface)이 최소화됩니다.

 

Cloudflare는 애플리케이션 레벨의 제로 트러스트를 구현합니다. Cloudflare Access 정책을 통해 서비스별로 인증을 요구하며, 이메일 OTP, IdP(Identity Provider) 연동 등 다양한 인증 방식을 지원합니다. WAF(Web Application Firewall)로 일반적인 웹 공격(SQL Injection, XSS 등)을 방어하고, Bot Management로 악성 봇 트래픽을 필터링합니다. 하지만 서비스 자체는 인터넷에 노출되어 있으므로, Cloudflare의 보호 레이어에 의존하게 됩니다.

graph TB
    subgraph tailscale_model["Tailscale 보안 모델"]
        TA[인증된 디바이스만 접근]
        TB[WireGuard E2E 암호화]
        TC[ACL/Grants 정책]
        TD[서비스가 인터넷에 비노출]
        TA --> TB --> TC --> TD
    end

    subgraph cloudflare_model["Cloudflare 보안 모델"]
        CA[서비스가 인터넷에 노출]
        CB[Cloudflare Edge가 트래픽 검사]
        CC[Access 정책으로 인증 요구]
        CD[WAF/DDoS 보호]
        CA --> CB --> CC --> CD
    end

    style tailscale_model fill:#4a90d9,stroke:#4a90d9,stroke-width:2
    style cloudflare_model fill:#f0a030,stroke:#f0a030,stroke-width:2

6. Tailscale과 Cloudflare의 복합 활용 전략

실제 홈랩이나 소규모 인프라에서는 Tailscale과 Cloudflare 중 하나만 사용하기보다, 두 서비스를 함께 활용하는 것이 가장 이상적입니다. 공개 서비스는 Cloudflare Tunnel로 보호하면서, 관리 인터페이스는 Tailscale로만 접근 가능하게 설정하면, 보안과 편의성 두 가지를 모두 확보할 수 있습니다. 이 섹션에서는 실제 환경에서 검증된 복합 활용 아키텍처를 소개합니다.

Tailscale과 Cloudflare Tunnel 복합 활용을 위한 아키텍처 구성도
Tailscale과 Cloudflare Tunnel 복합 활용을 위한 아키텍처 구성도

역할 분리 원칙

복합 활용의 핵심 원칙은 "역할에 따른 서비스 분리"입니다. 모든 서비스를 두 채널 모두에 노출하는 것이 아니라, 각 서비스의 특성에 맞는 채널을 선택합니다. 이 원칙을 적용하면 다음과 같은 분류가 됩니다.

서비스 유형 접근 채널 이유
블로그/웹사이트 Cloudflare Tunnel 불특정 다수가 접근해야 하며, CDN/DDoS 보호가 필요합니다
API 서버 Cloudflare Tunnel 외부 클라이언트/웹훅이 접근해야 하며, WAF 보호가 필요합니다
n8n 워크플로우 UI Cloudflare Tunnel + Access 외부에서 접근이 필요하지만, 인증으로 보호해야 합니다
n8n 웹훅 엔드포인트 Cloudflare Tunnel Telegram, GitHub 등 외부 서비스의 웹훅을 수신해야 합니다
Portainer Tailscale Only 관리자만 접근하는 Docker 관리 도구입니다
Grafana/Prometheus Tailscale Only 관리자만 접근하는 모니터링 도구입니다
PostgreSQL Tailscale Only 데이터베이스는 절대 인터넷에 노출하면 안 됩니다
SSH Tailscale SSH 서버 관리는 Tailnet 내부에서만 수행합니다
NAS 파일 공유 (SMB) Tailscale Only SMB 프로토콜은 Cloudflare Tunnel로 노출할 수 없습니다
Jellyfin (미디어) Tailscale Only 가족만 접근하는 미디어 서비스입니다

복합 아키텍처 구성도

아래는 Mac Mini 홈서버에서 Tailscale과 Cloudflare를 함께 사용하는 전형적인 아키텍처입니다. Cloudflare Tunnel은 외부 공개 서비스를, Tailscale은 관리 및 내부 서비스를 담당합니다.

flowchart TB
    subgraph external["External (Internet)"]
        VISITOR[Website Visitors]
        WEBHOOK[Webhook Services<br/>Telegram, GitHub]
        ADMIN_EXT[Admin<br/>외출 중]
    end

    subgraph cf["Cloudflare Network"]
        EDGE[Cloudflare Edge<br/>CDN + DDoS + WAF]
        ACCESS[Cloudflare Access<br/>인증 정책]
    end

    subgraph ts["Tailscale Network"]
        TS_ADMIN[Admin Device<br/>MacBook]
        TS_PHONE[Mobile Device]
    end

    subgraph server["Mac Mini Home Server (Docker)"]
        CFD[cloudflared<br/>Tunnel Connector]
        TSC[Tailscale<br/>Mesh Node]
        NGINX[Nginx<br/>Reverse Proxy]
        N8N[n8n<br/>:5678]
        BLOG[Blog<br/>:3000]
        PORT[Portainer<br/>:9000]
        GRAF[Grafana<br/>:3001]
        DB[(PostgreSQL<br/>:5432)]
    end

    VISITOR -->|HTTPS| EDGE
    WEBHOOK -->|HTTPS| EDGE
    ADMIN_EXT -->|WireGuard P2P| TSC

    EDGE -->|Tunnel| CFD
    EDGE -->|인증 필요| ACCESS
    ACCESS -->|승인 후| CFD

    CFD --> NGINX
    NGINX --> N8N
    NGINX --> BLOG

    TS_ADMIN -->|WireGuard| TSC
    TS_PHONE -->|WireGuard| TSC
    TSC --> PORT
    TSC --> GRAF
    TSC --> DB

    N8N --> DB
    BLOG --> DB

    style EDGE fill:#f0a030,stroke:#f0a030,stroke-width:2
    style TSC fill:#4a90d9,stroke:#4a90d9,stroke-width:2
    style ACCESS fill:#f0a030,stroke:#f0a030,stroke-width:1.5
    style CFD fill:#f0a030,stroke:#f0a030,stroke-width:1.5

Docker Compose 통합 구성 예시

아래는 하나의 Docker Compose 파일에서 Tailscale과 Cloudflare Tunnel을 함께 운영하는 프로덕션 설정입니다. 각 서비스의 역할에 따라 Cloudflare 또는 Tailscale을 통한 접근을 설정합니다.

# docker-compose.yml - Tailscale + Cloudflare 복합 구성
services:
  # === 네트워크 인프라 ===

  # Cloudflare Tunnel - 외부 공개 서비스용
  cloudflared:
    container_name: cloudflared
    image: cloudflare/cloudflared:latest
    restart: unless-stopped
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${CF_TUNNEL_TOKEN}
    networks:
      - public-net

  # Tailscale - 관리/내부 서비스용
  tailscale:
    container_name: tailscale
    image: tailscale/tailscale:latest
    restart: unless-stopped
    network_mode: host
    privileged: true
    environment:
      - TS_HOSTNAME=homelab
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=false
      - TS_ROUTES=192.168.1.0/24
      - TS_EXTRA_ARGS=--advertise-exit-node --accept-routes
    volumes:
      - ./tailscale-data:/var/lib
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - NET_RAW

  # === Cloudflare를 통해 공개되는 서비스 ===

  # Nginx 리버스 프록시
  nginx:
    container_name: nginx
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/ssl:/etc/nginx/ssl
    networks:
      - public-net
      - internal-net

  # n8n 워크플로우 자동화
  n8n:
    container_name: n8n
    image: n8nio/n8n:latest
    restart: unless-stopped
    environment:
      - N8N_HOST=0.0.0.0
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.yourdomain.com/
    volumes:
      - ./n8n-data:/home/node/.n8n
    networks:
      - internal-net

  # === Tailscale을 통해서만 접근 가능한 서비스 ===
  # (network_mode: host인 Tailscale 컨테이너를 통해
  #  호스트 네트워크의 포트로 접근)

  # Portainer - Docker 관리
  portainer:
    container_name: portainer
    image: portainer/portainer-ce:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer-data:/data
    networks:
      - internal-net

  # Grafana - 모니터링 대시보드
  grafana:
    container_name: grafana
    image: grafana/grafana:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3001:3000"
    volumes:
      - ./grafana-data:/var/lib/grafana
    networks:
      - internal-net

  # PostgreSQL - 데이터베이스
  postgres:
    container_name: postgres
    image: postgres:16
    restart: unless-stopped
    ports:
      - "127.0.0.1:5432:5432"
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=homelab
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - internal-net

networks:
  public-net:
    driver: bridge
  internal-net:
    driver: bridge

 

이 구성에서 핵심적인 보안 포인트는 다음과 같습니다. Portainer, Grafana, PostgreSQL의 포트 바인딩이 127.0.0.1로 설정되어 있어, 호스트의 localhost에서만 접근 가능합니다. 이는 외부 네트워크에서 직접 접근이 불가능하다는 의미이며, Tailscale의 network_mode: host 설정을 통해 Tailnet에 연결된 디바이스만 이 포트들에 접근할 수 있습니다. 반면 Nginx와 n8n은 Cloudflare Tunnel을 통해 외부에 노출되며, Cloudflare의 보안 기능(DDoS, WAF, Access)으로 보호됩니다.

DNS 전략  |  복합 환경에서의 도메인 관리

복합 환경에서의 DNS 관리는 세 가지 레이어로 구성하는 것이 깔끔합니다.

  • 첫 번째 레이어는 퍼블릭 도메인으로, Cloudflare DNS에서 관리합니다. blog.yourdomain.com, n8n.yourdomain.com 같은 외부 공개 도메인을 Cloudflare에 등록하고, Cloudflare Tunnel의 Public Hostname으로 연결합니다. 이 도메인들은 인터넷 어디서든 접근 가능하며, Cloudflare의 프록시를 통해 보호됩니다.
  • 두 번째 레이어는 Tailnet 내부 도메인으로, MagicDNS가 자동으로 처리합니다. homelab.tailnet-name.ts.net 같은 도메인으로 Tailnet 내부의 디바이스에 접근할 수 있습니다. 이 도메인은 Tailscale 클라이언트가 설치된 디바이스에서만 해석됩니다.
  • 세 번째 레이어는 커스텀 내부 도메인으로, Split DNS를 활용합니다. Pi-hole이나 AdGuard Home을 Tailnet에 연결하고, *.home.local 같은 내부 도메인을 해당 DNS 서버로 라우팅하도록 설정합니다. 이렇게 하면 Tailnet에 연결된 모든 디바이스에서 일관된 내부 도메인을 사용할 수 있습니다.
레이어 도메인 예시 관리 주체 접근 범위
퍼블릭 blog.yourdomain.com Cloudflare DNS 인터넷 전체
Tailnet homelab.ts-name.ts.net MagicDNS (자동) Tailnet 내부만
커스텀 내부 portainer.home.local Split DNS (Pi-hole) Tailnet 내부만

7. 트러블슈팅 가이드

Tailscale은 대부분의 환경에서 별다른 문제 없이 동작하지만, 특정 네트워크 환경이나 Docker 설정에서 이슈가 발생할 수 있습니다. 이 섹션에서는 실제 운영 중 자주 만나는 문제들과 그 해결 방법을 정리합니다.

연결 상태 진단

문제가 발생했을 때 가장 먼저 확인해야 할 것은 연결 상태입니다. tailscale status 명령어로 현재 Tailnet의 모든 노드 상태를 확인할 수 있으며, tailscale netcheck 명령어로 네트워크 환경을 진단할 수 있습니다.

# 기본 상태 확인
tailscale status

# 출력 예시:
# 100.100.100.1  homelab       user@   linux   active; direct 192.168.1.10:41641
# 100.100.100.2  macbook       user@   macOS   active; relay "tok"
# 100.100.100.3  phone         user@   iOS     idle; offline

# 네트워크 환경 진단
tailscale netcheck

# 특정 노드에 대한 상세 연결 정보
tailscale ping homelab-server

 

연결 상태에서 direct로 표시되면 P2P 직접 연결이 성립된 것이고, relay "tok" 같이 DERP 서버명이 표시되면 중계 서버를 경유하고 있는 것입니다. P2P 직접 연결이 안 되는 주된 원인은 양쪽 네트워크의 NAT 타입이 모두 Symmetric NAT인 경우입니다. 이 경우에도 DERP 중계 서버를 통해 연결은 유지되지만, 지연시간이 증가할 수 있습니다.

Docker 환경에서의 일반적인 문제

Docker 환경에서 Tailscale을 운영할 때 자주 만나는 문제들을 정리합니다.

문제 1  |  TUN 디바이스를 찾을 수 없음

wgengine.NewUserspaceEngine(tun "tailscale0") error: tstun.New("tailscale0"):
  permission denied

 

이 오류는 Docker 컨테이너가 /dev/net/tun 디바이스에 접근할 수 없을 때 발생합니다. Docker Compose에서 /dev/net/tun:/dev/net/tun 볼륨 마운트와 NET_ADMIN, NET_RAW capabilities가 올바르게 설정되어 있는지 확인합니다. Synology NAS에서는 /dev/net/tun 디바이스가 기본적으로 존재하지 않는 경우가 있으며, 이때는 다음 명령어로 생성해야 합니다.

# Synology NAS에서 TUN 디바이스 생성
sudo mkdir -p /dev/net
sudo mknod /dev/net/tun c 10 200
sudo chmod 600 /dev/net/tun

문제 2  |  Subnet Route가 동작하지 않음

Subnet Router를 설정했는데 다른 디바이스에서 로컬 네트워크의 기기에 접근할 수 없는 경우, 다음 항목들을 순서대로 확인합니다.

# 1. IP 포워딩 활성화 확인
cat /proc/sys/net/ipv4/ip_forward
# 출력이 1이어야 합니다

# 2. Tailscale에서 라우트 광고 상태 확인
tailscale status --json | jq '.Self.AllowedIPs'

# 3. Admin Console에서 라우트 승인 여부 확인
# https://login.tailscale.com/admin/machines에서 해당 머신의
# Route settings에서 서브넷이 승인되어 있는지 확인합니다

# 4. 접속하는 디바이스에서 라우트 수락 확인
tailscale set --accept-routes

문제 3  |  Auth Key 만료 후 재연결 실패

Auth Key의 최대 유효 기간은 90일입니다. 하지만 태그(Tag)가 부여된 노드는 키가 만료되더라도 연결이 유지됩니다. 이는 태그가 부여된 노드에서는 키 만료(key expiry)가 자동으로 비활성화되기 때문입니다. 따라서 프로덕션 환경에서는 반드시 Auth Key 생성 시 Tags 옵션을 설정하는 것을 권장합니다. 만약 태그 없이 키가 만료되어 연결이 끊어진 경우에는, 새로운 Auth Key를 생성하여 환경 변수를 교체하고 컨테이너를 재시작하면 됩니다.

Cloudflare와 Tailscale 동시 운영 시 주의사항

두 서비스를 동시에 운영할 때 발생할 수 있는 주요 이슈들을 정리합니다.

  • DNS 충돌: Tailscale의 TS_ACCEPT_DNS=true 설정과 Cloudflare의 DNS 설정이 충돌할 수 있습니다. 특히 Tailscale의 MagicDNS가 시스템의 DNS 설정을 변경하면, Cloudflare Tunnel의 DNS 해석에 영향을 줄 수 있습니다. 이 경우 Tailscale에서 TS_ACCEPT_DNS=false로 설정하고, DNS는 수동으로 관리하는 것이 안정적입니다.
  • 포트 바인딩 전략: Cloudflare를 통해 노출하는 서비스와 Tailscale을 통해서만 접근하는 서비스의 포트 바인딩을 명확히 구분해야 합니다. Cloudflare로 노출하는 서비스는 0.0.0.0에 바인딩하고, Tailscale 전용 서비스는 127.0.0.1에 바인딩하여 외부 접근을 원천적으로 차단합니다.

8. 마무리

이 글에서 다룬 내용을 정리하면 다음과 같습니다.

Tailscale은 WireGuard 기반의 P2P 메시 VPN으로, 설치와 설정이 매우 간단하면서도 엔터프라이즈급의 보안 기능을 제공합니다. 프로덕션 환경에서는 Docker Compose를 활용한 컨테이너화된 배포가 권장되며, Auth Key와 태그를 조합하면 자동화된 인증과 접근 제어가 가능합니다. Zero Trust 네트워크는 ACL/Grants 정책을 통해 구현하며, deny-by-default 원칙에 따라 필요한 통신만 명시적으로 허용합니다.

 

Tailscale과 Cloudflare는 경쟁 관계가 아닌 상호 보완 관계입니다. Cloudflare는 공개 서비스의 보호와 성능 최적화에, Tailscale은 사설 네트워크의 보안과 관리 접근에 각각 강점을 가집니다. 두 서비스를 역할에 따라 적절히 조합하면, 개인이 운영하는 홈랩에서도 기업 수준의 보안 인프라를 구축할 수 있습니다.


참고 자료