วิธีติดตั้ง Headscale ทำ Tailscale Server ส่วนตัวบน VPS
เรียนรู้วิธีติดตั้ง Headscale เพื่อรัน Tailscale Control Server บน VPS ของคุณเอง พร้อมขั้นตอนการตั้งค่า server_url และการเชื่อมต่อโหนดแรกเข้าสู่เครือข่ายอย่างถูกต้อง
headscale คืออะไร
headscale คือการนำเซิร์ฟเวอร์ควบคุมของ Tailscale มาติดตั้งใช้งานด้วยตนเอง ดังนั้นเครื่องที่ทำหน้าที่ประสานงานเครือข่ายส่วนตัวของคุณจึงเป็น VPS ที่คุณเป็นเจ้าของ นี่เป็นโครงการชุมชนและไม่ได้ดำเนินการโดย Tailscale Inc. โดยทุกเครื่องยังคงรันไคลเอนต์ tailscale อย่างเป็นทางการ ซึ่งชี้ไปยังเซิร์ฟเวอร์ของคุณด้วยแฟล็ก --login-server เพียงตัวเดียว
เซิร์ฟเวอร์ควบคุมคือส่วนที่ทำหน้าที่ระบุว่าใครเป็นสมาชิกของเครือข่าย โดยจะกำหนดที่อยู่จาก 100.64.0.0/10 ให้กับแต่ละโหนด แจกจ่ายกุญแจสาธารณะ และแจ้งให้โหนดทราบว่าต้องเชื่อมต่อหากันอย่างไร อุโมงค์เชื่อมต่อยังคงเป็น WireGuard ซึ่งสร้างขึ้นแบบโหนดต่อโหนด ทราฟฟิกระหว่างเครื่องสองเครื่องของคุณจะไม่ผ่านกล่อง headscale เว้นแต่ว่าจะไม่สามารถสร้างเส้นทางตรงได้และโหนดต้องเปลี่ยนไปใช้รีเลย์แทน
headscale รองรับหนึ่ง tailnet (เครือข่าย Tailscale หนึ่งเครือข่าย) ต่อหนึ่งอินสแตนซ์ ซึ่งโครงการระบุว่าเหมาะสมสำหรับการใช้งานส่วนตัวหรือองค์กรขนาดเล็ก หากมีเครื่องเพียง 3 หรือ 4 เครื่อง การใช้ VPN แบบ WireGuard บน VPS ที่คุณเป็นเจ้าของ จะเป็นซอฟต์แวร์ที่ต้องดูแลรักษาน้อยกว่าและมีโอกาสเกิดข้อผิดพลาดน้อยกว่า headscale จะคุ้มค่าเมื่อคุณไม่ต้องการเขียนบล็อก [Peer] ด้วยตนเองสำหรับแล็ปท็อปเครื่องใหม่ทุกเครื่อง สำหรับการเปรียบเทียบทั้งสองรูปแบบในวงกว้าง โปรดดูที่ ความแตกต่างระหว่าง WireGuard และ Tailscale
สิ่งที่ต้องเตรียมก่อนการติดตั้ง
- VPS ที่รัน Ubuntu 24.04 พร้อมที่อยู่ IPv4 สาธารณะและสิทธิ์ sudo หากเป็นเซิร์ฟเวอร์ใหม่ ให้ดำเนินการตาม สิบนาทีแรกบน VPS ใหม่ ก่อน
- ระเบียน DNS A ที่ชี้ไปยังที่อยู่นั้น คู่มือนี้ใช้
headscale.example.com - โดเมนที่สองหรือโดเมนย่อยสำหรับ MagicDNS คู่มือนี้ใช้
tailnet.example.netโดยต้องไม่เป็นโดเมนเดียวกับที่ใช้ในserver_url - เครื่องลูกข่ายหนึ่งเครื่องเพื่อเข้าร่วมเครือข่าย โดยรันระบบปฏิบัติการ Linux, macOS, Windows, Android หรือ iOS
การติดตั้ง headscale จากไฟล์ .deb อย่างเป็นทางการ
โครงการนี้เผยแพร่แพ็กเกจ .deb ไว้บนหน้า GitHub releases ณ เดือนกรกฎาคม 2026 เวอร์ชันปัจจุบันคือ 0.29.3 ให้ตรวจสอบสถาปัตยกรรมของระบบคุณก่อน เนื่องจากชื่อไฟล์จะระบุสถาปัตยกรรมไว้
sudo apt update
sudo apt install -y wget
dpkg --print-architectureคำสั่งดังกล่าวจะแสดงผล amd64 บน VPS x86 ทั่วไป และแสดงผล arm64 บนแผนบริการประเภท Ampere หรือ Graviton ให้นำค่าที่ได้ไปใส่ในตัวแปรด้านล่างนี้
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 unit โดยจะ ไม่ เริ่มการทำงานของเซอร์วิสโดยอัตโนมัติ ซึ่งเป็นลำดับขั้นตอนที่ถูกต้องแล้ว การตั้งค่าที่มาพร้อมกับซอฟต์แวร์จะชี้ server_url ไปที่ http://127.0.0.1:8080 ซึ่งไม่ใช่ที่อยู่ที่ไคลเอนต์ของคุณจะเข้าถึงได้ ดังนั้นหากเริ่มเซอร์วิสในตอนนี้ก็จะทำงานไม่ถูกต้องแม้ว่าจะเปิดใช้งานได้ก็ตาม การรันคำสั่ง sudo systemctl is-active headscale ในขั้นตอนนี้จะแสดงผล inactive ซึ่งเป็นสิ่งที่คาดการณ์ไว้ ไม่ใช่ข้อผิดพลาดแต่อย่างใด
กำหนดค่า server_url ก่อนเริ่มใช้งานบริการ
แก้ไขไฟล์ /etc/headscale/config.yaml ด้วย sudo nano /etc/headscale/config.yaml หรือใช้คำสั่ง sed เพื่อปรับเปลี่ยนการตั้งค่าทั้ง 3 จุด ให้สำรองไฟล์ต้นฉบับไว้เสมอ เนื่องจากไฟล์ดังกล่าวมีความยาวและมีคำอธิบายประกอบจำนวนมาก ซึ่งถือเป็นข้อมูลอ้างอิงที่ดีที่สุดสำหรับการตั้งค่าส่วนที่เหลือ
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.yamlserver_url คือที่อยู่ที่ headscale จะเขียนลงในการลงทะเบียนของไคลเอนต์ทุกเครื่อง ไคลเอนต์จะเชื่อมต่อไปยังสตริงดังกล่าวตลอดไป ดังนั้นค่านี้จะต้องเป็นชื่อสาธารณะที่ขึ้นต้นด้วย https:// เท่านั้น ห้ามใช้ 127.0.0.1
listen_addr คือตำแหน่งที่โพรเซสจะทำการ bind ให้คงค่าไว้ที่ loopback เนื่องจาก reverse proxy ที่อยู่บนเครื่องเดียวกันจะทำหน้าที่จัดการ TLS (transport layer security) และส่งต่อข้อมูลเข้ามา ดังนั้นจึงไม่มีความจำเป็นที่บริการภายนอกจะต้องเข้าถึงพอร์ต 8080 โดยตรง
base_domain คือส่วนต่อท้ายของ MagicDNS ซึ่งเป็นโดเมนที่โหนดของคุณจะได้รับชื่อภายใต้โดเมนนั้น ค่านี้จะต้องเป็นชื่อโดเมนแบบสมบูรณ์ (FQDN) โดยไม่มีจุดปิดท้าย และจะต้องเป็นโดเมนที่แตกต่างจากที่ระบุไว้ใน server_url มิฉะนั้นพื้นที่ชื่อทั้งสองส่วนจะเกิดการทับซ้อนกัน
ไม่ต้องแก้ไขส่วนของฐานข้อมูล ค่าเริ่มต้นคือ SQLite ที่ตำแหน่ง /var/lib/headscale/db.sqlite ซึ่งอยู่ในไดเรกทอรีที่แพ็กเกจสร้างขึ้นและเป็นเจ้าของอยู่แล้ว โดย SQLite เพียงพอสำหรับการใช้งาน tailnet ในขนาดเท่านี้
เริ่มการทำงานของ 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/healthis-active จะแสดงผล active และ curl จะแสดงผล 200 ส่วน enable --now จะทำหน้าที่ทั้งสองอย่าง คือการเริ่มบริการและกำหนดให้เริ่มทำงานโดยอัตโนมัติหลังจากรีบูตเครื่อง
หาก is-active แสดงผล failed ให้ตรวจสอบบันทึกการทำงานด้วย sudo journalctl -u headscale -n 50 --no-pager ความผิดพลาดในขั้นตอนนี้มักเกิดจากไฟล์การตั้งค่าเสมอ เนื่องจาก headscale จะตรวจสอบไฟล์ทั้งหมดก่อนที่จะเปิด socket ดังนั้นการย่อหน้าผิดหรือการใช้คีย์ที่ไม่รู้จักจะทำให้กระบวนการหยุดทำงานก่อนที่จะมีการเปิดพอร์ตใดๆ ให้แก้ไขไฟล์แล้วจึงใช้ 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 จะสร้างไฟล์ใหม่ขึ้นมา และโหนดทุกโหนดจะต้องลงทะเบียนใหม่อีกครั้ง
การติดตั้ง TLS หน้า headscale
ไคลเอนต์ต้องเข้าถึง server_url ผ่าน HTTPS โดย Caddy เป็นเส้นทางที่สั้นที่สุด เนื่องจาก 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 caddyvalidate จะแสดงผล adapted config to JSON เมื่อไฟล์ถูกประมวลผล คำเตือนเรื่องรูปแบบไฟล์ไม่ถูกต้องเป็นเพียงเรื่องความสวยงามเท่านั้น จากแล็ปท็อปของคุณ คำสั่ง curl -sS -o /dev/null -w '%{http_code}\\n' https://headscale.example.com/health ควรแสดงผล 200 เช่นกัน การตรวจสอบเพียงขั้นตอนเดียวนี้เป็นการยืนยันว่า DNS, ไฟร์วอลล์, ใบรับรอง และพร็อกซีทำงานร่วมกันได้อย่างถูกต้อง
นี่คือรายละเอียดของพร็อกซีที่มักทำให้เสียเวลาในการแก้ไขปัญหา การเชื่อมต่อควบคุมของ Tailscale เป็นการอัปเกรด HTTP ซึ่งเริ่มต้นด้วย POST แทนที่จะเป็น GET และค่าของส่วนหัว Upgrade คือ tailscale-control-protocol โดย Caddy จะส่งผ่านค่านี้ไปโดยไม่ต้องตั้งค่าเพิ่มเติม แต่ nginx ไม่ได้ทำเช่นนั้น ดังนั้น nginx ที่ทำหน้าที่เป็น front end จึงจำเป็นต้องมีแผนผังการอัปเกรด:
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 คุณสามารถดู Certbot บน Ubuntu 24.04 ร่วมกับ nginx สำหรับขั้นตอนการจัดการใบรับรอง
พอร์ตที่ต้องเปิดใน 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 challenge และการเปลี่ยนเส้นทางไปยัง HTTPS เท่านั้น โดย Caddy จำเป็นต้องใช้พอร์ตนี้ในการขอใบรับรอง
พอร์ต 8080 ควรปิดไว้ listen_addr คือ 127.0.0.1:8080 ดังนั้นพร็อกซีจะเข้าถึง headscale ผ่านอินเทอร์เฟซ loopback โดยไม่ต้องผ่านกฎของไฟร์วอลล์ การเปิดพอร์ต 8080 สู่สาธารณะจะทำให้ไคลเอนต์ใช้ช่องทางควบคุมแบบข้อความธรรมดา (cleartext) ซึ่งไม่มีประโยชน์ใดๆ โปรดทราบว่าผู้ให้บริการส่วนใหญ่จะมีไฟร์วอลล์อีกชั้นหนึ่งในแผงควบคุม ซึ่งแยกต่างหากจาก UFW ดังนั้นพอร์ตอาจเปิดอยู่บนเซิร์ฟเวอร์แต่ยังคงถูกปิดอยู่ที่ระดับเครือข่ายภายนอก พื้นฐานการใช้งาน UFW บน VPS อธิบายไวยากรณ์ของกฎต่างๆ ไว้โดยละเอียด
การสร้างผู้ใช้และคีย์ preauth
sudo headscale users create alice
sudo headscale users listคำสั่ง headscale ทำหน้าที่เป็นไคลเอนต์ โดยจะสื่อสารกับ daemon ที่กำลังทำงานอยู่ผ่าน unix socket ที่ /var/run/headscale/headscale.sock ซึ่งกำหนดสิทธิ์ไว้ที่ 0770 และเป็นกรรมสิทธิ์ของกลุ่ม headscale สิ่งนี้ส่งผลให้เกิดสองประเด็นคือ คำสั่งจะทำงานล้มเหลวหากบริการหยุดทำงาน ซึ่งเป็นเหตุผลว่าทำไมลำดับขั้นตอนในคู่มือนี้จึงมีความสำคัญ และจำเป็นต้องใช้ sudo เว้นแต่คุณจะเพิ่มบัญชีผู้ใช้ของคุณเข้าไปในกลุ่ม headscale
users list จะแสดง ID กำกับไว้ข้างชื่อแต่ละรายการ คุณจำเป็นต้องใช้ตัวเลขนั้นเนื่องจากคำสั่ง key ต้องการระบุเป็นตัวเลข ID ของผู้ใช้ ไม่ใช่ชื่อ
sudo headscale preauthkeys create --user 1 --expiration 24hคีย์จะถูกแสดงออกมาเพียงครั้งเดียว ให้คัดลอกไว้ทันที คีย์ preauth สามารถใช้งานได้เพียงครั้งเดียวและมีอายุการใช้งานหนึ่งชั่วโมงเว้นแต่คุณจะกำหนดเป็นอย่างอื่น ดังนั้นการใช้ --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 -4tailscale ip -4 จะแสดงที่อยู่ที่ headscale กำหนดให้ ซึ่งจะมีลักษณะคล้ายกับ 100.64.0.1 กลับไปที่ฝั่งเซิร์ฟเวอร์ sudo headscale nodes list จะแสดงโหนดพร้อมกับ ID, ผู้ใช้งาน และสถานะออนไลน์
ค่าของ --login-server จะต้องตรงกับ server_url ทุกประการ รวมถึงรูปแบบ (scheme) และต้องไม่มีเครื่องหมายทับ (slash) ต่อท้าย ทั้งสองค่าจะถูกเปรียบเทียบในรูปแบบสตริง หากไม่ตรงกันจะทำให้ไคลเอนต์ลงทะเบียนกับที่อยู่หนึ่ง แต่ได้รับคำสั่งให้ไปติดต่อกับอีกที่อยู่หนึ่งแทน
เครื่องที่เคยลงชื่อเข้าใช้บริการโฮสต์ของ Tailscale มาก่อนจะยังคงสถานะการลงชื่อเข้าใช้นั้นไว้ ให้รันคำสั่ง sudo tailscale logout บนเครื่องนั้นก่อน จากนั้นจึงรัน tailscale up ด้วย --login-server
หากคุณละเว้น --auth-key ไว้ ไคลเอนต์จะแสดง URL ออกมาแทน ให้เปิด URL ดังกล่าวแล้วหน้าเว็บจะแสดงตัวระบุสำหรับการลงทะเบียนนั้น ซึ่งคุณจะต้องอนุมัติบนเซิร์ฟเวอร์:
sudo headscale auth register --user alice --auth-id PASTE-THE-ID-FROM-THE-PAGEรูปแบบดังกล่าวสะดวกกว่าสำหรับแล็ปท็อปส่วนตัวของคุณ ส่วน Preauth keys จะเหมาะสมกว่าสำหรับงานที่ทำผ่านสคริปต์ เนื่องจากไม่จำเป็นต้องมีผู้ใช้งานคอยเฝ้าดูอยู่ตลอดเวลา
DERP และสิ่งที่ทำหน้าที่ส่งต่อทราฟฟิกเมื่อเส้นทางตรงล้มเหลว
DERP (designated encrypted relay for packets) คือเส้นทางสำรอง เมื่อโหนดสองโหนดไม่สามารถเปิดการเชื่อมต่อ WireGuard แบบตรงได้ ซึ่งมักเกิดจากทั้งสองโหนดอยู่หลัง NAT (network address translation) ที่เข้มงวด โหนดเหล่านั้นจะส่งแพ็กเก็ตผ่านรีเลย์แทน รีเลย์ไม่มีกุญแจเข้ารหัส จึงไม่สามารถอ่านทราฟฟิกของคุณได้ แต่รีเลย์จะเห็นว่าโหนดใดกำลังสื่อสารกันและมีปริมาณข้อมูลเคลื่อนย้ายเท่าใด
โปรดทำความเข้าใจว่าการตั้งค่าเริ่มต้นทำงานอย่างไร Headscale ถูกปล่อยออกมาโดยชี้ไปที่ https://controlplane.tailscale.com/derpmap/default พร้อมด้วย auto_update_enabled: true และ update_frequency: 3h ดังนั้นในขณะที่ระนาบควบคุม (control plane) เป็นของคุณ แต่รีเลย์ยังคงเป็นของ Tailscale สำหรับคนส่วนใหญ่ถือเป็นการแลกเปลี่ยนที่ยอมรับได้ หากคุณไม่ต้องการเช่นนั้น คุณสามารถรันรีเลย์ของคุณเองได้
ในการรันรีเลย์ของคุณเอง ให้ตั้งค่า enabled: true ภายใต้ derp.server ใน config.yaml จากนั้นรีสตาร์ท headscale และเปิดพอร์ต STUN (session traversal utilities for NAT) ด้วย sudo ufw allow 3478/udp ไฟล์การตั้งค่าระบุข้อกำหนดไว้อย่างชัดเจนว่า server_url ต้องใช้ https เนื่องจาก DERP จำเป็นต้องใช้ TLS การล้างรายการ derp.urls จะเป็นการนำรีเลย์ของ Tailscale ออกจากแผนผัง และหากคุณทำเช่นนั้นโดยไม่มีรีเลย์แบบฝังตัวที่ทำงานได้ โหนดคู่ใดก็ตามที่ไม่สามารถเชื่อมต่อกันโดยตรงได้ จะไม่สามารถเชื่อมต่อกันได้เลย
จากฝั่งไคลเอนต์ tailscale netcheck จะแสดงค่าความหน่วง (latency) ไปยังแต่ละภูมิภาคของรีเลย์ที่ไคลเอนต์รู้จัก และ tailscale status จะระบุเพียร์แต่ละตัวว่าอยู่ในสถานะ direct พร้อมที่อยู่ หรือ relay พร้อมรหัสภูมิภาค หากเพียร์ติดอยู่ที่สถานะ relay นั่นคือปัญหาของ NAT ไม่ใช่ปัญหาของ headscale
ทำไมโหนดถึงแสดงสถานะเป็นออฟไลน์?
พร็อกซีปฏิเสธการอัปเกรด นี่เป็นสาเหตุที่พบบ่อยที่สุด โดยมีลักษณะคือทุกอย่างดูปกติ: /health ส่งค่ากลับเป็น 200, headscale nodes list แสดงโหนดดังกล่าว แต่โหนดไม่เคยออนไลน์ การเชื่อมต่อควบคุมคือ POST ที่ส่ง Upgrade: tailscale-control-protocol หากพร็อกซีไม่ส่งต่อข้อมูลนี้ จะทำให้ช่องทางเดียวที่ใช้รายงานสถานะโหนดถูกตัดขาด ให้ตรวจสอบการตั้งค่า nginx ของคุณเทียบกับบล็อก map ด้านบน หรือเปลี่ยนไปใช้ Caddy เพื่อตัดปัญหาเรื่องพร็อกซีออกไป
server_url เปลี่ยนแปลงหลังจากโหนดลงทะเบียนแล้ว โหนดจะพยายามเชื่อมต่อด้วยค่าที่ได้รับตอนลงทะเบียนเสมอ หากคุณแก้ไขค่านี้ ให้รัน sudo tailscale up --login-server https://headscale.example.com --force-reauth บนโหนดแต่ละตัว
ไคลเอนต์ไม่ได้ทำงาน บนโหนด ให้ตรวจสอบ sudo systemctl is-active tailscaled และ sudo journalctl -u tailscaled -n 50 --no-pager ไคลเอนต์ที่ไม่สามารถแก้ไขชื่อโดเมนหรือเข้าถึงโดเมนของคุณได้จะบันทึกการพยายามเชื่อมต่อซ้ำไว้ที่นั่น
คีย์หมดอายุ รายละเอียดอยู่ในหัวข้อถัดไป
หากต้องการตรวจสอบฝั่งเซิร์ฟเวอร์ในระหว่างการทดสอบ ให้รัน sudo journalctl -u headscale -f บน VPS และรีสตาร์ท tailscaled บนไคลเอนต์ โหนดที่เข้าถึง headscale ได้จะสร้างบรรทัดบันทึกข้อมูลขึ้นมาทันที หากไม่มีข้อมูลปรากฏ แสดงว่าคำขอส่งมาไม่ถึง ให้ตรวจสอบ DNS, ไฟร์วอลล์ และพร็อกซีก่อนที่จะตรวจสอบ headscale
การหมดอายุของคีย์ และโหนดที่หยุดทำงานในอีกหลายสัปดาห์ต่อมา
มีการหมดอายุอยู่สองประเภทที่แยกจากกัน และการสับสนระหว่างสองสิ่งนี้ทำให้เสียเวลา
คีย์ประเภท Preauth ถูกออกแบบมาให้หมดอายุอย่างรวดเร็ว โดยค่าเริ่มต้นคือหนึ่งชั่วโมงและใช้งานได้เพียงครั้งเดียว หาก tailscale up ปฏิเสธคีย์ดังกล่าว ให้สร้างคีย์ใหม่บนเซิร์ฟเวอร์แทนการแก้ไขค่าใดๆ บนไคลเอนต์
คีย์ของโหนดเป็นส่วนที่มีอายุการใช้งานยาวนาน ส่วน node ของ config.yaml จะกำหนดค่า expiry: 0 และการตั้งค่า 0 หมายความว่าจะไม่มีการหมดอายุโดยอัตโนมัติ โหนดที่ลงทะเบียนไว้จะมีสถานะใช้งานได้จนกว่าคุณจะสั่งให้หมดอายุ ส่วนโหนดที่ติดแท็ก (Tagged nodes) จะไม่มีวันหมดอายุไม่ว่ากรณีใดๆ ให้ตั้งค่า expiry: 180d หากคุณต้องการให้การลงทะเบียนมีวันหมดอายุ และต้องเข้าใจผลลัพธ์ที่จะเกิดขึ้น: โหนดที่ไม่ได้ติดแท็กทุกโหนดจะต้องทำการ sudo tailscale up --login-server https://headscale.example.com --force-reauth ตามกำหนดเวลานั้น และเซิร์ฟเวอร์แบบ headless ที่ไม่มีใครทำการยืนยันตัวตนใหม่จะหลุดออกจากเครือข่ายโดยอัตโนมัติ
ให้ดำเนินการด้วยตนเองเมื่อมีคนทำแล็ปท็อปสูญหาย คำสั่ง 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ให้ย้ายไฟล์ทั้งสองออกจากเครื่องเซิร์ฟเวอร์ ไฟล์เหล่านี้ประกอบด้วยคีย์ส่วนตัวและการลงทะเบียนทั้งหมด จึงควรได้รับการดูแลเช่นเดียวกับตัวเซิร์ฟเวอร์เอง บทความ การสำรองข้อมูลด้วย restic จาก VPS ครอบคลุมวิธีการดำเนินการดังกล่าวตามกำหนดเวลาและมีการเข้ารหัสข้อมูล
การอัปเกรดให้ทำซ้ำขั้นตอนการติดตั้ง: ดาวน์โหลด .deb และ sudo apt install ./headscale.deb เวอร์ชันใหม่ จากนั้นรีสตาร์ทและรันการตรวจสอบ is-active และ /health อีกครั้ง ตั้งแต่เวอร์ชัน 0.29 เป็นต้นมา เส้นทางการอัปเกรดมีความเข้มงวด ระบบจะบล็อกการข้ามเวอร์ชันย่อย รวมถึงการดาวน์เกรดไปยังเวอร์ชันย่อยที่เก่ากว่า ให้ดำเนินการทีละเวอร์ชันย่อย สำรองข้อมูลก่อนเริ่มแต่ละขั้นตอน และอ่านบันทึกประจำรุ่น (release notes) ของเวอร์ชันนั้นๆ ก่อนเสมอ เนื่องจากบางรุ่นมีการเปลี่ยนแปลงพฤติกรรมของนโยบาย ACL และมีการย้ายคีย์การตั้งค่าหลายรายการ
FAQ
ทำไม headscale ถึงไม่เริ่มทำงานทันทีหลังจากที่ผมติดตั้งไฟล์ .deb?
แพ็กเกจจะติดตั้ง unit ไว้แต่จะปล่อยให้ service หยุดทำงานอยู่ และค่าเริ่มต้นใน /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 จะระบุสาเหตุของปัญหา ซึ่งในขั้นตอนนี้มักเกิดจากข้อผิดพลาดในไฟล์ YAML เนื่องจาก headscale จะอ่านไฟล์ทั้งหมดก่อนที่จะทำการ bind พอร์ต
ผมยังต้องติดตั้ง Tailscale client แบบปกติบนเครื่องของผมหรือไม่?
ใช่ครับ Headscale จะทำหน้าที่แทนเฉพาะ control server เท่านั้น ทุกโหนดจะรัน client อย่างเป็นทางการจาก Tailscale และคุณต้องชี้ client ไปยังเซิร์ฟเวอร์ของคุณด้วย sudo tailscale up --login-server https://headscale.example.com แฟล็กดังกล่าวมีอยู่ใน client มาตรฐานอยู่แล้ว จึงไม่จำเป็นต้องแก้ไขหรือคอมไพล์โปรแกรมใหม่
ทราฟฟิกของผมจะวิ่งผ่านเซิร์ฟเวอร์ headscale หรือไม่?
โดยปกติแล้วจะไม่ใช่ครับ Headscale ทำหน้าที่ประสานงานเครือข่ายและแจกจ่ายคีย์รวมถึงที่อยู่ IP ในขณะที่เส้นทางข้อมูลจะเป็น WireGuard ระหว่างโหนดของคุณโดยตรง ทราฟฟิกจะอ้อมผ่านเซิร์ฟเวอร์ก็ต่อเมื่อโหนดสองโหนดไม่สามารถเชื่อมต่อกันโดยตรงได้และต้องเปลี่ยนไปใช้ DERP relay แทน ซึ่งในการตั้งค่าที่ให้มา relay เหล่านี้จะเป็น relay สาธารณะของ Tailscale ให้รันคำสั่ง tailscale status บนโหนดเพื่อตรวจสอบว่า peer ที่กำหนดนั้นเชื่อมต่อแบบ direct หรือผ่าน relay
ทำไมโหนดของผมถึงยังคงสถานะออฟไลน์หลังจากลงทะเบียนแล้ว?
โหนดที่ปรากฏใน headscale nodes list แต่ไม่เคยออนไลน์ มักเกิดจากการสูญเสียการเชื่อมต่อ control connection ที่ reverse proxy การเชื่อมต่อดังกล่าวคือ HTTP upgrade ที่ส่งผ่าน POST พร้อมเฮดเดอร์ Upgrade: tailscale-control-protocol ซึ่ง nginx จะตัดการเชื่อมต่อนี้ทิ้งหากคุณไม่ได้เพิ่มบล็อก map $http_upgrade $connection_upgrade และบรรทัด proxy_set_header ที่สอดคล้องกัน ส่วน Caddy จะส่งต่อการเชื่อมต่อนี้โดยไม่ต้องตั้งค่าเพิ่มเติม ซึ่งทำให้เป็นวิธีที่รวดเร็วในการทดสอบว่าปัญหาเกิดจาก proxy หรือไม่
ผมจำเป็นต้องมีชื่อโดเมนและ TLS สำหรับ headscale หรือไม่?
ในทางปฏิบัติแล้วจำเป็นครับ Client จะเชื่อมต่อไปยังสตริงที่คุณระบุไว้ใน server_url โดยใบรับรองจะออกให้สำหรับชื่อโดเมนไม่ใช่สำหรับ IP address เปล่าๆ และไฟล์การตั้งค่าระบุว่า DERP จำเป็นต้องใช้ TLS การใช้โดเมนร่วมกับ Caddy ใช้เวลาเพียงประมาณห้านาทีและจะทำให้คุณได้ HTTPS endpoint ที่ต่ออายุใบรับรองอัตโนมัติ การรัน control server ผ่าน HTTP ธรรมดาจะทำให้การสื่อสารทั้งหมดระหว่าง client กับเซิร์ฟเวอร์ถูกส่งผ่านอินเทอร์เน็ตโดยไม่มีการเข้ารหัส