SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

วิธีติดตั้ง Headscale เพื่อทำ Tailscale ส่วนตัวบน VPS

เรียนรู้วิธีติดตั้ง Headscale บน VPS เพื่อจัดการ Tailscale ด้วยตนเอง เริ่มต้นจากไฟล์ .deb กำหนดค่า server_url ให้ถูกต้องก่อนเปิดใช้งาน เพื่อเชื่อมต่อโหนดแรกเข้าเครือข่าย

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

Headscale คืออะไร

Headscale คือการนำ Tailscale control server มาติดตั้งใช้งานด้วยตนเอง (self-hosted) ดังนั้นเครื่องที่ทำหน้าที่ประสานงานเครือข่ายส่วนตัวของคุณจึงเป็น VPS ที่คุณเป็นเจ้าของเอง นี่เป็นโครงการจากชุมชนและไม่ได้ดำเนินการโดย Tailscale Inc. โดยทุกเครื่องยังคงรันไคลเอนต์ tailscale อย่างเป็นทางการ และชี้ไปยังเซิร์ฟเวอร์ของคุณด้วยแฟล็ก --login-server เพียงตัวเดียว

Control server คือส่วนที่ทำหน้าที่ระบุว่าใครบ้างที่อยู่ในเครือข่าย โดยจะแจกจ่ายที่อยู่จาก 100.64.0.0/10 ให้กับแต่ละโหนด กระจาย public key และบอกโหนดต่างๆ ว่าจะพบกันที่ไหน อุโมงค์เชื่อมต่อยังคงเป็น WireGuard ที่สร้างขึ้นระหว่างโหนดต่อโหนด การรับส่งข้อมูลระหว่างเครื่องของคุณสองเครื่องจะไม่ผ่านเครื่องที่รัน headscale เว้นแต่ว่าจะไม่สามารถสร้างเส้นทางตรงได้และโหนดต้องเปลี่ยนไปใช้ relay การทำหน้าที่ประสานงานด้วยตนเองเป็นการเปลี่ยนผู้ถือครองสิทธิ์ ไม่ใช่เปลี่ยนความสามารถของระบบ ดังนั้นจึงควรทำความเข้าใจ สิ่งที่ control server สามารถเข้าถึงได้และไม่ได้ในโมเดลนี้ ก่อนที่จะมองว่าการย้ายมาใช้ระบบนี้เป็นชัยชนะด้านความปลอดภัยเพียงอย่างเดียว

Headscale รองรับหนึ่ง tailnet (เครือข่าย Tailscale หนึ่งเครือข่าย) ต่อหนึ่งอินสแตนซ์ ซึ่งโครงการระบุว่าเหมาะสำหรับการใช้งานส่วนตัวหรือองค์กรขนาดเล็ก หากมีเครื่องเพียง 3 หรือ 4 เครื่อง การใช้ WireGuard VPN แบบปกติบน VPS ของคุณเอง จะเป็นซอฟต์แวร์ที่จัดการน้อยกว่าและมีโอกาสพังน้อยกว่า Headscale จะคุ้มค่าเมื่อคุณไม่ต้องการเขียนบล็อก [Peer] ด้วยตนเองสำหรับแล็ปท็อปเครื่องใหม่ทุกเครื่อง ค่าใช้จ่ายมักเป็นเหตุผลแรกที่ทำให้คนมองหาทางเลือกอื่น ดังนั้นจึงควรศึกษา สิ่งที่แผนฟรีของบริการโฮสต์ครอบคลุมจริง ก่อนที่จะตัดสินใจรันเซิร์ฟเวอร์เอง เพราะอุปกรณ์ส่วนตัวจำนวนไม่กี่เครื่องมักจะใช้งานได้ฟรีอยู่แล้ว หากคุณมีจำนวนอุปกรณ์เกินขีดจำกัดนั้น ให้ลองคำนวณเทียบกับ ราคาของแผนชำระเงิน ซึ่งคิดตามรายผู้ใช้ไม่ใช่รายอุปกรณ์ เพราะการใช้งานในครัวเรือนภายใต้บัญชีเดียวอาจมีราคาถูกกว่ามากแม้จำนวนอุปกรณ์จะเพิ่มขึ้น หากคุณต้องการ control plane แบบ self-hosted แต่ต้องการไคลเอนต์ของตนเองและมีเว็บอินเทอร์เฟซสำหรับจัดการ peer แทนที่จะเป็นตัวแทนที่ใช้งานแทน Tailscale ได้ทันที NetBird บน VPS เดียว เป็นทางเลือกที่น่าพิจารณา สำหรับการเปรียบเทียบเชิงลึกระหว่างสองโมเดลนี้ โปรดดู ความแตกต่างระหว่าง WireGuard และ Tailscale

สิ่งที่ต้องเตรียมก่อนการติดตั้ง

  • VPS ที่รัน Ubuntu 24.04 พร้อม public IPv4 address และสิทธิ์ sudo หากเป็นเซิร์ฟเวอร์ใหม่ ให้ดำเนินการตาม สิบนาทีแรกบน VPS ใหม่ ให้เรียบร้อยก่อน
  • DNS A record ที่ชี้ไปยัง address ดังกล่าว คู่มือนี้ใช้ headscale.example.com
  • โดเมนหรือ subdomain ที่สองสำหรับ 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 ไว้ให้ โดยจะ ไม่ สั่งเริ่มการทำงานของ service ทันที ซึ่งเป็นลำดับขั้นตอนที่ถูกต้องแล้ว ไฟล์คอนฟิกูเรชันที่มาพร้อมกับแพ็กเกจจะชี้ server_url ไปที่ http://127.0.0.1:8080 ซึ่งไม่ใช่ที่อยู่ที่จะเข้าถึงได้จากไคลเอนต์ของคุณ ดังนั้นหากสั่งเริ่ม service ในตอนนี้ก็จะทำงานผิดพลาดแม้ว่า service จะรันขึ้นมาได้ก็ตาม การรันคำสั่ง sudo systemctl is-active headscale ในขั้นตอนนี้จะแสดงผล inactive ซึ่งเป็นเรื่องปกติ ไม่ใช่ข้อผิดพลาดแต่อย่างใด

กำหนดค่า server_url ก่อนเริ่มการทำงานของ service

แก้ไข /etc/headscale/config.yaml ด้วย sudo nano /etc/headscale/config.yaml หรือใช้การเปลี่ยนแปลงทั้ง 3 จุดด้วย 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 จะเขียนลงในการลงทะเบียนของไคลเอนต์ทุกเครื่อง ไคลเอนต์จะเชื่อมต่อไปยังสตริงนั้นตลอดไป ดังนั้นต้องเป็นชื่อสาธารณะที่ขึ้นต้นด้วย https:// เท่านั้น ห้ามใช้ 127.0.0.1

listen_addr คือตำแหน่งที่ process จะผูกพอร์ตไว้ ให้คงค่าเป็น loopback ไว้ตามเดิม โดยให้ reverse proxy ที่อยู่บนเครื่องเดียวกันทำหน้าที่จัดการ TLS (transport layer security) และส่งต่อคำขอเข้ามา ดังนั้นจึงไม่มีความจำเป็นที่บริการภายนอกจะต้องเข้าถึงพอร์ต 8080 โดยตรง

base_domain คือ suffix ของ MagicDNS ซึ่งเป็นโดเมนที่โหนดของคุณจะได้รับชื่อภายใต้โดเมนนั้น โดยต้องเป็น fully qualified domain name ที่ไม่มีจุดปิดท้าย และต้องเป็นโดเมนที่แตกต่างจากที่ระบุใน server_url มิฉะนั้น namespace ทั้งสองจะเกิดการทับซ้อนกัน

ไม่ต้องแก้ไขส่วนของฐานข้อมูล ค่าเริ่มต้นคือ 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/health

is-active จะแสดงผล active และ curl จะแสดงผล 200 ส่วน enable --now ทำหน้าที่ทั้งสองอย่างพร้อมกัน คือเริ่มการทำงานของ service และกำหนดให้ service เริ่มทำงานโดยอัตโนมัติหลังจากรีบูตเครื่อง

หาก is-active แสดงผล failed ให้ตรวจสอบ log ด้วย sudo journalctl -u headscale -n 50 --no-pager ความล้มเหลวในขั้นตอนนี้มักเกิดจากไฟล์ configuration เป็นหลัก เนื่องจาก headscale จะอ่านไฟล์ทั้งหมดก่อนที่จะเปิด socket ดังนั้นการย่อหน้าผิดหรือการใช้ key ที่ไม่รู้จักจะทำให้กระบวนการหยุดทำงานก่อนที่จะเริ่มรับการเชื่อมต่อ ให้แก้ไขไฟล์แล้วใช้ sudo systemctl restart headscale การเปลี่ยนแปลง configuration ในภายหลังทั้งหมดจำเป็นต้องรีสตาร์ทด้วยวิธีเดียวกันนี้ โดย client จะเชื่อมต่อใหม่โดยอัตโนมัติหลังจากนั้น หากคุณยังไม่คุ้นเคยกับ systemd สามารถศึกษาคำสั่งที่ใช้ในที่นี้ได้จาก การรัน service และ timer ของคุณเองด้วย systemd

ตรวจสอบไฟล์สถานะในขณะที่คุณยังอยู่ใน shell:

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

ทั้งสองบรรทัดเริ่มต้นด้วย headscale ซึ่งเป็นผู้ใช้ที่ไม่มีสิทธิ์ (unprivileged user) ที่แพ็กเกจสร้างขึ้น ส่วน noise_private.key คือตัวตนของเซิร์ฟเวอร์ที่ใช้สื่อสารกับ client ให้เก็บไฟล์นี้ไว้ หากคุณลบไฟล์นี้ headscale จะสร้างไฟล์ใหม่ขึ้นมา และ node ทุกตัวจะต้องทำการลงทะเบียนใหม่ทั้งหมด

การวาง 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 caddy

validate จะแสดง adapted config to JSON หากไฟล์ถูกวิเคราะห์ไวยากรณ์ได้ถูกต้อง คำเตือนเรื่องรูปแบบไฟล์ที่ไม่เป็นระเบียบเป็นเพียงเรื่องความสวยงามเท่านั้น จากแล็ปท็อปของคุณ คำสั่ง curl -sS -o /dev/null -w '%{http_code}\\n' https://headscale.example.com/health ควรแสดงผลลัพธ์เป็น 200 เช่นกัน การตรวจสอบเพียงขั้นตอนเดียวนี้เป็นการพิสูจน์ว่า DNS, ไฟร์วอลล์, ใบรับรอง และพร็อกซีทำงานร่วมกันได้อย่างถูกต้อง

นี่คือรายละเอียดของพร็อกซีที่มักทำให้ผู้ใช้งานเสียเวลาไปทั้งคืน การเชื่อมต่อควบคุมของ Tailscale เป็นการทำ HTTP upgrade ซึ่งเริ่มต้นด้วยเมธอด POST แทนที่จะเป็น GET และค่าของเฮดเดอร์ Upgrade คือ tailscale-control-protocol โดย Caddy จะส่งผ่านค่านี้ไปโดยไม่ต้องตั้งค่าเพิ่มเติม แต่ nginx ไม่ได้ทำเช่นนั้น ดังนั้น nginx ที่ทำหน้าที่เป็น front end จึงจำเป็นต้องมีการกำหนด upgrade map ดังนี้:

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 ดังนั้น proxy จะเข้าถึง headscale ผ่าน loopback interface โดยไม่ผ่านกฎของ firewall การเปิดพอร์ต 8080 สู่สาธารณะจะทำให้ไคลเอนต์สื่อสารผ่านช่องทางควบคุมแบบ cleartext ซึ่งไม่มีประโยชน์ใดๆ โปรดทราบว่าผู้ให้บริการส่วนใหญ่มี firewall ชั้นที่สองใน control panel ซึ่งแยกจาก UFW ดังนั้นพอร์ตอาจเปิดอยู่บนเซิร์ฟเวอร์แต่ยังคงถูกปิดที่ระดับเครือข่ายภายนอก พื้นฐานการใช้งาน UFW firewall บน VPS อธิบายไวยากรณ์ของกฎเหล่านี้ไว้โดยละเอียด

การสร้างผู้ใช้และ preauth key

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 key เป็นคีย์ที่ใช้ได้ครั้งเดียวและมีอายุการใช้งานหนึ่งชั่วโมงหากคุณไม่ได้กำหนดเป็นอย่างอื่น ดังนั้นการตั้งค่า --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 ทุกประการ รวมถึง 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 จะเหมาะสมกว่าสำหรับงานที่ทำผ่านสคริปต์ เนื่องจากไม่จำเป็นต้องมีคนคอยเฝ้าดู เมื่อ VPS กลายเป็นโหนดหนึ่งในเครือข่ายแล้ว มันยังสามารถทำหน้าที่ส่งผ่านทราฟฟิกอินเทอร์เน็ตให้กับเครื่องอื่นๆ ของคุณได้ ซึ่งเรียกว่า การตั้งค่า exit node โดยมีความแตกต่างเพียงจุดเดียวคือ คุณต้องอนุมัติเส้นทางที่ประกาศไว้บนเซิร์ฟเวอร์ด้วยคำสั่ง headscale แทนที่จะทำผ่านคอนโซลผู้ดูแลระบบแบบ hosted หากสิ่งที่คุณต้องการคือการเข้าถึงเครือข่ายส่วนตัวที่อยู่หลัง VPS นั้น แทนที่จะเป็นการออกสู่อินเทอร์เน็ต ขั้นตอนการอนุมัติแบบเดียวกันนี้จะครอบคลุมถึง การประกาศ subnet นั้นให้กับ tailnet ของคุณ การเผยแพร่แอปพลิเคชันจากโหนดเดียว แทนที่จะเป็นการกำหนดเส้นทางผ่านเครือข่ายทั้งหมดนั้นเป็นงานที่ต่างออกไป และ serve และ funnel คือสองวิธีในการทำสิ่งนี้ แม้ว่าทั้งสองวิธีจะพึ่งพากลไก certificate และ ingress ของ Tailscale เอง ดังนั้นให้ทำความเข้าใจว่าเป็นฟีเจอร์ของ hosted-tailnet มากกว่าจะเป็นสิ่งที่ headscale จัดเตรียมไว้ให้คุณโดยตรง

DERP และสิ่งที่ทำหน้าที่ส่งต่อทราฟฟิกเมื่อเส้นทางตรงล้มเหลว

DERP (designated encrypted relay for packets) คือเส้นทางสำรอง เมื่อโหนดสองโหนดไม่สามารถเปิดการเชื่อมต่อ WireGuard แบบตรงได้ ซึ่งมักเกิดจากทั้งสองโหนดอยู่หลัง NAT (network address translation) ที่เข้มงวด โหนดเหล่านั้นจะส่งแพ็กเก็ตผ่าน relay แทน ตัว relay จะไม่มีคีย์ใดๆ จึงไม่สามารถอ่านทราฟฟิกของคุณได้ แต่จะเห็นว่าโหนดใดกำลังสื่อสารกันและมีการรับส่งข้อมูลมากน้อยเพียงใด

โปรดทำความเข้าใจให้ชัดเจนว่าการตั้งค่าเริ่มต้นทำงานอย่างไร Headscale ถูกกำหนดค่ามาให้ชี้ไปที่ https://controlplane.tailscale.com/derpmap/default โดยใช้ auto_update_enabled: true และ update_frequency: 3h ดังนั้น control plane จึงเป็นของคุณในขณะที่ relay เป็นของ Tailscale สำหรับคนส่วนใหญ่ถือเป็นการแลกเปลี่ยนที่ยอมรับได้ หากคุณไม่ต้องการเช่นนั้น คุณสามารถรัน relay ของคุณเองได้

ในการรัน relay ของคุณเอง ให้ตั้งค่า 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 ว่างเปล่าจะเป็นการลบ relay ของ Tailscale ออกจากแผนผัง และหากคุณทำเช่นนั้นโดยไม่มี relay ที่ฝังตัวทำงานอยู่ โหนดคู่ใดก็ตามที่ไม่สามารถเชื่อมต่อกันโดยตรงได้ จะไม่สามารถเชื่อมต่อกันได้เลย

จาก client, tailscale netcheck จะแสดง latency ไปยังแต่ละ relay region ที่ client รู้จัก และ tailscale status จะระบุ peer แต่ละรายการว่าเป็น direct พร้อม address หรือเป็น relay พร้อม region code หาก peer ค้างอยู่ที่ relay แสดงว่าเป็นปัญหา NAT ไม่ใช่ปัญหาของ headscale ส่วน peer ที่เป็น direct แต่ยังทำงานช้า เป็นอีกประเด็นหนึ่ง และ โดยทั่วไปสาเหตุคือ MTU ไม่ใช่ตัว tunnel เอง

เหตุใดโหนดจึงแสดงสถานะเป็นออฟไลน์?

Proxy ปฏิเสธการอัปเกรด นี่เป็นสาเหตุที่พบบ่อยที่สุด โดยมีลักษณะคือทุกอย่างดูปกติ: /health ส่งค่ากลับเป็น 200, headscale nodes list แสดงชื่อโหนด แต่โหนดไม่เคยออนไลน์ การเชื่อมต่อควบคุมเป็นแบบ POST ที่ส่ง Upgrade: tailscale-control-protocol หาก proxy ไม่ส่งต่อคำขอนี้ ช่องทางเดียวที่ใช้รายงานสถานะโหนดจะถูกตัดขาด ให้เปรียบเทียบการตั้งค่า nginx ของคุณกับบล็อก map ด้านบน หรือเปลี่ยนไปใช้ Caddy เพื่อตรวจสอบว่าปัญหาเกิดจาก proxy หรือไม่

server_url เปลี่ยนแปลงหลังจากโหนดลงทะเบียนแล้ว โหนดจะพยายามเชื่อมต่อด้วยค่าที่ได้รับตอนลงทะเบียน หากคุณแก้ไขค่าดังกล่าว ให้รัน sudo tailscale up --login-server https://headscale.example.com --force-reauth บนโหนดแต่ละตัว

Client ไม่ได้ทำงานอยู่ บนโหนด ให้ตรวจสอบ sudo systemctl is-active tailscaled และ sudo journalctl -u tailscaled -n 50 --no-pager หาก client ไม่สามารถ resolve หรือเข้าถึงโดเมนของคุณได้ จะมีการบันทึกการพยายามเชื่อมต่อใหม่ไว้ใน log

Key หมดอายุ รายละเอียดอยู่ในหัวข้อถัดไป

หากต้องการตรวจสอบฝั่งเซิร์ฟเวอร์ในระหว่างการทดสอบ ให้รัน sudo journalctl -u headscale -f บน VPS และรีสตาร์ท tailscaled บนฝั่ง client โหนดที่เข้าถึง headscale ได้จะแสดงบรรทัด log ออกมาทันที หากไม่มีข้อความใดปรากฏ แสดงว่าคำขอส่งมาไม่ถึง ให้ตรวจสอบ DNS, firewall และ proxy ก่อนที่จะตรวจสอบ headscale

การหมดอายุของคีย์ และโหนดที่หยุดทำงานในอีกหลายสัปดาห์ต่อมา

มีการหมดอายุอยู่สองประเภทที่แยกจากกัน การสับสนระหว่างสองสิ่งนี้ทำให้เสียเวลาโดยเปล่าประโยชน์

Preauth keys ถูกออกแบบมาให้หมดอายุอย่างรวดเร็ว ค่าเริ่มต้นคือหนึ่งชั่วโมงและใช้งานได้เพียงครั้งเดียว หาก tailscale up ปฏิเสธคีย์ดังกล่าว ให้สร้างคีย์ใหม่บนเซิร์ฟเวอร์แทนการแก้ไขค่าใดๆ บนฝั่งไคลเอนต์

Node keys คือส่วนที่มีอายุการใช้งานยาวนาน ส่วน 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

ย้ายไฟล์ทั้งสองออกจากเซิร์ฟเวอร์ ไฟล์เหล่านี้ประกอบด้วย private key และข้อมูลการลงทะเบียนทั้งหมด จึงควรได้รับการดูแลเช่นเดียวกับตัวเซิร์ฟเวอร์เอง การสำรองข้อมูลด้วย restic จาก VPS ครอบคลุมวิธีการทำสิ่งนี้ตามกำหนดเวลาและมีการเข้ารหัส

การอัปเกรดให้ทำซ้ำขั้นตอนการติดตั้ง: ดาวน์โหลด .deb และ sudo apt install ./headscale.deb เวอร์ชันใหม่ จากนั้นรีสตาร์ทและรันการตรวจสอบด้วย is-active และ /health อีกครั้ง ตั้งแต่เวอร์ชัน 0.29 เป็นต้นมา เส้นทางการอัปเกรดมีความเข้มงวด การข้ามเวอร์ชันย่อย (minor version) จะถูกบล็อก รวมถึงการดาวน์เกรดไปยังเวอร์ชันย่อยที่เก่ากว่าด้วย ให้ดำเนินการทีละเวอร์ชันย่อย สำรองข้อมูลก่อนเริ่มแต่ละขั้นตอน และอ่านบันทึกประจำรุ่น (release notes) ของเวอร์ชันนั้นก่อนเสมอ เนื่องจากรุ่นเดียวกันอาจมีการเปลี่ยนแปลงพฤติกรรมของนโยบาย ACL และมีการย้าย configuration key หลายรายการ

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 และคุณต้องชี้การเชื่อมต่อไปยังเซิร์ฟเวอร์ของคุณด้วย sudo tailscale up --login-server https://headscale.example.com แฟล็กนี้มีอยู่ใน client มาตรฐานอยู่แล้ว จึงไม่จำเป็นต้องแก้ไขหรือคอมไพล์โปรแกรมใหม่

ทราฟฟิกของฉันจะผ่านเซิร์ฟเวอร์ headscale หรือไม่?

โดยปกติแล้วไม่ headscale ทำหน้าที่ประสานงานเครือข่ายและแจกจ่ายคีย์รวมถึงที่อยู่ IP ในขณะที่เส้นทางข้อมูลจะเป็น WireGuard ระหว่างโหนดของคุณโดยตรง ทราฟฟิกจะอ้อมผ่านเซิร์ฟเวอร์ก็ต่อเมื่อโหนดสองโหนดไม่สามารถเชื่อมต่อกันโดยตรงและต้องถอยกลับไปใช้ DERP relay ซึ่งในการตั้งค่าเริ่มต้น relay เหล่านี้จะเป็นของสาธารณะจาก Tailscale ให้รัน tailscale status บนโหนดเพื่อดูว่า peer ที่กำหนดนั้นเป็น direct หรืออยู่บน relay

ทำไมโหนดของฉันถึงยังคงออฟไลน์หลังจากลงทะเบียนแล้ว?

โหนดที่ปรากฏใน headscale nodes list แต่ไม่เคยออนไลน์ มักเกิดจากการสูญเสียการเชื่อมต่อควบคุมที่ reverse proxy การเชื่อมต่อดังกล่าวคือ HTTP upgrade ที่ส่งผ่าน POST พร้อม header 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 ทุกเครื่องถูกส่งผ่านอินเทอร์เน็ตโดยไม่มีการเข้ารหัส