김솔비 블로그
기술 블로그

Tailscale은 무엇인가: 내 기기들만의 사설망을 5분 만에

4분 읽기

TL;DR

  • Tailscale은 내 기기들을 하나의 사설망(tailnet)으로 묶어 준다. 어디에 있든 기기끼리 사설 IP로 바로 통신한다.
  • 공유기 설정도, VPN 서버도 필요 없다. 로그인만 하면 된다.
  • serve는 tailnet 안에만, Funnel은 인터넷에 서비스를 연다. Funnel은 열 경로를 최소한으로 좁혀서 쓴다.

들어가며

집에 서버를 하나 두면 바로 이런 고민이 생긴다. "밖에서 이 서버에 SSH로 들어가려면? 관리 화면은 나만 보고 싶은데?"

전통적인 답은 공유기 포트 포워딩이나 직접 VPN 서버를 세우는 것이다. 둘 다 번거롭고, 잘못 설정하면 위험하다. Tailscale은 이 문제를 "로그인하면 끝" 수준으로 줄여 준다.

1. Tailscale이 하는 일

Tailscale을 기기마다 설치하고 같은 계정으로 로그인하면, 그 기기들은 tailnet이라는 사설망에 들어간다.

   [내 Mac] ─────┐
                 ├── tailnet (100.x.y.z 대역의 사설 IP)
 [내 휴대폰] ────┤
                 │
   [집 서버] ────┘
  • 각 기기는 100.x.y.z 형태의 고정 사설 IP를 받는다. 카페 와이파이에 있든 LTE에 있든 그대로다.
  • 기기끼리 직접 연결(peer-to-peer)한다. 중앙 서버를 거치지 않아서 빠르다. 직접 연결이 안 되는 네트워크에서는 Tailscale의 중계 서버(DERP)를 거친다.
  • 통신은 WireGuard로 암호화된다. WireGuard는 코드가 짧고 빠른 최신 VPN 프로토콜이다.

왜 포트를 안 열어도 되나

공유기 뒤에 있는 기기들은 바깥에서 먼저 들어오는 연결을 받을 수 없다. Tailscale은 양쪽 기기가 동시에 바깥으로 연결을 시도하게 해서 공유기의 NAT를 통과한다(NAT traversal). 그래서 포트 포워딩 없이도 기기끼리 만날 수 있다.

2. 자주 쓰는 기능

MagicDNS

IP 대신 기기 이름으로 접속할 수 있다. ssh my-server처럼 쓰면 된다. tailnet 안에서만 풀리는 이름이다.

ACL (접근 제어)

tailnet 안에서도 "어떤 기기가 어떤 기기의 어느 포트에 접속할 수 있나"를 JSON으로 정할 수 있다. 예를 들어 "CI용 임시 노드는 서버의 SSH에만 접속 가능"처럼 좁힐 수 있다.

serve: tailnet 안에서만 HTTPS로

서버에서 돌고 있는 웹 앱을 tailnet 안에서만 HTTPS 주소로 열어 준다.

bash
tailscale serve --bg 8080 # → https://my-server.<tailnet 이름>.ts.net 으로 접속 가능 (tailnet 안에서만)

인증서도 Tailscale이 알아서 발급한다. 관리 화면처럼 나만 보면 되는 서비스에 딱 맞다. 인터넷에서는 아예 보이지 않으니 로그인 화면이 공격받을 일도 없다.

Funnel: 인터넷에 공개

Funnel은 serve로 연 서비스를 인터넷 전체에 공개한다. 외부 서비스가 내 서버의 파일을 가져가야 할 때(예: 소셜 API가 이미지 URL을 직접 내려받는 경우) 쓸 수 있다.

Funnel은 편한 만큼 조심해서 쓴다.

  • 경로 단위로 좁게 연다. 서비스 전체가 아니라 꼭 필요한 경로만 연다.
  • 앱에서도 한 번 더 막는다. Funnel로 들어온 요청에는 Tailscale이 표시 헤더를 붙여 준다. 앱이 이 헤더를 보고 허용한 경로가 아니면 거절하면, 설정 실수가 있어도 나머지가 드러나지 않는다.
  • 오래 열어 두지 않는다. 필요한 순간에만 쓰는 주소라면 일회용 토큰과 함께 쓴다.

3. CI에서 tailnet에 들어가기

GitHub Actions 같은 CI가 집 서버에 배포하려면, CI 러너가 서버에 닿아야 한다. 서버 포트를 인터넷에 여는 대신 CI 러너를 잠깐 tailnet에 넣는 방법이 있다.

yaml
- name: Connect to Tailscale uses: tailscale/github-action@v3 with: authkey: ${{ secrets.TS_AUTHKEY }} # 임시(ephemeral) 키
  • 임시(ephemeral) 키를 쓰면 작업이 끝난 러너는 tailnet에서 자동으로 사라진다.
  • 키에 태그를 붙이고 ACL로 그 태그가 닿을 수 있는 곳을 좁혀 두면, 키가 새도 할 수 있는 일이 제한된다.
  • 서버의 SSH는 tailnet 안에서만 열려 있으면 된다.

4. Cloudflare Tunnel과 무엇이 다른가

둘 다 "포트를 열지 않고 집 서버에 닿게" 해 주지만 목적이 다르다.

TailscaleCloudflare Tunnel
기본 대상나와 내 기기인터넷의 방문자
잘 맞는 일SSH, 관리 화면, 기기 간 통신, CI 배포공개 웹 서비스
공개 범위기본은 비공개, Funnel로 일부만 공개기본이 공개, Access로 제한 가능
도메인tailnet 전용 주소내 도메인

그래서 둘을 같이 쓰는 경우가 많다. 방문자가 쓰는 서비스는 Cloudflare Tunnel로, 나만 쓰는 통로는 Tailscale로 나누는 식이다. 실제로 어떻게 나눴는지는 개인 프로젝트 인프라 설계에 정리했다.

정리

  • Tailscale은 로그인만으로 만드는 개인 사설망이다.
  • serve는 나만, Funnel은 모두에게. Funnel은 좁게, 짧게, 두 겹으로.
  • CI는 임시 키로 잠깐 tailnet에 들어왔다 나간다.

무료 플랜으로 개인 기기 수십 대까지 쓸 수 있어서, 집 서버를 하나라도 운영한다면 가장 먼저 깔아 둘 만한 도구다.