SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-28

Headscale 설치 및 Tailscale 자체 호스팅 방법

Tailscale 제어 서버를 VPS에 직접 구축하는 방법을 안내합니다. 공식 .deb 패키지 설치부터 server_url 설정 및 첫 노드 연결까지의 과정을 상세히 설명하며, 자체 호스팅 시 고려해야 할 네트워크 구성 및 보안 주의사항을 정리했습니다.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Headscale이란 무엇인가

Headscale은 Tailscale 제어 서버를 직접 호스팅하는 구현체이며, 사설 네트워크를 조정하는 기기는 사용자가 소유한 VPS가 됩니다. 이는 커뮤니티 프로젝트이며 Tailscale Inc.에서 운영하지 않습니다. 모든 기기는 여전히 공식 tailscale 클라이언트를 실행하며, --login-server 플래그를 사용하여 사용자의 서버를 가리키도록 설정합니다.

제어 서버는 네트워크에 누가 속해 있는지 파악하는 역할을 합니다. 각 노드에 100.64.0.0/10 대역의 주소를 할당하고, 공개 키를 배포하며, 노드들이 서로를 찾을 수 있도록 안내합니다. 터널은 노드 간에 직접 구축되는 WireGuard 방식을 유지합니다. 두 기기 간의 트래픽은 직접적인 경로를 구축할 수 없어 릴레이를 거쳐야 하는 상황이 아니라면 Headscale 서버를 통과하지 않습니다. 조정 역할을 직접 수행하는 것은 해당 권한을 누가 가지느냐를 바꿀 뿐 기능 자체를 바꾸는 것은 아니므로, 이 전환을 그 자체로 보안상의 이득으로 간주하기 전에 이 모델에서 제어 서버가 접근할 수 있는 범위와 없는 범위를 이해하는 것이 중요합니다.

Headscale은 인스턴스당 하나의 tailnet(Tailscale 네트워크)을 제공하며, 프로젝트 측에서는 이를 개인용이나 소규모 조직에 적합하다고 설명합니다. 기기가 3~4대 정도라면 사용자가 소유한 VPS에서 일반 WireGuard VPN을 운영하는 것이 관리할 소프트웨어가 적고 장애 지점도 줄어듭니다. Headscale은 새로운 노트북을 추가할 때마다 [Peer] 블록을 수동으로 작성하고 싶지 않을 때 유용합니다. 많은 사용자가 비용 문제로 대안을 찾기 시작하므로, 서버를 직접 운영하기 전에 호스팅된 무료 플랜이 실제로 무엇을 포함하는지 확인하는 것이 좋습니다. 개인용 기기 몇 대는 보통 무료 플랜 범위 내에 포함되기 때문입니다. 이미 그 한계를 넘어섰다면 기기당 과금이 아닌 사용자당 과금인 유료 플랜 비용과 비교해 보십시오. 하나의 계정을 사용하는 가구는 기기 대수가 늘어나도 저렴하게 유지될 수 있습니다. Tailscale의 대체재보다는 자체 클라이언트와 피어 관리를 위한 웹 인터페이스를 선호하면서 직접 호스팅하는 제어 평면을 원한다면, 단일 VPS에서의 NetBird가 고려해 볼 만한 대안입니다. 두 모델에 대한 더 넓은 비교는 WireGuard와 Tailscale의 차이점을 참조하십시오.

설치 전 준비 사항

  • 공인 IPv4 주소와 sudo 권한을 가진 Ubuntu 24.04 기반의 VPS가 필요합니다. 서버를 새로 구축했다면 먼저 새 VPS 설정의 첫 10분 과정을 진행하십시오.
  • 해당 주소를 가리키는 DNS A 레코드가 필요합니다. 이 가이드는 headscale.example.com를 사용합니다.
  • MagicDNS를 위한 두 번째 도메인 또는 서브도메인이 필요합니다. 이 가이드는 tailnet.example.net를 사용합니다. 이 도메인은 server_url에 사용된 도메인과 달라야 합니다.
  • Linux, macOS, Windows, Android 또는 iOS를 실행 중인 클라이언트 기기 한 대가 필요합니다.

공식 .deb 파일로 headscale 설치하기

이 프로젝트는 GitHub 릴리스 페이지를 통해 .deb 패키지를 배포합니다. 2026년 7월 기준 최신 릴리스는 0.29.3입니다. 파일명에 아키텍처 정보가 포함되어 있으므로 먼저 본인의 아키텍처를 확인하십시오.

sudo apt update
sudo apt install -y wget
dpkg --print-architecture

일반적인 x86 VPS에서는 amd64이 출력되고, Ampere나 Graviton 계열 플랜에서는 arm64가 출력됩니다. 해당 값을 아래 변수에 입력하십시오.

HEADSCALE_VERSION="0.29.3"
HEADSCALE_ARCH="amd64"
wget --output-document=headscale.deb \\
  "https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
sudo apt install -y ./headscale.deb
headscale version

파일명 앞의 ./는 필수입니다. 이를 생략하면 apt은 저장소에서 headscale.deb이라는 패키지를 찾으려 시도하며, 결과적으로 실패하게 됩니다.

이 패키지는 headscale 시스템 사용자를 생성하고, 기본 /etc/headscale/config.yaml를 작성하며, systemd 유닛을 설치합니다. 서비스는 자동으로 시작되지 않으며, 이는 올바른 절차입니다. 기본 제공 설정은 server_urlhttp://127.0.0.1:8080로 가리키고 있는데, 이는 클라이언트가 접근할 수 없는 주소이므로 지금 서비스를 시작하더라도 정상적으로 동작하지 않습니다. 이 시점에서 sudo systemctl is-active headscale를 실행하면 inactive이 출력됩니다. 이는 오류가 아니라 예상된 결과입니다.

서비스를 시작하기 전에 server_url 설정하기

/etc/headscale/config.yamlsudo nano /etc/headscale/config.yaml로 편집하거나, sed을 사용하여 동일한 세 가지 변경 사항을 적용하십시오. 파일이 길고 주석이 상세하게 달려 있어 나머지 설정에 대한 가장 좋은 참고 자료가 되므로, 원본을 복사해 두십시오.

sudo cp /etc/headscale/config.yaml /etc/headscale/config.yaml.orig
sudo sed -i 's|^server_url:.*|server_url: https://headscale.example.com|' /etc/headscale/config.yaml
sudo sed -i 's|^listen_addr:.*|listen_addr: 127.0.0.1:8080|' /etc/headscale/config.yaml
sudo sed -i 's|^  base_domain:.*|  base_domain: tailnet.example.net|' /etc/headscale/config.yaml
sudo grep -E '^(server_url|listen_addr):|^  base_domain:' /etc/headscale/config.yaml

server_url은 headscale이 모든 클라이언트 등록 시 기록하는 주소의 머리말입니다. 클라이언트는 이후로 해당 문자열로만 접속을 시도하므로, 127.0.0.1가 아닌 https://이 앞에 붙은 공용 도메인 이름이어야 합니다.

listen_addr은 프로세스가 바인딩되는 위치입니다. 루프백으로 두십시오. 동일한 서버의 리버스 프록시가 TLS(transport layer security)를 종료하고 해당 포트로 전달하므로, 서버 외부에서 8080 포트에 직접 접근할 필요는 없습니다.

base_domain은 MagicDNS 접미사로, 노드에 이름이 부여되는 도메인입니다. 끝에 점이 없는 정규화된 도메인 이름(FQDN)이어야 하며, server_url에 설정된 도메인과는 달라야 합니다. 그렇지 않으면 두 이름 공간이 충돌하게 됩니다.

데이터베이스 섹션은 그대로 두십시오. 기본값은 /var/lib/headscale/db.sqlite에 위치한 SQLite이며, 패키지가 생성하고 소유하는 디렉터리에 있습니다. 현재 규모의 tailnet에는 SQLite로 충분합니다.

headscale을 시작하고 실행 상태 확인하기

sudo systemctl enable --now headscale
sudo systemctl is-active headscale
curl -sS -o /dev/null -w '%{http_code}\\n' http://127.0.0.1:8080/health

is-activeactive를 출력하고, curl200을 출력합니다. enable --now은 두 작업을 모두 수행합니다. 즉, 서비스를 시작하고 재부팅 후에도 자동으로 시작되도록 설정합니다.

is-activefailed을 출력한다면, sudo journalctl -u headscale -n 50 --no-pager을 사용하여 저널을 확인하십시오. 이 단계에서의 실패는 거의 항상 설정 파일 문제입니다. headscale은 소켓을 열기 전에 설정 파일 전체를 구문 분석하므로, 들여쓰기가 잘못되었거나 알 수 없는 키가 있으면 프로세스가 시작되기 전에 중단됩니다. 파일을 수정한 후 sudo systemctl restart headscale를 실행하십시오. 이후의 모든 설정 변경 시에도 동일한 재시작 과정이 필요합니다. 클라이언트는 이후 자동으로 다시 연결됩니다. systemd 유닛이 생소하다면 systemd를 이용한 서비스 및 타이머 직접 운영하기에서 여기에 사용된 명령어들을 다루고 있으니 참고하십시오.

셸에 접속한 상태에서 상태 파일들을 확인하십시오.

stat -c '%U %n' /var/lib/headscale/db.sqlite /var/lib/headscale/noise_private.key

두 줄 모두 패키지가 생성한 권한 없는 사용자 headscale으로 시작합니다. noise_private.key는 클라이언트에 대한 서버의 식별자입니다. 이 파일을 보관하십시오. 만약 삭제하면 headscale이 새로운 식별자를 생성하게 되며, 모든 노드를 다시 등록해야 합니다.

headscale 앞에 TLS 배치하기

클라이언트는 HTTPS를 통해 server_url에 도달해야 합니다. Caddy는 인증서를 스스로 요청하고 갱신하므로 가장 빠른 경로입니다.

sudo apt install -y caddy

/etc/caddy/Caddyfile을 headscale 문서의 블록으로 교체하십시오:

headscale.example.com {
    reverse_proxy 127.0.0.1:8080 {
        header_up True-Client-IP {remote_host}
        header_up X-Real-IP {remote_host}
    }
}
sudo caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile
sudo systemctl restart caddy
sudo systemctl is-active caddy

validate은 파일이 구문 분석될 때 adapted config to JSON을 출력합니다. 파일 형식이 지정되지 않았다는 경고는 외관상의 문제입니다. 노트북에서 curl -sS -o /dev/null -w '%{http_code}\\n' https://headscale.example.com/health를 실행해도 200이 출력되어야 합니다. 이 단일 확인으로 DNS, 방화벽, 인증서 및 프록시가 모두 정상적으로 작동함을 입증할 수 있습니다.

다음은 많은 사용자가 시간을 허비하게 만드는 프록시 세부 설정입니다. Tailscale 제어 연결은 HTTP 업그레이드이며, GET이 아닌 POST로 시작되고 Upgrade 헤더의 값은 tailscale-control-protocol입니다. Caddy는 별도의 설정 없이 이를 통과시킵니다. nginx는 그렇지 않으므로 nginx 프런트엔드에는 업그레이드 맵이 필요합니다:

map $http_upgrade $connection_upgrade {
    default keep-alive;
    ''      close;
}

server {
    listen 443 ssl;
    server_name headscale.example.com;
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_buffering off;
        proxy_pass http://127.0.0.1:8080;
    }
}

이 줄들을 생략하면 일반적인 요청은 여전히 성공하므로 /health이 200을 반환하고 모든 것이 정상으로 보입니다. 하지만 장기 유지되는 제어 연결이 형성되지 않아 노드가 등록된 후 오프라인 상태로 남게 됩니다. nginx 방식을 선택한다면 Ubuntu 24.04의 nginx에서 Certbot 사용하기에서 인증서 관련 내용을 확인할 수 있습니다.

UFW에서 개방해야 할 포트

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

포트 443은 모든 클라이언트 통신을 처리합니다. 포트 80은 오직 ACME(automatic certificate management environment) HTTP 챌린지와 HTTPS 리다이렉트를 위해서만 존재하며, Caddy가 인증서를 발급받으려면 반드시 필요합니다.

포트 8080은 닫아 두어야 합니다. listen_addr127.0.0.1:8080이므로, 프록시는 루프백 인터페이스를 통해 headscale에 접근하며 방화벽 규칙이 관여하지 않습니다. 8080 포트를 인터넷에 개방하면 클라이언트에게 평문 제어 채널이 노출될 뿐 아무런 이득이 없습니다. 대부분의 제공업체는 UFW와 별도로 제어판에서 두 번째 방화벽을 운영하므로, 서버 내부에서 포트가 열려 있어도 네트워크 경계에서는 닫혀 있을 수 있다는 점을 유념하십시오. VPS에서의 UFW 방화벽 기초에서 규칙 구문을 더 자세히 다룹니다.

사용자 생성 및 사전 인증 키 생성

sudo headscale users create alice
sudo headscale users list

headscale 명령어는 클라이언트 역할을 합니다. 이 명령어는 /var/run/headscale/headscale.sock에 위치한 유닉스 소켓을 통해 실행 중인 데몬과 통신하며, 해당 소켓은 0770 모드로 설정되어 있고 headscale 그룹이 소유합니다. 이로 인해 두 가지 결과가 발생합니다. 서비스가 중지된 상태에서는 명령어가 실패하는데, 이것이 본 가이드의 순서가 중요한 또 다른 이유입니다. 또한, 본인의 계정을 headscale 그룹에 추가하지 않았다면 sudo 권한이 필요합니다.

users list은 각 이름 옆에 ID를 출력합니다. 키 명령어는 이름이 아닌 숫자 형태의 사용자 ID를 인자로 받으므로 이 숫자가 필요합니다.

sudo headscale preauthkeys create --user 1 --expiration 24h

키는 한 번만 출력됩니다. 지금 복사하십시오. 사전 인증 키는 별도의 설정이 없다면 1회용이며 1시간 동안 유효하므로, 테스트 중이라면 --expiration 24h를 설정하는 것이 좋습니다. 여러 대의 장비를 등록할 키라면 --reusable을 추가하십시오. 이 키를 가진 사람은 누구나 네트워크에 참여할 수 있으므로 비밀번호처럼 취급해야 합니다.

--login-server를 사용하여 첫 번째 클라이언트 연결하기

연결하려는 머신에서 다음을 실행합니다:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --login-server https://headscale.example.com --auth-key 'hskey-auth-PASTE-YOUR-KEY-HERE'
tailscale status
tailscale ip -4

tailscale ip -4는 headscale이 할당한 주소를 출력하며, 100.64.0.1와 같은 형태입니다. 서버로 돌아와 sudo headscale nodes list을 실행하면 해당 노드의 ID, 사용자, 온라인 상태를 확인할 수 있습니다.

--login-server의 값은 스킴을 포함하고 끝에 슬래시가 없는 상태로 server_url과 정확히 일치해야 합니다. 이 값들은 문자열로 비교되므로, 불일치할 경우 클라이언트가 한 주소로 등록을 시도한 뒤 다른 주소로 통신하라는 지시를 받게 되어 문제가 발생합니다.

이전에 Tailscale의 호스팅 서비스를 사용하던 머신은 해당 로그인 정보를 유지합니다. 먼저 sudo tailscale logout를 실행하여 로그아웃한 뒤, --login-server 옵션을 사용하여 tailscale up을 실행하십시오.

--auth-key를 생략하면 클라이언트는 URL을 출력합니다. 해당 URL을 열면 등록 시도에 대한 식별자가 표시되며, 서버에서 이를 승인하면 됩니다:

sudo headscale auth register --user alice --auth-id PASTE-THE-ID-FROM-THE-PAGE

이 방식은 개인용 노트북에 적합합니다. 스크립트를 사용하는 경우에는 사람이 직접 확인할 필요가 없는 사전 인증 키(preauth keys)가 더 효율적입니다. VPS 자체가 노드가 되면 다른 머신의 인터넷 트래픽을 전달하는 exit node 설정도 가능합니다. 단, 호스팅 관리 콘솔 대신 서버에서 headscale 명령을 사용하여 광고된 경로를 승인해야 한다는 점이 다릅니다. 인터넷으로 나가는 경로가 아니라 VPS 뒤에 있는 사설 네트워크에 접근하려는 경우, 동일한 승인 단계를 통해 해당 서브넷을 tailnet 전체에 광고할 수 있습니다. 노드를 통해 전체 네트워크를 라우팅하는 대신 특정 애플리케이션 하나만 게시하는 것은 별개의 작업이며, serve와 funnel을 사용하여 수행할 수 있습니다. 다만 이 두 기능은 Tailscale 자체의 인증서 및 인그레스 메커니즘에 의존하므로, headscale이 직접 제공하는 기능이라기보다 호스팅된 tailnet의 기능으로 이해해야 합니다.

DERP와 직접 경로 실패 시 트래픽을 중계하는 방식

DERP(designated encrypted relay for packets)는 대체 경로입니다. 두 노드가 직접 WireGuard 연결을 맺을 수 없을 때, 보통 양쪽 모두 엄격한 NAT(network address translation) 뒤에 위치한 경우, 대신 릴레이를 통해 패킷을 전송합니다. 릴레이는 키를 보유하지 않으므로 트래픽을 읽을 수 없습니다. 다만 어떤 노드끼리 통신하는지, 데이터가 얼마나 이동하는지는 확인할 수 있습니다.

기본 설정이 어떻게 동작하는지 명확히 이해해야 합니다. Headscale은 기본적으로 https://controlplane.tailscale.com/derpmap/default를 가리키며 auto_update_enabled: trueupdate_frequency: 3h을 사용하도록 설정되어 있습니다. 따라서 제어 평면은 사용자가 직접 관리하지만, 릴레이는 Tailscale의 것을 사용하게 됩니다. 대부분의 사용자에게는 합리적인 타협점입니다. 만약 그렇지 않다면 직접 릴레이를 운영하십시오.

직접 릴레이를 운영하려면 config.yaml 내의 derp.server 아래에 enabled: true을 설정하고, headscale을 재시작한 뒤 sudo ufw allow 3478/udp을 사용하여 STUN(session traversal utilities for NAT) 포트를 개방하십시오. 설정 파일에는 요구 사항이 명시되어 있습니다. DERP는 TLS를 필요로 하므로 server_url은 반드시 https를 사용해야 합니다. derp.urls 목록을 비우면 Tailscale의 릴레이가 맵에서 제거됩니다. 만약 작동하는 내장 릴레이 없이 이 작업을 수행하면, 직접 연결할 수 없는 노드 쌍은 아예 통신이 불가능해집니다.

클라이언트에서 tailscale netcheck를 실행하면 알고 있는 각 relay 리전에 대한 지연 시간이 출력되고, tailscale status은 각 피어를 주소가 있는 direct 또는 리전 코드가 있는 relay 중 하나로 표시한다. relay 상태에서 멈춘 피어는 headscale 문제가 아니라 NAT 문제다. direct 상태인데도 여전히 느린 피어는 별개의 문제이며, 이 경우 일반적인 원인은 터널 자체보다 MTU다.

노드가 오프라인으로 표시되는 이유는 무엇입니까?

프록시가 업그레이드 요청을 차단하고 있습니다. 이는 가장 흔한 원인이며, 다른 모든 상태는 정상으로 보인다는 특징이 있습니다. /health은 200 응답을 반환하고, headscale nodes list는 노드를 보여주지만, 노드가 온라인 상태로 전환되지 않습니다. 제어 연결은 Upgrade: tailscale-control-protocol을 포함하는 POST 요청인데, 이를 전달하지 않는 프록시는 노드 상태를 보고하는 유일한 채널을 끊어버립니다. nginx 설정을 위의 map 블록과 비교하거나, 프록시 문제를 배제하기 위해 Caddy로 전환해 보십시오.

노드 등록 후 server_url이 변경되었습니다. 노드는 등록 시점에 부여받은 값을 계속 사용합니다. 해당 값을 수정했다면 각 노드에서 sudo tailscale up --login-server https://headscale.example.com --force-reauth를 실행하십시오.

클라이언트가 실행 중이지 않습니다. 노드에서 sudo systemctl is-active tailscaledsudo journalctl -u tailscaled -n 50 --no-pager를 확인하십시오. 도메인을 해석할 수 없거나 도달할 수 없는 클라이언트는 해당 위치에 재시도 로그를 남깁니다.

키가 만료되었습니다. 다음 섹션에서 다룹니다.

테스트하는 동안 서버 측을 모니터링하려면 VPS에서 sudo journalctl -u headscale -f를 실행하고 클라이언트에서 tailscaled을 재시작하십시오. headscale에 도달한 노드는 즉시 로그 라인을 생성합니다. 아무런 반응이 없다면 요청이 도착하지 않는 것이므로, headscale을 확인하기 전에 DNS, 방화벽, 프록시를 먼저 점검하십시오.

키 만료와 몇 주 뒤 작동이 중단되는 노드

두 가지 별도의 만료 기한이 존재하며, 이를 혼동하면 시간을 낭비하게 됩니다.

사전 인증 키(Preauth keys)는 설계상 빠르게 만료됩니다. 기본값은 1시간, 1회 사용입니다. 만약 tailscale up이 키를 거부한다면, 클라이언트에서 설정을 수정하기보다 서버에서 새로운 키를 생성하십시오.

노드 키(Node keys)는 장기간 유지되는 부분입니다. config.yamlnode 섹션에서 expiry: 0을 설정하며, 0은 기본 만료 기한이 없음을 의미합니다. 즉, 등록된 노드는 사용자가 직접 만료시키기 전까지 유효합니다. 태그가 지정된 노드는 어떤 경우에도 만료되지 않습니다. 등록된 노드가 시간이 지나면 만료되기를 원한다면 expiry: 180d를 설정하십시오. 단, 이 설정의 의미를 이해해야 합니다. 태그가 지정되지 않은 모든 노드는 해당 일정에 맞춰 sudo tailscale up --login-server https://headscale.example.com --force-reauth을 수행해야 하며, 아무도 재인증하지 않는 헤드리스 서버는 스스로 네트워크에서 제외됩니다.

누군가 노트북을 분실했을 때는 수동으로 처리하십시오. sudo headscale nodes list로 ID를 확인하고, sudo headscale nodes expire -i 3로 해당 노드를 로그아웃시킨 뒤, sudo headscale nodes delete -i 3으로 네트워크에서 완전히 제거하십시오.

백업 및 업그레이드

/var/lib/headscale/etc/headscale은 서버 전체를 구성합니다. SQLite는 실행 중에 쓰기 작업이 발생할 수 있으므로, 복사하기 전에 서비스를 중지해야 합니다. 부하가 걸린 상태에서 복사한 데이터베이스는 일관성이 깨질 수 있습니다.

sudo systemctl stop headscale
sudo tar czf /root/headscale-state.tgz -C /var/lib headscale
sudo tar czf /root/headscale-config.tgz -C /etc headscale
sudo systemctl start headscale
sudo chmod 600 /root/headscale-*.tgz

두 파일을 서버 외부로 이동하십시오. 이 파일들에는 개인 키와 모든 등록 정보가 포함되어 있으므로 서버 자체와 동일한 수준의 보안 관리가 필요합니다. VPS에서 restic 백업하기 문서에서 암호화된 백업을 일정에 따라 수행하는 방법을 다룹니다.

업그레이드는 설치 과정을 반복합니다. 새로운 .debsudo apt install ./headscale.deb을 다운로드한 뒤, 서비스를 재시작하고 is-active/health 검사를 다시 실행하십시오. 0.29 버전부터 업그레이드 경로는 엄격하게 제한됩니다. 마이너 버전을 건너뛰거나 이전 마이너 버전으로 다운그레이드하는 것은 차단됩니다. 한 번에 한 마이너 버전씩 업그레이드하고, 각 단계마다 백업을 수행하십시오. 또한 해당 버전의 릴리스 노트를 먼저 읽어보아야 합니다. 동일한 릴리스에서 ACL 정책 동작이 변경되거나 여러 설정 키의 위치가 이동된 사례가 있기 때문입니다.

FAQ

.deb 패키지를 설치한 직후 headscale이 시작되지 않는 이유는 무엇입니까?

패키지는 유닛을 설치하지만 서비스는 중지된 상태로 둡니다. 또한 기본 제공되는 /etc/headscale/config.yaml은 작동 가능한 설정이 아닌 템플릿입니다. 먼저 server_url, listen_addr, base_domain을 편집한 다음 sudo systemctl enable --now headscale을 실행하고 sudo systemctl is-active headscale로 확인하십시오. 그래도 실패한다면 sudo journalctl -u headscale -n 50 --no-pager를 통해 문제의 원인을 파악할 수 있습니다. headscale은 포트를 바인딩하기 전에 전체 파일을 파싱하므로, 이 단계에서의 실패는 거의 항상 YAML 설정 오류입니다.

내 기기에 일반 Tailscale 클라이언트를 그대로 설치해야 합니까?

네. Headscale은 컨트롤 서버만 대체합니다. 모든 노드는 Tailscale의 공식 클라이언트를 실행하며, sudo tailscale up --login-server https://headscale.example.com을 사용하여 서버를 지정하면 됩니다. 해당 플래그는 표준 클라이언트에 포함되어 있으므로 별도의 패치나 재빌드가 필요하지 않습니다.

내 트래픽이 headscale 서버를 거쳐서 이동합니까?

일반적으로 그렇지 않습니다. Headscale은 네트워크를 조정하고 키와 주소를 배포하며, 데이터 경로는 노드 간의 WireGuard를 직접 사용합니다. 트래픽이 우회하는 경우는 두 노드가 서로 직접 연결할 수 없어 DERP 릴레이로 전환될 때뿐이며, 기본 설정에서는 Tailscale의 공개 릴레이를 사용합니다. 노드에서 tailscale status을 실행하면 특정 피어가 direct 상태인지 아니면 relay을 경유하는지 확인할 수 있습니다.

노드가 등록된 후에도 오프라인 상태로 유지되는 이유는 무엇입니까?

headscale nodes list에는 나타나지만 온라인 상태가 되지 않는 노드는 보통 리버스 프록시에서 컨트롤 연결이 끊긴 경우입니다. 해당 연결은 Upgrade: tailscale-control-protocol 헤더가 포함된 POST 요청으로 전송되는 HTTP 업그레이드인데, map $http_upgrade $connection_upgrade 블록과 일치하는 proxy_set_header 라인을 추가하지 않으면 nginx가 이를 차단합니다. Caddy는 별도의 설정 없이도 이를 전달하므로, 프록시 문제인지 빠르게 테스트하는 방법으로 유용합니다.

headscale을 위해 도메인 이름과 TLS가 필요합니까?

실제 운영 환경에서는 필요합니다. 클라이언트는 server_url에 입력한 문자열로 연결을 시도하며, 인증서는 IP 주소가 아닌 도메인 이름으로 발급됩니다. 또한 설정 파일에 따르면 DERP는 TLS를 요구합니다. 도메인과 Caddy를 사용하면 5분 내에 자동으로 갱신되는 HTTPS 엔드포인트를 구성할 수 있습니다. 일반 HTTP로 컨트롤 서버를 운영하면 클라이언트와의 모든 통신 내용이 암호화되지 않은 상태로 인터넷을 통해 전송됩니다.