Headscale 노드, 서버에 한해서는 무제한으로 연장하기

노드 키가 만료되면
셀프호스팅 Tailscale(Headscale)을 쓰면서 가장 짜증나는 순간이 있습니다.
잘 쓰고 있던 exit node가 어느 날 갑자기 안 됩니다.
키가 만료된 겁니다.
Headscale은 기본 180일마다 노드 키가 만료되거든요.
서버처럼 항상 켜져있어야 하는 노드에게 이건 맞지 않습니다.
180일마다 SSH 들어가서 재인증해야 하니까요.
공식적인 방법은?
Tailscale 공식 서비스에서는 tagged node(서버용)의 키 만료를 자동으로 꺼줍니다.
Headscale도 비슷하게, tagged preauth key로 등록하면 expiry가 자동으로 무제한이 됩니다.
실제로 제 subnet router는 처음부터 tagged key로 등록해서 만료가 0001-01-01 (= 없음)이었거든요.
근데 문제는 이미 등록된 노드입니다.
Headscale 0.28 기준으로 CLI에 nodes disable-expiry 같은 명령어가 없어요.
API 문서를 뒤져봐도 노드 expiry를 수정하는 엔드포인트가 안 보입니다.
문제 발생, auth-key로 재인증하면?
"노드 안 지우고 tagged auth-key로 다시 tailscale up 하면 expiry가 리셋되지 않을까?"
해봤는데 안 됩니다.
backend error: authkey already used
일회용 키라서 그런가 싶어 reusable로 만들어도 같은 에러.
이미 등록된 노드에 auth-key를 다시 먹이는 건 Headscale이 거부합니다.
노드를 삭제하고 재등록하면 되긴 하는데, IP가 바뀔 수 있고 route 승인도 다시 해야 하고...
저는 VPS도 운용하고 있어서 하나하나 재갱신하는 건 현실적이지 않았습니다.
결론: DB 직접 수정
Headscale은 sqlite를 씁니다. 그냥 열어서 바꾸면 됩니다.
# headscale data 경로에서 직접 실행
sqlite3 /path/to/headscale/data/db.sqlite \
"UPDATE nodes SET expiry = '0001-01-01 00:00:00+00:00';"
전체 노드의 expiry를 Go의 zero time으로 밀어버리면 만료 자체가 사라집니다.
특정 노드만 하고 싶으면:
sqlite3 db.sqlite "UPDATE nodes SET expiry = '0001-01-01 00:00:00+00:00' WHERE id = 6;"
수정 후 headscale 컨테이너 재시작하면 반영됩니다.
docker compose restart headscale
그 다음 만료됐던 노드에서 재연결:
tailscale up --reset --advertise-exit-node --login-server=http://your-headscale:8089 --accept-routes
--reset 안 붙이면 기존 설정이랑 충돌나면서 모든 플래그를 명시하라고 에러 뱉으니까 주의.
앞으로 새 노드는?
DB 수정은 기존 노드에만 적용됩니다. 새로 등록되는 노드는 여전히 180일 만료가 붙어요.
방지하려면:
- 서버/인프라 노드: tagged preauth key로 등록 → 자동 무제한
- 개인 디바이스: OIDC 로그인 → 180일 만료 (어쩔 수 없음, 만료되면 DB 한 줄 치면 됨)
# tagged preauth key 생성 예시
headscale preauthkeys create -u <USER_ID> --reusable --tags tag:server -e 24h
이 키로 tailscale up --auth-key=... 하면 처음부터 만료 없이 등록됩니다.
마무리
정리하면:
- Headscale CLI에 노드 expiry disable 기능은 (0.28 기준) 없음
- sqlite DB에서
expiry컬럼을 zero time으로 밀면 끝 - 새 서버 노드는 처음부터 tagged key로 등록하면 만료 안 붙음
- v0.29에서 이 기능이 추가될 수도 있음 (GitHub issue #1711 참고)