VPN 동작 원리의 이해 [with WireGuard, Tailscale]

VPN 동작 원리의 이해 [with WireGuard, Tailscale]

서론

필자의 홈서버는 일부 서비스(포트폴리오, 블로그)를 제외하곤 외부에서 접근할 수 없다.
불가피하게 외부에서 접근하기 위해서는 VPN을 활용해야만 한다. 구체적인 구성은 지난 글에 정리해 두었다.

그런데 홈서버를 다루는 글들을 보면 하나같이 설치하고 로그인만 하면 끝이라며 Tailscale을 권한다.

정작 필자의 홈서버에는 그게 불가능했고, 결국 손이 훨씬 많이 가는 순수 WireGuard로 붙여야 했다.

이번 글에서는 그간 막연히 알고 있던 VPN의 동작 원리부터 제약까지 살펴보고자 한다.


본론

대황클로드 님께 VPN이란 무엇인지 감히 여쭈어보았다.

VPN은 Virtual Private Network(가상 사설망)의 약자로, 인터넷 연결을 암호화된 터널로 감싸서 안전하게 데이터를 주고받게 해주는 기술입니다.

기본 원리

평소 인터넷을 사용하면 내 기기에서 나가는 데이터가 통신사(ISP)를 거쳐 목적지 서버로 갑니다. 이 과정에서 통신사나 중간에 있는 누군가가 내 통신 내용을 들여다볼 수 있습니다.

VPN을 켜면 내 데이터가 먼저 암호화되어 VPN 서버로 전달되고, 거기서 다시 목적지로 나갑니다. 그래서 목적지 서버 입장에서는 내 진짜 IP 주소가 아니라 VPN 서버의 IP 주소를 보게 됩니다. 마치 내가 VPN 서버가 있는 위치에서 접속하는 것처럼 보이는 거죠.

주요 용도

보안 측면에서는 카페나 공항 같은 공용 Wi-Fi를 쓸 때 통신 내용을 보호할 수 있습니다. 공용 네트워크는 해킹 위험이 있는데 VPN이 데이터를 암호화해주기 때문입니다.

프라이버시 측면에서는 실제 IP와 위치를 숨길 수 있어서, 통신사나 웹사이트가 내 활동을 추적하기 어려워집니다.

지역 우회 측면에서는 특정 국가에서만 볼 수 있는 콘텐츠에 접근하거나, 반대로 차단된 사이트에 접속할 때 사용하기도 합니다.

회사에서는 직원이 외부에서도 사내 네트워크에 안전하게 접속하도록 하는 용도로 많이 씁니다. 원격 근무할 때 회사 시스템에 접근하는 경우가 대표적입니다.


출처 : Anthropic. (2026). Claude Opus 4.8 [Large language model]. https://claude.ai/

VPN(Virtual Private Network)이란

VPN(Virtual Private Network)은 말 그대로 가상의 사설망이다. 기존에는 물리적으로 떨어진 두 네트워크를 연결하기 위해 별도의 사설망(랜선)을 구성하여 다이렉트로 연결하였다면, VPN이 탄생함에 따라 이를 인터넷상에 '가상'으로 구성할 수 있게 됐다. 여기서 핵심은 "신뢰할 수 없는 공용 인터넷 위에, 같은 내부망에 있는 것처럼 통신하는 통로를 만든다"는 데 있다.

즉, VPN은 인터넷과 완전히 분리된 마술 같은 게 아니라 공용 인터넷망 위에 암호화된 통로를 만들어 통신하는 것이다. 이 말인즉슨 암호화에 사용한 세션 키가 유출되면 해당 세션의 패킷 내부를 들여다볼 수 있게 된다는 뜻이기도 하다.

다만 WireGuard처럼 순방향 비밀성(forward secrecy)을 갖춘 프로토콜은 세션 키를 주기적으로 갈아치우기 때문에, 정적 개인 키가 유출되더라도 과거 대화 내역까지 복호화가 가능한 것은 아니다.

참고로 VPN은 용도에 따라 크게 두 갈래로 나뉜다. 떨어진 두 네트워크를 통째로 잇는 사이트 간(Site-to-Site) VPN, 그리고 개인 기기 하나를 내부망에 붙이는 원격 접속(Remote Access) VPN이다. 이 글에서 다루는 홈서버 접근은 후자에 해당한다.

그런데 애초에 왜 이런 통로가 필요할까. 문제는 사설 IP(Private IP)에서 시작된다.

사설 IP에 대한 이해

초기 인터넷은 전체가 하나의 주소 공간이라는 전제로 설계됐다. 네트워크에 참여하는 개개인이 모두 고유한 주소를 갖고, 패킷은 변형 없이 끝에서 끝까지 직접 오간다. RFC 2775(Internet Transparency)에서는 이를 종단 간 투명성(End-to-End Transparency)이라 부르며, 다음과 같이 정의한다.

For the purposes of this document, "transparency" refers to the original Internet concept of a single universal logical addressing scheme, and the mechanisms by which packets may flow from source to destination essentially unaltered.


출처 : IETF Datatracker, "Internet Transparency, RFC 2775", https://datatracker.ietf.org/doc/html/rfc2775

즉 투명성은 "모든 주소가 전 세계에서 유일한 데다 불변이다"라는 개념과 "패킷이 출발지에서 목적지까지 본질적으로 변형 없이 흐른다"라는 두 성질의 결합이다. 이 전제는 1974년 푸쟁(Pouzin)의 제안을 거쳐 1978년 서프(Cerf)가 정식화한 catenet(네트워크들의 네트워크) 개념 때부터 깔려 있던 태생적 가정이고, 주소가 고유하다는 성질은 단순한 관례를 넘어 체크섬·암호 서명·웹 문서 등 온갖 곳에 박혀 버릴 만큼 깊었다.

그런데 IPv4 주소는 32비트로 가능한 경우의 수가 고작 43억 개뿐이라 1990년대 초에 이미 고갈이 예상되었다. Cisco 집계에 따르면 IP 기반으로 네트워크에 연결된 기기는 2018년에 이미 약 184억 개로 43억을 한참 넘어섰고, 2023년에는 약 293억 개에 이를 것으로 전망됐다.

다만 이 보고서는 2018–2023판을 마지막으로 갱신이 멈춰, 실제로 저 전망치에 도달했는지는 미지수다.

이러한 고갈을 해결하기 위해 IPv6(128비트)가 고안되었으나 30년째 전환 중이고, 당장의 대안으로 나온 게 사설 IP와 NAT다. "내부망에서는 아무나 재사용해도 되는 주소를 쓰고, 인터넷에 나갈 때만 공인 IP 하나를 나눠 쓰자"라는 것이 기본 골자이다.

근데 당장의 대안이 생각보다 효과가 좋고, IPv6 전환이 비싸서인지 아직도 IPv4를 사용하고 있다.

또한 사설 IP를 사용하는 이유가 단순히 주소가 모자라기 때문만은 아니다. 기업 내부망이나 금융권, 군대와 같이 보안을 위해 인터넷과 완전히 단절된 폐쇄망 환경을 구축하기 위해 일부러 사설 대역을 쓰는 경우도 많다. 필자의 홈서버 또한 이러한 경우라고 볼 수 있다.

사설 IP는 192.168.0.x10.x.x.x 같은 주소를 쓰는데 어느 대역이 사설 IP인지는 RFC 1918에 명시되어 있다.

대역 범위 주소 수
10.0.0.0/8 10.0.0.0 ~ 10.255.255.255 약 1,678만 개
172.16.0.0/12 172.16.0.0 ~ 172.31.255.255 약 105만 개
192.168.0.0/16 192.168.0.0 ~ 192.168.255.255 65,536개

약속은 간단하다. "이 세 대역은 누구나 내부망에서 재사용해라. 대신 공인 인터넷으로는 절대 내보내지 마라." 실제로 RFC 1918은 이 대역의 라우팅 정보를 조직 간 링크로 전파해서는 안 되며(shall not), 이 대역을 출발지나 목적지로 한 패킷을 조직 경계(일반적으로 게이트웨이, 공유기 등) 너머로 넘기지 않아야 한다(should not)고 규정한다. 전자는 강제, 후자는 권고다.

그래서 카페에서 우리 집 홈서버 192.168.0.10으로 패킷을 보내면 실제로는 이런 일이 벌어진다.

  1. 노트북이 목적지 192.168.0.10를 향한 패킷을 만들고, OS가 라우팅 테이블에서 이 주소를 어디로 보낼지 조회한다.
  2. 이때 카페 와이파이가 마침 같은 192.168.0.0/24 대역이면, OS는 목적지가 "같은 LAN 안에 있다"라고 판단한다. 그래서 게이트웨이로 넘기지 않고 ARP(Address Resolution Protocol)로 "192.168.0.10 누구야?" 하고 브로드캐스트를 뿌려, 응답한 카페 안의 엉뚱한 기기에게 패킷을 건넨다. 인터넷으로 나가 보지도 못하고 여기서 끝난다.
  3. 대역이 다르면 OS는 이 주소를 로컬에서 못 찾고, 라우팅 테이블의 기본 경로(default route)에 따라 패킷을 공유기(게이트웨이)로 보낸다. 공유기 역시 목적지가 자기 LAN 대역이 아니면 사설 IP라고 특별 취급하지 않고, 여느 패킷처럼 자기 기본 경로를 따라 ISP로 올려보낸다.
  4. 그러나 ISP의 백본 라우터에는 사설 대역으로 가는 경로 자체가 없다. 갈 곳을 못 찾은 패킷은 여기서 버려진다.

이렇게 공인망에 나타나서는 안 될 주소의 패킷을 bogon 혹은 martian packet이라 부르며, 많은 ISP는 백본까지 가기 전에 경계에서 이를 명시적으로 필터링한다.

Bogon filtering - Wikipedia

결국 우리 집(192.168.0.10)이라는 정보는 우리 집 네트워크 밖에서는 아무 의미가 없다. 오히려 세상 어디에나 같은 주소가 있으니, 누군지 모를 192.168.0.10에게 잘못 배송될 위험도 있다.

앞에서 살펴본 전제가 정확히 여기서 뒤집힌다. 사설 IP로 인해 같은 주소가 세상 곳곳에 존재하니 "주소는 고유한 라벨"이라는 성질이 깨졌고, 아래에서 보다 구체적으로 서술하겠지만 공인망 경계에서 주소를 바꿔치기하는 NAT(Network Address Translation)는 "패킷은 변형 없이 흐른다"는 성질마저 깨뜨린다. 주소 고갈을 버티려던 타협의 대가가 종단 간 투명성이었던 셈이다. RFC 2775의 진단도 같다.

This concept had two clear consequences - packets could flow essentially unaltered throughout the network, and their source and destination addresses could be used as unique labels for the end systems.

...

IPv4 addresses can no longer be assumed to be either globally unique or invariant, and any protocol or applications design that assumes these properties will fail unpredictably. ... We have to recognise that the Internet has lost end-to-end transparency


출처 : IETF Datatracker, "Internet Transparency, RFC 2775", https://datatracker.ietf.org/doc/html/rfc2775

때문에 외부(WAN)에서 목적지 LAN 대역으로 접근하는 방법은 크게 둘이다. 포트 포워딩으로 특정 포트를 인터넷에 직접 노출하거나 VPN으로 내 기기를 논리적으로 "우리 집 안"에 집어넣거나.

Cloudflare Tunnel처럼 내부에서 밖으로 연결을 열어두는 역방향 터널 계열도 있지만 지금 다루진 않겠다.

매번 얘기하지만 기상천외한 방법으로 해킹이 발생하는 요즘, 굳이 공격 표면을 늘릴 이유는 없다.

NAT에 대한 이해

마찬가지로 이전 글에서 잠깐 다루긴 했지만 빼놓기가 애매해서 좀 더 다뤄보도록 하겠다.

원격 접속의 대상이 되는 VPN 서버는 보통 우리 집 안에 있다. 그런데 앞서 사설 IP는 외부에서 못 찾는다고 했다. 그럼, 밖에 있는 내 노트북은 애초에 어떻게 우리 집 VPN 서버에 처음 말을 거는 걸까? 여기서 NAT(Network Address Translation)를 알아야 한다.

집에 인터넷 회선을 깔면 ISP는 보통 공인 IP를 딱 하나 준다. 그런데 집 안엔 노트북, 폰, 홈서버, TV까지 기기가 여럿이다. 이 여럿을 공인 IP 하나로 인터넷에 내보내는 일이 공유기가 하는 NAT다.

내부망에 위치한 기기(192.168.0.10)가 외부로 패킷을 보내면, 공유기가 출발지 주소를 자기 공인 IP로 바꿔치기하고 "이 포트는 192.168.0.10이 쓰는 중"이라고 매핑 테이블에 적어둔다. 응답이 공인 IP로 돌아오면 테이블을 보고 다시 192.168.0.10으로 돌려보낸다.

NAT 동작 원리 | 출처 : Pandora FMS, "NAT: what it is and how it works in our network", https://pandorafms.com/en/it-topics/what-is-nat/

정확히는 IP 주소만 바꾸는 단순 NAT에 더해, 포트 번호까지 함께 변환하여 트래픽을 구분하는 NAPT(Network Address Port Translation) 기술이다. 포트 번호가 16비트(65,536개)이므로 공인 IP 하나로도 수만 개의 동시 연결을 거뜬히 식별할 수 있다.

문제는 이 매핑(NAT, NAPT)이 "안에서 밖으로" 나갈 때만 생긴다는 점이다. 밖에서 안으로 먼저 들어오려는 패킷은 대응하는 매핑이 없다. 공유기는 "이걸 누구한테 줘야 하지?" 하다가 그냥 버린다. 그래서 외부에서 NAT 뒤에 숨은 내부 기기로 직접 연결하는 것은 원천 차단되어 있다.

그래서 가정에서 원격 접속 VPN을 굴리려면 보통 포트 포워딩(Port Forwarding)으로 이 문제를 해결한다. 공유기에서 특정 포트 하나(WireGuard의 51820/UDP 등)를 명시적으로 열어, "이 특정 포트로 들어오는 외부 패킷은 무조건 우리 집 VPN 서버로 보내라"고 고정된 길을 뚫어두는 것이다. 외부 클라이언트는 이 포트 하나로만 노크하고, 그 통로 안에서 안전한 암호화 터널을 맺는다.

다만 이 포트 포워딩에는 전제가 하나 있다. 집 쪽이 포트를 열어줄 공인 IP를 실제로 가지고 있어야 한다는 것이다. 여기서 방향이 중요하다. NAT 매핑은 "안에서 밖으로"만 열리므로, 먼저 말을 거는 쪽인 클라이언트(카페의 노트북, 모바일 등)는 NAT든 몇 겹의 NAT든 그 뒤에 있어도 아무 문제가 없다.

실제로 공인 IP가 없는 모바일에서 WireGuard가 문제없이 붙는 이유가 이것이다.

그런데 요즘은 집에 공인 IP가 아예 없는 경우도 있다고 한다. 필자는 아직 겪어보지 못했지만, 일부 통신사가 공인 IP를 아끼려고 여러 가입자를 한 번 더 NAT로 묶는 CGNAT(Carrier-Grade NAT)를 쓴다는 것이다. 이러면 외부에서 노크할 대문(우리 집 공인 IP) 자체가 없어 포트 포워딩이 성립하지 않는다.

다행히 한국인터넷정보센터(KRNIC)에서 공개하기를 2026년 6월 기준 우리나라가 확보한 IPv4 주소의 개수는 약 1억 1천만 개로 단순 수치상으로도 1인당 약 2.2개를 부여할 수 있는 수준이다. 때문에 한국 유선 인터넷은 대체로 가정마다 공인 IP를 부여하기에 CGNAT로 인해 문제를 겪는 경우가 흔치 않지만, 모바일 회선이나 일부 해외 ISP에서는 오히려 기본값에 가깝다고 한다. 이렇게 양쪽 다 막힌 경우를 푸는 게 후술할 Tailscale의 특기이기도 하다.

연도별 IPv4 보유 현황 | 출처 : 한국인터넷정보센터, "국내-보유현황(IPv4주소)", https://xn--3e0bx5euxnjje69i70af08bea817g.xn--3e0b707e/jsp/statboard/IPAS/inter/pos/currentV4Addr.jsp

VPN에 대한 이해

앞에서 사설 IP와 NAT라는 '문제'를 봤으니, 이제 '해법'인 VPN이 실제로 어떻게 동작하는지 볼 차례다.

그런데 "내 기기를 논리적으로 우리 집 안에 집어넣는다"는 건 구체적으로 무슨 뜻일까. 몸은 카페에 있는데 어떻게 우리 집 내부망의 일원처럼 통신한다는 걸까. 그 답이 터널(Tunnel)이고, 터널은 두 가지 동작으로 만들어진다.

  1. 원본 패킷을 통째로 감싸는 캡슐화(Encapsulation)
  2. 그리고 감싼 내용물을 잠그는 암호화(Encryption)

비유하자면 이렇다. 집과 회사는 멀리 떨어져 있고 둘 사이에 전용 도로(회선)를 깔 수는 없다. 때문에 모두가 함께 쓰는 공용 고속도로(인터넷)를 타야 한다. 문제는 이 위에선 내부가 다 들여다보인다는 거다. 그래서 창문을 까맣게 칠한 차량을 만들어 그 안에서만 오가게 한다. 이게 터널이다.

물론 군대처럼 보안이 중요하고 남는 게 사람인 곳은 방차나 UTP 박스를 들고 사설망을 직접 깔곤 한다.
예초병이 선을 끊어서 뭐가 안된다 하면 끊긴 데를 찾아서 결선하느니 그냥 새로 까는 식이었다.

캡슐화(Encapsulation)

캡슐화는 원래 보내려던 패킷을 통째로 새 패킷 안에 집어넣어 감싸는 것이다. 카페에서 홈서버로 보내는 패킷을 단순화하면 이렇다.

원본:        [ 목적지: 192.168.0.10 ] [ 데이터 ]

포장지에는 공인 인터넷에서 길을 찾을 수 있는 우리 집 공인 IP만 적혀 있다. 진짜 목적지(사설 IP)는 포장지 안쪽에 숨어 있다가, 우리 집 VPN 서버에 도착해서야 포장을 벗고 내부망으로 전달된다.

캡슐화 후:    [ 목적지: 우리 집 공인 IP ] { [ 목적지: 192.168.0.10 ] [ 데이터 ] }

참고로 "감싼다"는 동작 자체는 터널만의 것이 아니다. 패킷은 원래 계층적으로 포장돼 다니고(IP 패킷은 이더넷 프레임에 실려 이동한다), 라우터도 홉마다 프레임(L2) 껍데기를 벗기고 새로 씌운다. 다만 그때도 IP 헤더의 출발지·목적지는 끝까지 그대로다.

터널이 특별한 건 IP 패킷을 다시 IP 패킷 안에 넣어(L3-in-L3) 새 목적지가 적힌 새 IP 헤더를 만들어낸다는 점이다. 중간 라우터들은 겉 IP만 보고 여느 패킷처럼 나를 뿐, 안에 또 다른 IP 패킷이 들어 있는 줄은 모른다.

사설 IP 패킷을 공인 IP 패킷 형태로 감싼 모습 | 출처 : Generated by Claude

이때 내 기기에는 보통 가상 네트워크 인터페이스(wg0)가 하나 생긴다. 이 인터페이스가 VPN 전용 사설 IP를 부여받아 물리적으로 밖에 있으면서도 내부망의 일원처럼 행세할 수 있게 된다.

물론 봉투를 한 겹 더 쓰는 만큼 공짜는 아니다. WireGuard를 예로 들면 겉봉투인 IP 헤더(20바이트)와 UDP 헤더(8바이트), 그리고 WireGuard의 전송 헤더(16바이트)와 Poly1305 인증 태그(16바이트)를 합쳐 패킷마다 60바이트의 오버헤드가 발생한다. IPv6라면 겉 IP 헤더가 40바이트라 80바이트가 된다.

WireGuard VPN으로 인한 패킷 오버헤드 | 출처 : defguard, "MTU/MSS Decision Tree for WireGuard Deployments", https://defguard.net/blog/mtu-mss-decision-tree/#overview

그럼 이 봉투는 실제로 어떻게 공용망을 건너갈까. 앞서 말한 "중간 라우터는 겉 IP만 본다"는 원리는 우리 집 공유기에도 똑같이 적용된다. 공유기(NAT) 환경에서는 포트 포워딩으로 51820/UDP 포트 단 하나만 열어두게 되는데, 여기서 어떻게 이 단일 포트로 SSH나 웹 같은 다양한 실제 트래픽까지 모두 오가는지 의아할 수 있다. 답은 간단하다. 클라이언트와 VPN 서버 간에 오가는 모든 통신은, 연결 초기 핸드셰이크던 그 뒤의 실제 데이터든 관계없이 전부 이 하나의 UDP 봉투에 담겨 흐르기 때문이다.

진짜 목적지(사설 IP)와 데이터는 봉투 속에 암호화돼 숨어 있으니, 공유기는 안을 구분할 필요도 없이 "51820/UDP로 온 건 VPN 서버로"라는 규칙 하나로 전부 넘긴다. 봉투를 뜯어 진짜 목적지로 라우팅하는 일은 온전히 VPN 서버의 몫이다.

암호화(Encryption)

사실 인터넷의 기본 단위인 IP 패킷은 설계상 알맹이가 평문으로 노출된다. 중간 경로의 누군가가 패킷을 가로채면 내용이 그대로 읽힌다. 캡슐화만 해서는 "봉투를 뜯으면" 다 보이는 셈이다.

혹자는 "요즘 누가 HTTP로 평문 그대로 노출하나, 다 HTTPS를 쓰지"라고 의문을 제기할 수 있다. 타당한 말이지만, TLS가 감추는 건 애플리케이션 데이터뿐이다. 내가 어느 IP의 어느 포트에 접속하는지, 즉 IP 헤더는 그대로 보이고, TLS 핸드셰이크의 SNI 필드에는 접속하려는 도메인 이름까지 평문으로 실린다.

VPN은 원본 IP 패킷을 헤더째 통째로 암호화하므로 "누구와 통신하는가"라는 메타데이터까지 겉봉투 안에 숨긴다. 이 암호를 풀 수 있는 건 양 끝단(내 기기와 우리 집 VPN 서버)뿐이다. 이를 위해 연결 초기에 양쪽이 서로의 신원을 확인하고 암호 키를 주고받는 핸드셰이크(Handshake) 과정을 거친다.

정리하면 VPN은 "감싸고(캡슐화) 잠그는(암호화)" 두 동작으로 공용망 위에 사설 통로를 세우는 기술이다. 그 결과 나는 카페에 앉아서도 우리 집 거실에 있는 것처럼 홈서버에 접근할 수 있게 된다.

VPN의 구분

OSI 계층에 따른 구분

앞서 내용을 보면 한 가지 의문이 들 수 있다. "패킷을 감싼다고 했는데, 그 패킷은 도대체 어느 수준의 패킷인가?" 바로 이 지점에서 VPN이 OSI 계층 중 어느 층에서 동작하느냐로 갈린다. 크게 L2 VPN과 L3 VPN이다.

L2 VPN

L2 VPN(데이터링크 계층)은 이더넷 프레임 단위로 터널을 뚫는다. 비유하자면 멀리 떨어진 내 기기를 우리 집 공유기에 직접 랜선으로 꽂은 것처럼 만드는 것이다. 같은 브로드캐스트 도메인에 속하니, ARP나 mDNS 같은 브로드캐스트 기반 동작도 그대로 넘어온다. 같은 LAN에서만 보이던 기기 자동 검색(예: 프린터, 미디어 기기 탐색)이 외부에서도 된다는 뜻이다. 대신 브로드캐스트 트래픽까지 통째로 터널로 흘러 네트워크가 무겁고, 기기가 많아지면 확장성이 크게 떨어진다. VXLAN, OpenVPN의 TAP 모드 등이 여기에 속한다.

L3 VPN

L3 VPN(네트워크 계층)은 IP 패킷 단위로 터널을 뚫는다. 이쪽은 내 기기를 라우터 건너편에 둔 것에 가깝다. 오직 IP 패킷만 라우팅 되고, 브로드캐스트는 넘어오지 않는다. 그래서 가볍고 확장성이 좋다. 대신 같은 LAN에 꽂힌 듯한 효과는 없으니, 브로드캐스트 기반 기기 검색 같은 건 기대하기 어렵다. IPsec(터널 모드), WireGuard, OpenVPN의 TUN 모드가 여기에 속한다.

L2 VPN vs L3 VPN 모식도 | 출처 : Generated by Claude

앞서 VPN의 동작 원리를 설명할 때 "IP 패킷을 통째로 또 다른 IP 패킷으로 감싼다"고 했는데, 이게 바로 L3 방식이다. 그리고 필자가 사용한 WireGuard는 철저히 L3 VPN이다. 가상 인터페이스(wg0)를 만들어 IP 패킷만 라우팅하고, 이더넷 프레임이나 브로드캐스트는 다루지 않는다.

홈서버 원격 접속 같은 용도엔 L3로 충분하다. 어차피 SSH, 웹 대시보드, API 같은 건 전부 IP 위에서 도는 트래픽이니까 브로드캐스트가 불필요하다. 때문에 굳이 무거운 L2를 끌고 올 이유가 없다. WireGuard가 가볍고 빠른 이유 중 하나도 여기에 있다. 처음부터 L3에만 집중했기 때문이다.

터널 방식에 따른 구분

전통적으로 VPN 프로토콜은 IPsec, OpenVPN 같은 것들이 주류였다. 강력하긴 한데 무겁고 복잡하다. 설정 항목이 수십 개고 핸드셰이크 과정도 길다. 한 번 제대로 구성하려면 머리가 아프다.

그러다 등장한 게 이 글에서 지속적으로 언급한 WireGuard다. WireGuard의 철학은 한마디로 "단순함"으로, 아래와 같은 특징을 지닌다.

  • 코드가 매우 적다. 커널 구현 기준 약 4천 줄로, OpenVPN이 OpenSSL까지 합치면 수십만 줄인 것과 비교하면 사람이 전수 감사(audit)할 수 있는 규모다.
  • 이 단순함을 인정받아 2020년 리눅스 커널 5.6에 정식 편입됐다.
  • 공개키(Public Key) 기반으로, 양쪽이 서로의 공개키만 알면 된다.
  • UDP 기반으로 세션 키와 재생 방지 카운터 정도의 최소한의 상태만 내부에 유지할 뿐, 사용자에게 '연결'이라는 개념 자체를 노출하지 않아 빠르고 가볍다.
  • AllowedIPs라는 개념으로 "이 피어로는 이 대역만 보낸다"를 명시한다. 이를 암호키 라우팅(Cryptokey Routing)이라 한다.
  • 라우팅 테이블과 암호 키가 한 몸이라 "이 대역의 패킷은 이 공개키로만 암호화되고, 이 공개키로 복호화된 패킷은 이 대역일 때만 통과된다"는 양방향 검증까지 겸한다.

요즘 새로 나오는 VPN 솔루션 상당수가 내부적으로 WireGuard를 쓴다. 그만큼 사실상의 표준이 됐다.

다만 WireGuard 그 자체는 "데이터를 나르는 도구"일 뿐이다. 누가 어떤 키를 갖고 있고, 어떤 IP를 쓰고, 새 기기를 어떻게 추가하는지. 이런 "관리"는 전부 내가 손으로 해야 한다. 이게 WireGuard의 특징이자 한계다.

연결 방식에 따른 구분

연결 방식에 따른 구분은 크게 두 가지다.

  1. 허브 앤 스포크(Hub-and-Spoke)는 중앙 서버 하나에 모든 기기가 매달리는 방식이다. 모든 트래픽이 가운데 허브를 거쳐 간다. 전통적인 회사 VPN이 대부분 이 구조다. 단순하지만 허브가 죽으면 다 죽고, 기기끼리 통신해도 굳이 중앙을 한 번 찍고 가야 한다.
  2. 메시(Mesh)는 기기들이 서로 직접(P2P) 연결되는 방식이다. 거미줄처럼 얽힌다. 중앙을 거치지 않으니 빠르고, 한 노드가 죽어도 나머지는 멀쩡하다. 대신 "누가 누구랑 연결돼 있는지"를 관리하는 게 훨씬 복잡하다.
연결 방식에 따른 구조 모식도 | 출처 : Generated by Claude

순수 WireGuard로 메시를 짜는 건 가능은 하다. 그런데 기기가 N개면 연결 경우의 수가 확 늘고, 키도 일일이 다 나눠 줘야 한다. 손이 많이 간다.

바로 이 "메시 관리가 귀찮다"는 빈틈을 파고든 게 Tailscale이다.

Tailscale에 관해

사실 위 내용을 끝으로 VPN에 대한 이론적인 설명은 끝났다. 이제 서두에 던진 질문으로 돌아갈 차례다.

Tailscale을 한 줄로 정의하면 이렇다. "WireGuard라는 몸통 위에, 메시를 알아서 관리해 주는 두뇌(컨트롤플레인)를 얹은 것." 좀 더 풀면 Tailscale은 두 부분으로 나뉜다.

  1. 데이터 플레인(Dataplane) : 실제 암호화된 트래픽이 오가는 길로, 이건 그냥 WireGuard다. 기기끼리 직접 P2P로 흐른다.
  2. 컨트롤플레인(Controlplane) : "누가 이 네트워크에 속해 있고 각자의 공개키와 주소는 뭔지"를 관리하는 좌표 서버(coordination server)이다. 기기를 새로 붙이면 이 서버가 알아서 모두에게 알려준다.

그리고 이렇게 한데 묶인 네트워크 한 덩어리를 tailnet이라 부른다. 계정(또는 조직) 단위로 갈리며, 처음 로그인하는 순간 tailnet 하나가 만들어진다.

한 가지 짚어둘 건, 좌표 서버가 tailnet마다 하나씩 존재하는 게 아니라는 점이다. Tailscale의 좌표 서버는 controlplane.tailscale.com 하나뿐인 공용 서비스이고, 전 세계 모든 tailnet이 공유한다. tailnet은 그 위에서 계정 단위로 논리적으로 격리될 뿐이다.

여기에 더해 추가적인 편의 기능이 붙는다.

기기를 IP 대신 이름으로 부르게 해주는 MagicDNS, 접근 제어 규칙(ACL), 그리고 중계 서버 DERP(Designated Encrypted Relay for Packets)다.

Tailscale이 연결을 맺는 방법

DERP를 이해하려면 앞서 본 NAT 문제로 돌아가야 한다. 포트 포워딩이 되는 쪽(공인 IP를 가진 집)이 하나라도 있으면 순수 WireGuard로도 충분하다. 하지만 양쪽 다 NAT/CGNAT 뒤에 있으면 서로에게 '먼저 들어갈 대문'이 없어 직접 연결이 막힌다.

여기서 한 가지 짚고 갈 게 있다. 흔히 DERP를 "직접 연결이 실패했을 때의 대비책"으로만 알고 있지만, 공식 문서의 설명은 좀 다르다.

All connections start as relayed through a DERP server, and Tailscale then tries to upgrade them to a direct connection.


출처 : tailscale, "Connection types", https://tailscale.com/docs/reference/connection-types

즉 모든 연결은 예외 없이 DERP를 거쳐 시작한 뒤 직접 연결로 '승격(upgrade)'된다. 생각해 보면 당연하다. 홀펀칭을 하려면 양쪽이 서로의 공인 엔드포인트를 주고받아야 하는데, 그러려면 그 정보를 교환할 통로가 먼저 있어야 하기 때문이다. DERP는 중계 서버인 동시에 홀펀칭을 조율하는 채널인 셈이다.

실제 공식 홈페이지에 명시된 시나리오는 이렇다.

Tailscale 연결 시나리오 | 출처 : tailscale, "How Tailscale establishes connections", https://tailscale.com/docs/reference/connection-types#how-tailscale-establishes-connections

이를 간단히 도식화하면 아래와 같다.

Tailscale 연결 시나리오 도식화 | 출처 : Generated by Claude

순수 WireGuard였다면 STUN을 통한 주소 확인, 홀펀칭 시도, 중계 서버 구축은 물론이고 키 교환과 피어 등록까지 전부 사용자가 수동으로 해야 했을 일이다. Tailscale은 이 모든 복잡한 과정을 백그라운드에서 알아서 처리해 준다.

그럼 DERP를 거치는 내 트래픽을 Tailscale이 다 들여다보는 걸까? 다행히 아니다. DERP는 봉투를 '전달'만 하지 '열지'는 못한다. 중계되는 건 양 끝단의 키로 암호화된 WireGuard 패킷이고, 그 키는 각 기기를 벗어난 적이 없어 DERP 서버로서는 복호화할 방법 자체가 없다. 다만 "어떤 공개키가 어떤 공개키에, 얼마나" 같은 메타데이터는 지나는 길목이니 볼 수 있다. 대부분은 곧바로 직접 연결로 승격되므로, 이러한 메타데이터조차 제한적으로 남게 된다.

오히려 더 많이 아는 쪽은 좌표 서버다. "누가 이 tailnet의 멤버이고 각자의 키·주소·ACL이 뭔지"라는 네트워크 지도를 쥐고 있으니까. 물론 이것도 메타데이터일 뿐 데이터 내용은 아니다.

그런데 이런 의문이 들 수 있다. 전 세계 수많은 Tailscale 사용자에게 나눠준 주소가 서로 겹치지는 않을까? Tailscale은 기기마다 100.x.y.z 형태의 주소를 부여하는데, 결론부터 말하면 한 tailnet 안에서는 절대 겹치지 않고, 다른 tailnet과는 겹칠 수 있지만 대개 무해하다.

Tailscale이 부여하는 100.64.0.0/10은 아무 대역이나 고른 게 아니다. 앞서 CGNAT를 이야기할 때 나온, 통신사가 가입자를 한 번 더 NAT로 묶을 때 쓰라고 RFC 6598이 따로 떼어둔 공유 주소 공간(Shared Address Space)이다.

This document requests the allocation of an IPv4 /10 address block to be used as Shared Address Space to accommodate the needs of Carrier-Grade NAT (CGN) devices.

...

IANA has recorded the allocation of an IPv4 /10 for use as Shared Address Space.

The Shared Address Space address range is 100.64.0.0/10.


출처 : IETF Datatracker, "IANA-Reserved IPv4 Prefix for Shared Address Space, RFC 6598", https://datatracker.ietf.org/doc/html/rfc6598

Tailscale이 굳이 여기를 고른 이유는 명확하다. 192.168.x.y10.x.y.z 같은 사설 IP 대역을 썼다간 사용자의 기존 홈 네트워크나 사내망과 정면으로 충돌할 수 있지만, 100.64.0.0/10은 공인망에도 나타나지 않고 일반 사용자가 직접 쓸 일도 거의 없는 틈새이기 때문이다.

뒤집어 말하면, 진짜로 ISP가 CGNAT 형태로 운영하는 회선에서는 겹칠 수도 있다. Tailscale 측도 이를 인지하고 있는데, 해당 증상이 발생하면 IPv4 말고 IPv6를 쓰라고 안내한다.

한 tailnet 안에서 주소를 나눠주는 주체는 좌표 서버다. 전체 명단을 쥔 쪽이 배정하니 같은 tailnet 안에서 중복이 날 수 없다. 반면 서로 다른 tailnet끼리는 같은 주소를 거리낌없이 재사용한다. 애초에 이 대역은 약 419만 개(2²²)뿐이라 전 세계 기기를 감당할 수도 없다. 그래도 괜찮은 건 tailnet이 서로 격리된 별개의 네트워크라, 내 기기는 오직 내 tailnet 안으로만 라우팅하기 때문이다.

바로 이 "다른 tailnet끼리는 주소가 겹칠 수 있다"는 성질이, 다음에 이야기할 제약의 원인이 된다.

tailnet의 한계

여기서 결정적인 제약이 나온다. 한 기기는 동시에 하나의 tailnet에만 접속할 수 있다.

이유는 바로 앞에서 본 그대로다. 모든 tailnet이 똑같이 100.64.0.0/10에서 주소를 발급하니, 두 tailnet에 동시에 붙으면 같은 100.x.y.z 주소가 양쪽에 존재할 수 있어 어느 쪽으로 보내야 할지 결정할 수 없다. 대역 재사용이라는 편의가 곧 동시 접속의 발목을 잡는 셈이다.

Tailscale은 이를 빠른 사용자 전환(fast user switching)으로 우회한다. 여러 계정을 미리 로그인해 두고 재인증 없이 갈아탈 수 있게 해주는 기능인데, 공식 문서도 이건 어디까지나 '전환'이지 동시 접속이 아니라고 못 박는다. "한 tailnet에서는 패킷을 버리고 다른 tailnet에서는 허용하는 것과 같다"는 표현을 쓴다.

A device is not able to transmit packets on multiple tailnets simultaneously. When using fast user switching between tailnets, one tailnet doesn't have knowledge of the other tailnet's existence, nor whether the client device is also in another tailnet.


출처 : tailscale, "Fast user switching", https://tailscale.com/docs/features/client/fast-user-switching

서두에 던진 질문의 답이 정확히 여기 있다. 회사 VPN이 Tailscale이라 노트북과 폰은 이미 회사 tailnet에 물려 있다. 그런데 홈서버를 회사 tailnet에 넣는 건 가능 여부는 차치하고서라도 내 인프라를 회사 관리망에 노출하는 셈이라 꺼려지고, 개인 tailnet을 따로 파자니 "한 기기 한 tailnet" 제약 때문에 회사 것과 동시에 쓸 수 없다.

그래서 홈서버는 Tailscale과 완전히 독립된 WireGuard 터널로 붙였다. WireGuard는 tailnet 슬롯과 무관하니 회사 Tailscale과 나란히 켜둘 수 있고, 앞서 본 AllowedIPs로 "우리 집 대역만 이 터널로" 좁혀두면 회사 트래픽과 목적지가 겹치지도 않는다.

단 여기엔 조건이 하나 붙는다. AllowedIPs를 0.0.0.0/0 으로 잡아 풀-터널링을 하는 순간 100.64.0.0/10까지 이 터널이 삼켜버려 회사 Tailscale이 죽을 수 있다. 두 VPN을 나란히 쓰려면 필요한 대역만 좁혀 잡아야 한다.


결론

VPN은 사설 IP와 NAT로 인해 단절된 통신 환경에서, 암호화된 통로를 뚫어 외부에 있는 내 기기를 논리적으로 내부망 안에 위치시키는 기술이다. 특히 홈서버를 운영하는 환경에서는 서비스마다 포트를 하나씩 열어 공격 표면을 늘리기보다는, 포트 하나만 열어두고 L3 계층에서 가볍고 빠르게 동작하는 WireGuard로 그 안을 통과시키는 편이 낫다.

더 나아가 설정과 키 관리가 번거롭다면 Tailscale과 같은 메시형 구조로 복잡성을 줄일 수도 있다. 다만 이미 다른 tailnet에 소속된 기기가 있다면, 앞서 본 "한 기기 한 tailnet" 제약을 먼저 확인해야 한다. 필자처럼 회사 tailnet에 발이 묶여 있다면 오히려 순수 WireGuard가 유일한 답이 되기도 한다.


참고자료

Virtual private network - Wikipedia
Forward secrecy - Wikipedia
Bogon filtering - Wikipedia
RFC 2775: Internet Transparency
This document describes the current state of the Internet from the architectural viewpoint, concentrating on issues of end-to-end connectivity and transparency.
RFC 1918: Address Allocation for Private Internets
This document describes address allocation for private internets. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.
CGNAT(Carrier-Grade NAT) IP 구성
이 문서에서는 ISP가 하나의 공용 IP를 공유하여 IPv4를 확장하는 데 사용하는 메서드인 CGNAT(Carrier-Grade NAT)의 상위 레벨 개요에 대해 설명합니다.
Cisco Annual Internet Report - Cisco Annual Internet Report (2018–2023) White Paper
The Cisco Annual Internet Report is a global forecast/analysis that assesses digital transformation across various business segments (enterprise, small-to-medium business, public sector, and service provider). The report covers fixed broadband, Wi-Fi, and mobile (3G, 4G, 5G) networking. Quantitative projections are provided on the growth of Internet users, devices and connections as well as network performance and new application requirements.
MTU/MSS Decision Tree for WireGuard Deployments
Complete troubleshooting guide for MTU and MSS issues in WireGuard VPN deployments, including decision trees, discovery procedures, and configuration examples.
Linux_5.6 - Linux Kernel Newbies
List of changes and new features merged in the Linux kernel during the 5.6 development cycle
wireguard « net « drivers - wireguard-linux - WireGuard for the Linux kernel
What Is Cryptokey Routing in Wireguard?
Cryptokey routing associates public keys with a list of tunnel IP addresses allowed inside the tunnel. Learn why this sets WireGuard apart.
LAN 쉽게 이해하기
사람들은 자신이 사는 곳과 그 주변 일대를 친근하게 ‘동네’라고 부릅니다. 보통 집을 중심으로 걸어가기 쉬운 지근거리를 일컫는 말이기도 하지요. 저는 야탑동에 살고 있는데요. 누군가 제게 사는 동네가 어디냐고 묻는다면 전 ”야탑동에 삽니다.”라고 말합니다. 동네(洞네) [동ː네] [명사] 사람들이 생활하는 여러 집이 모여 있는 곳. - 출처 : 네이버 어학사전 - 다른 분들께 사는 동네가 어디냐고 물어보면 저처럼 야탑에 산다고 하시는 분들도 있겠지만 어떤 분은 ”야탑 1동에 삽니다.”라고 말을 하고, 어떤 분은 ”야탑역 인근에서 삽니다.”라고 말씀하시죠. 이처럼 동네에 대한 정의는 개인에 따라 다릅니다만 한 가지 공통점이 있습니다. 그것은 바로 자신의 집을 중심으로 가깝다고 판단하는 지근거리라는 것입니다…
ARP 쉽게 이해하기
주소 결정 프로토콜(Address Resolution Protocol, ARP)은 네트워크 상에서 IP 주소를 물리적 네트워크 주소로 대응(bind)시키기 위해 사용되는 프로토콜이다. 여기서 물리적 네트워크 주소는 이더넷 또는 토큰링의 48 비트 네트워크 카드(NIC) 주소를 뜻한다. - 출처 : 위키백과 -ARP는 Address Resolution Protocol의 약자로 IP 주소를 MAC 주소와 매칭시키기 위한 프로토콜입니다. ARP를 사용하는 이유는 로컬 네트워크(LAN, Local Area Network)에서 단말과 단말 간 통신을 하기 위해서는 IP 주소와 함께 MAC 주소를 이용하게 되는데, IP 주소를 MAC Address와 매칭하여 목적지 IP의 단말이 소유한 MAC 주소를 향해 제대로…
♥오리뎅이의 네트워크 사랑방♥ : 네이버 블로그
Connection types · Tailscale Docs
Understand how Tailscale connects devices using either direct or relayed connections.
Device connectivity · Tailscale Docs
Understand connectivity between Tailscale devices.
DERP servers · Tailscale Docs
Tailscale uses Designated Encrypted Relay for Packets (DERP) servers for secure, low-latency connections in your tailnet. Customization options let you optimize device communication and NAT traversal.
How NAT traversal works
Learn how NAT traversal works, how Tailscale can get through and securely connect your devices directly to each other.
Fast user switching · Tailscale Docs
Quickly switch between two or more logged in accounts on the same device, without requiring re-authentication.
RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space
This document requests the allocation of an IPv4 /10 address block to be used as Shared Address Space to accommodate the needs of Carrier- Grade NAT (CGN) devices. It is anticipated that Service Providers will use this Shared Address Space to number the interfaces that connect CGN devices to Customer Premises Equipment (CPE). Shared Address Space is distinct from RFC 1918 private address space because it is intended for use on Service Provider networks. However, it may be used in a manner similar to RFC 1918 private address space on routing equipment that is able to do address translation across router interfaces when the addresses are identical on two different interfaces. Details are provided in the text of this document. This document details the allocation of an additional special-use IPv4 address block and updates RFC 5735. This memo documents an Internet Best Current Practice.
TCP hole punching - Wikipedia