SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-11-01

آموزش راه‌اندازی Headscale به عنوان سرور کنترل Tailscale

با نصب Headscale روی VPS، کنترل کامل شبکه خصوصی خود را در دست بگیرید. این راهنما نحوه نصب فایل .deb، تنظیم server_url و اتصال اولین نود به سرور شخصی را شرح می‌دهد.

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

Headscale چیست

Headscale یک پیاده‌سازی خودمیزبان (self-hosted) از سرور کنترل Tailscale است؛ بنابراین ماشینی که شبکه خصوصی شما را هماهنگ می‌کند، یک VPS تحت مالکیت خودتان است. این یک پروژه جامعه‌محور است و توسط شرکت Tailscale Inc اداره نمی‌شود. هر ماشین همچنان کلاینت رسمی tailscale را اجرا می‌کند که با استفاده از یک فلگ، یعنی --login-server، به سرور شما اشاره می‌کند.

سرور کنترل بخشی است که می‌داند چه کسی عضو شبکه است. این سرور به هر گره (node) یک آدرس از محدوده 100.64.0.0/10 اختصاص می‌دهد، کلیدهای عمومی را توزیع می‌کند و به گره‌ها می‌گوید که یکدیگر را کجا پیدا کنند. تونل‌ها همچنان WireGuard باقی می‌مانند که به‌صورت گره‌به‌گره ایجاد می‌شوند. ترافیک بین دو ماشین شما از طریق سرور Headscale عبور نمی‌کند، مگر اینکه امکان ایجاد مسیر مستقیم وجود نداشته باشد و گره‌ها به یک رله (relay) متوسل شوند. اجرای این نقش هماهنگ‌کننده توسط خودتان، صرفاً تغییردهنده مسئولیت آن است، نه قابلیت‌های آن؛ بنابراین پیش از آنکه این جابجایی را به‌تنهایی یک دستاورد امنیتی تلقی کنید، درک اینکه یک سرور کنترل در این مدل به چه چیزی دسترسی دارد و به چه چیزی ندارد ضروری است.

Headscale در هر instance یک tailnet (یک شبکهٔ Tailscale) ارائه می‌کند و پروژه آن را برای استفادهٔ شخصی یا یک سازمان کوچک مناسب می‌داند. با سه یا چهار ماشین، یک VPN سادهٔ WireGuard روی VPS تحت مالکیت شما نرم‌افزار کمتری برای اجرا و موارد کمتری برای خرابی دارد. Headscale زمانی ارزش خود را نشان می‌دهد که دیگر نخواهید برای هر laptop جدید، یک بلوک [Peer] را دستی بنویسید. هزینه معمولاً یکی از دلایلی است که افراد ابتدا به بررسی این گزینه روی می‌آورند؛ بنابراین پیش از پذیرش مسئولیت یک server، بهتر است بررسی کنید پلن رایگان میزبانی‌شده در عمل چه مواردی را پوشش می‌دهد، زیرا چند ماشین شخصی معمولاً در محدودهٔ آن قرار می‌گیرد. اگر از این سقف عبور کرده‌اید، هزینه را با هزینهٔ پلن‌های پولی به‌ازای هر user و هر resource دارای tag مقایسه کنید، زیرا تعداد deviceهای user نامحدود است، اما resourceهای دارای tag سهمیه‌ها و هزینه‌های جداگانه دارند. اگر control plane خودمیزبان می‌خواهید، اما ترجیح می‌دهید به‌جای جایگزینی مستقیم برای Tailscale، client اختصاصی و web interface برای مدیریت peerها داشته باشید، NetBird روی یک VPS گزینهٔ جایگزینی است که باید بررسی شود. هر دو گزینه ترافیک شما را از طریق WireGuard منتقل می‌کنند؛ بنابراین انتخاب به نحوهٔ نوشتن ruleهای دسترسی و رفتار relayها بستگی دارد و پیش از نصب هرکدام، مقایسهٔ NetBird و Tailscale از این جنبه‌ها ارزشمند است. برای مقایسهٔ گسترده‌تر این دو مدل، تفاوت WireGuard و Tailscale را ببینید.

پیش‌نیازهای پیش از نصب

  • یک سرور مجازی (VPS) با سیستم‌عامل Ubuntu 24.04 که دارای آدرس IPv4 عمومی و دسترسی sudo باشد. اگر سرور جدید است، ابتدا مراحل ده دقیقه اول روی یک سرور مجازی جدید را انجام دهید.
  • یک رکورد DNS از نوع A که به آن آدرس اشاره کند. این راهنما از headscale.example.com استفاده می‌کند.
  • یک دامنه یا زیردامنه دوم برای MagicDNS. این راهنما از tailnet.example.net استفاده می‌کند. این دامنه نباید با دامنه‌ای که در server_url استفاده شده، یکسان باشد.
  • یک دستگاه کلاینت برای اتصال، که سیستم‌عامل آن Linux، macOS، Windows، Android یا iOS باشد. نسخه 0.29.6 از Headscale به کلاینت Tailscale نسخه 1.80.0 یا جدیدتر نیاز دارد.

نصب headscale از طریق فایل .deb رسمی

این پروژه بسته‌های .deb را در صفحه GitHub releases خود منتشر می‌کند. تا تاریخ 27 اکتبر 2026، آخرین نسخه پایدار 0.29.6 است که در 24 اکتبر 2026 منتشر شده است. ابتدا معماری سیستم خود را بررسی کنید، زیرا نام فایل به آن بستگی دارد.

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

این دستور در یک VPS معمولی x86 عبارت amd64 و در پلن‌های نوع Ampere یا Graviton عبارت arm64 را چاپ می‌کند. پاسخ را در متغیر زیر قرار دهید.

HEADSCALE_VERSION="0.29.6"
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 پیش‌فرض می‌نویسد، یک unit برای systemd نصب می‌کند و سپس سرویس را اجرا می‌نماید. بنابراین، هنگامی که apt به پایان می‌رسد، headscale در حال اجرا است و sudo systemctl is-active headscale عبارت active را چاپ می‌کند. با این حال، در یک نصب تازه، بسته unit را فعال (enable) نمی‌کند؛ بنابراین سرویس پس از reboot بالا نمی‌آید مگر اینکه آن را فعال کنید، که در مرحله restart زیر انجام می‌شود. سرویس همچنین با پیکربندی پیش‌فرض اجرا می‌شود که server_url را به http://127.0.0.1:8080 اشاره می‌دهد؛ این آدرسی نیست که کلاینت‌های شما بتوانند به آن دسترسی داشته باشند. هنوز چیزی در معرض دید قرار نگرفته است، زیرا listen_addr پیش‌فرض نیز روی loopback تنظیم شده است، اما تا زمانی که server_url را تنظیم نکرده و سرویس را restart نکرده‌اید (که در دو مرحله بعدی انجام می‌شود)، هیچ کلاینتی را به شبکه اضافه نکنید.

پیکربندی server_url پیش از اتصال هر کلاینت

فایل /etc/headscale/config.yaml را با استفاده از sudo 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 هنگام ساخت URLهای ثبت‌نام از آن استفاده می‌کند. کلاینت‌ها از آدرس کنترلی که با --login-server پیکربندی شده استفاده می‌کنند، بنابراین از همان نام عمومی با https:// در هر دو مکان استفاده کنید و هرگز از 127.0.0.1 استفاده نکنید. مستندات headscale بیان می‌کند که استفاده از HTTP ساده، یا HTTPS روی پورتی غیر از 443 ممکن است، اما برای محیط عملیاتی (production) اکیداً استفاده از HTTPS روی پورت 443 را توصیه می‌کند و باقی این راهنما نیز بر همین فرض استوار است.

listen_addr محلی است که پردازش روی آن bind می‌شود. آن را روی loopback باقی بگذارید. یک reverse proxy روی همان سرور، TLS (امنیت لایه انتقال) را خاتمه داده و درخواست‌ها را به آن هدایت می‌کند، بنابراین هیچ چیزی خارج از سرور نیازی به دسترسی به پورت 8080 ندارد.

base_domain پسوند MagicDNS است، دامنه‌ای که گره‌های شما تحت آن نام‌گذاری می‌شوند. این باید یک نام دامنه کاملاً واجد شرایط (FQDN) بدون نقطه در انتها باشد و باید با دامنه‌ای که در server_url قرار دارد متفاوت باشد، زیرا در غیر این صورت فضای نام این دو با هم تداخل پیدا می‌کنند.

بخش پایگاه داده را تغییر ندهید. مقدار پیش‌فرض SQLite در /var/lib/headscale/db.sqlite است، در دایرکتوری که توسط بسته ایجاد شده و مالکیت آن را در اختیار دارد؛ و SQLite برای یک tailnet با این ابعاد کافی است.

راه‌اندازی مجدد headscale و اطمینان از اجرای آن

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

is-active عبارت active، is-enabled عبارت enabled و curl عبارت 200 را چاپ می‌کند. راه‌اندازی مجدد (restart) مرحله‌ای است که تغییرات شما را بارگذاری می‌کند. headscale فایل پیکربندی خود را تنها یک‌بار، هنگام شروع به کار، می‌خواند؛ بنابراین فرآیندی که توسط بسته (package) آغاز شده است، تا زمانی که آن را restart نکنید، به استفاده از server_url پیش‌فرض ادامه می‌دهد. sudo systemctl enable --now headscale این وظیفه را انجام نمی‌دهد: سرویس از قبل در حال اجرا است، بنابراین دستور --now تغییری ایجاد نمی‌کند و مقدار قدیمی همچنان فعال می‌ماند. شروع به کار در زمان بوت وظیفه enable است و این کار به‌صورت خودکار برای شما انجام نمی‌شود: در یک نصب تازه، بسته سرویس را بدون فعال‌سازی شروع می‌کند، پس همان‌طور که در بالا گفته شد، یک‌بار دستور sudo systemctl enable headscale را اجرا کنید.

اگر is-active خروجی غیر از active نشان داد، یا curl عبارت 200 را چاپ نکرد، لاگ‌های سیستم را با sudo journalctl -u headscale -n 50 --no-pager بخوانید. شکست در این مرحله تقریباً همیشه به دلیل فایل پیکربندی است، زیرا headscale پیش از باز کردن سوکت، کل فایل را تجزیه (parse) می‌کند؛ بنابراین یک تورفتگی اشتباه یا یک تنظیم الزامی نامعتبر، فرآیند را پیش از آنکه سرویس روی پورتی گوش دهد، متوقف می‌کند. فایل را اصلاح کرده و سپس sudo systemctl restart headscale را اجرا کنید. هر تغییر پیکربندی در آینده به همین راه‌اندازی مجدد نیاز دارد. کلاینت‌ها پس از آن به‌طور خودکار دوباره متصل می‌شوند. اگر با unitهای systemd آشنا نیستید، اجرای سرویس‌ها و تایمرهای شخصی با systemd دستورات استفاده‌شده در اینجا را پوشش می‌دهد.

در حالی که در shell هستید، فایل‌های وضعیت را بررسی کنید:

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

هر دو خط با headscale شروع می‌شوند که همان کاربر بدون دسترسی ریشه (unprivileged) است که بسته ایجاد کرده است. noise_private.key هویت سرور برای کلاینت‌های آن است. آن را حفظ کنید. اگر آن را حذف کنید، headscale یک کلید جدید تولید می‌کند و کلاینت‌ها باید پیش از اتصال مجدد، کلید جدید سرور را دریافت کنند؛ ثبت‌نام‌های موجود در پایگاه داده باقی می‌مانند.

قرار دادن TLS در مقابل headscale

کلاینت‌ها باید از طریق 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 upgrade است؛ این اتصال با یک POST به جای GET شروع می‌شود و مقدار هدر Upgrade برابر با tailscale-control-protocol است. Caddy این مورد را بدون پیکربندی اضافی عبور می‌دهد. اما nginx این کار را انجام نمی‌دهد، بنابراین یک front end از نوع nginx باید هدرهای Upgrade و Connection را به‌طور صریح فوروارد کند. مستندات headscale این کار را با یک 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 تمام اتصالات کنترلی کلاینت‌ها به headscale را منتقل می‌کند. اگر بعداً relay داخلی DERP را فعال کنید، به پورت 3478/udp نیز نیاز خواهید داشت که در ادامه به آن پرداخته شده است. پورت 80 برای چالش HTTP در ACME (محیط مدیریت خودکار گواهی) و هدایت (redirect) به HTTPS در نظر گرفته شده است. Caddy همچنان می‌تواند با بسته بودن پورت 80 گواهی دریافت کند، زیرا قادر است از چالش TLS-ALPN روی پورت 443 استفاده کند؛ اما با باز بودن پورت 80، هر دو چالش در دسترس خواهند بود و درخواست‌های ساده http:// به HTTPS هدایت می‌شوند.

پورت 8080 باید بسته بماند. listen_addr به صورت 127.0.0.1:8080 است، بنابراین پروکسی از طریق رابط loopback به headscale دسترسی پیدا می‌کند و هیچ قانون فایروالی در این میان دخیل نیست. باز کردن پورت 8080 در UFW هیچ چیزی را در معرض خطر قرار نمی‌دهد، زیرا هیچ سرویسی از بیرون روی آن گوش نمی‌دهد و هیچ مزیتی هم ندارد. به خاطر داشته باشید که اکثر ارائه‌دهندگان، یک فایروال دوم در پنل مدیریتی خود دارند که از UFW جداست؛ بنابراین ممکن است یک پورت روی سرور باز باشد اما در لبه شبکه (edge) همچنان بسته بماند. اصول فایروال UFW در VPS سینتکس قوانین را با جزئیات بیشتری بررسی می‌کند.

ایجاد یک کاربر و کلید پیش‌احراز هویت (preauth key)

sudo headscale users create alice
sudo headscale users list

دستور headscale یک کلاینت است. این دستور از طریق سوکت یونیکس در مسیر /var/run/headscale/headscale.sock با دیمون در حال اجرا ارتباط برقرار می‌کند؛ این سوکت دارای دسترسی 0770 بوده و مالکیت آن در اختیار گروه headscale است. دو نکته از این موضوع استنتاج می‌شود: اول اینکه این دستور در زمانی که سرویس متوقف است با خطا مواجه می‌شود (که دلیل دیگری برای اهمیت ترتیب مراحل در این راهنماست)، و دوم اینکه برای اجرای آن به sudo نیاز دارید، مگر اینکه حساب کاربری خود را به گروه headscale اضافه کنید.

دستور users list یک شناسه (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، کاربر و وضعیت آنلاین بودن آن نمایش می‌دهد.

از آدرس HTTPS عمومی که در server_url آمده است برای --login-server استفاده کنید. کلاینت به‌طور خودکار اسلش‌های انتهایی را از URL کنترل حذف می‌کند؛ بنابراین نیازی به رعایت دقیق این مورد در رشته ورودی نیست.

ماشینی که قبلاً به سرویس میزبانی‌شده Tailscale متصل بوده، همان لاگین را حفظ می‌کند. ابتدا روی آن sudo tailscale logout را اجرا کنید و سپس tailscale up را با --login-server به کار ببرید.

اگر --auth-key را حذف کنید، کلاینت یک 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 دو روش برای انجام این کار هستند؛ اگرچه هر دو به گواهی و مکانیزم ورودی (ingress) خودِ Tailscale متکی هستند، بنابراین آن‌ها را به عنوان ویژگی‌های tailnet میزبانی‌شده در نظر بگیرید، نه چیزی که headscale مستقیماً در اختیار شما قرار می‌دهد.

DERP و آنچه ترافیک را هنگام شکست مسیر مستقیم رله می‌کند

DERP (مخفف designated encrypted relay for packets) مسیر جایگزین (fallback) است. زمانی که دو گره نمی‌توانند یک اتصال مستقیم WireGuard برقرار کنند، معمولاً به این دلیل که هر دو پشت NAT (ترجمه آدرس شبکه) سخت‌گیرانه قرار دارند، بسته‌ها را از طریق یک رله ارسال می‌کنند. رله هیچ کلیدی در اختیار ندارد، بنابراین نمی‌تواند ترافیک شما را بخواند. رله فقط می‌بیند که کدام گره‌ها با هم در ارتباط هستند و چه حجمی از داده جابه‌جا می‌شود.

در مورد عملکرد پیکربندی پیش‌فرض شفاف باشید. Headscale به‌صورت پیش‌فرض به https://controlplane.tailscale.com/derpmap/default با auto_update_enabled: true و update_frequency: 3h اشاره می‌کند، بنابراین کنترل پلین (control plane) متعلق به شماست اما رله‌ها متعلق به Tailscale هستند. برای اکثر افراد این یک معامله منصفانه است. اگر برای شما این‌طور نیست، رله خودتان را اجرا کنید.

برای اجرای رله اختصاصی، enabled: true را در بخش derp.server در فایل config.yaml تنظیم کنید، ipv4: 198.51.100.1 و ipv6: 2001:db8::1 پیش‌فرض را با آدرس‌های عمومی رله خود جایگزین کنید، یا هر دو تنظیم را حذف کنید تا از DNS استفاده شود؛ سپس headscale را ری‌استارت کرده و پورت STUN (ابزارهای پیمایش نشست برای NAT) را با sudo ufw allow 3478/udp باز کنید. آن تنظیمات آدرس، DNS را نادیده می‌گیرند (override می‌کنند)، بنابراین باقی گذاشتن هر یک از مقادیر پیش‌فرض باعث می‌شود کلاینت‌ها به آدرسی غیرقابل‌دسترس هدایت شوند. فایل پیکربندی این الزام را به‌وضوح بیان می‌کند: server_url باید از https استفاده کند، زیرا DERP به TLS نیاز دارد. خالی کردن لیست derp.urls، رله‌های Tailscale را از نقشه حذف می‌کند؛ پیش از انجام این کار، مطمئن شوید یک رله داخلی یا سفارشی فعال دارید. Headscale در صورت خالی بودن نقشه رله‌ها اجرا نمی‌شود و نقشه‌ای که فقط شامل یک رله غیرقابل‌دسترس باشد، باعث می‌شود گره‌هایی که نمی‌توانند مستقیماً متصل شوند، قادر به برقراری ارتباط نباشند.

از سمت کلاینت، tailscale netcheck میزان تأخیر (latency) به هر منطقه رله‌ای که می‌شناسد را چاپ می‌کند و tailscale status برای اتصالات فعال همتا، direct را با یک آدرس یا relay را با یک کد منطقه نشان می‌دهد. همتایی که روی relay گیر کرده است، نیاز به بررسی مسیر مستقیم، شامل قوانین NAT و فایروال دارد. همتایی که direct است و همچنان سرعت پایینی دارد، موضوع متفاوتی است و پاسخ معمول در آنجا مربوط به MTU است تا خود تونل.

چرا یک گره (node) به صورت offline نمایش داده می‌شود؟

پراکسی درخواست ارتقا را مسدود می‌کند. نشانهٔ این وضعیت این است که /health کد 200 برمی‌گرداند، اما ثبت‌نام‌های جدید با شکست مواجه می‌شوند یا گره‌های موجود نمی‌توانند دوباره متصل شوند. اتصال کنترل یک درخواست POST است که حاوی Upgrade: tailscale-control-protocol می‌باشد؛ پراکسی که این درخواست را هدایت نکند، هم ثبت‌نام و هم کانالی که وضعیت گره را گزارش می‌دهد، مسدود می‌کند. پیکربندی nginx خود را با خطوط ارتقا در بالا مقایسه کنید یا برای اطمینان از عدم دخالت پراکسی، از Caddy استفاده کنید.

آدرس عمومی کنترل تغییر کرده است. گره‌ها همچنان به آدرسی متصل می‌شوند که با --login-server پیکربندی شده است؛ تغییر 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 را بررسی کنید. کلاینتی که نمی‌تواند دامنهٔ شما را Resolve کند یا به آن دسترسی یابد، تلاش‌های مجدد خود را در آنجا ثبت می‌کند.

کلید منقضی شده است. این مورد در بخش بعدی توضیح داده شده است.

برای نظارت بر سمت سرور در حین تست، دستور sudo journalctl -u headscale -f را روی VPS اجرا کرده و tailscaled را روی کلاینت restart کنید. ژورنال کلاینت را نیز بررسی کنید: رسیدن یک درخواست به headscale لزوماً به معنای ثبت یک خط در سطح لاگ پیش‌فرض نیست؛ بنابراین سکوت لاگ سرور به تنهایی ثابت‌کنندهٔ خرابی DNS، فایروال یا پراکسی نیست.

انقضای کلید و نودی که هفته‌ها بعد از کار می‌افتد

دو نوع انقضای مجزا وجود دارد و اشتباه گرفتن آن‌ها باعث اتلاف وقت می‌شود.

کلیدهای Preauth طبق طراحی، سریع منقضی می‌شوند. مقدار پیش‌فرض یک ساعت و یک‌بار استفاده است. اگر tailscale up کلید را نپذیرفت، به‌جای ویرایش هر چیزی در کلاینت، یک کلید جدید روی سرور تولید کنید.

کلیدهای Node بخش با عمر طولانی هستند. بخش node در config.yaml مقدار expiry: 0 را تعیین می‌کند و 0 به معنای عدم وجود انقضای پیش‌فرض است؛ با این حال، انقضای صریح کلاینت یا انقضای OIDC همچنان می‌تواند اعمال شود. نودهای دارای Tag از انقضای خودکار معاف هستند، اگرچه مدیر سیستم می‌تواند آن‌ها را به‌صورت دستی منقضی کند. اگر می‌خواهید برای ثبت‌نام‌های بدون Tag یک پیش‌فرض 180 روزه تعیین کنید، expiry: 180d را تنظیم کنید، اما انقضای درخواستی کلاینت اولویت دارد و OIDC می‌تواند مقدار پیش‌فرض را نادیده بگیرد. تغییر این تنظیمات، ثبت‌نام‌های موجود را به‌صورت عطف‌به‌ماسبق تغییر نمی‌دهد. نودی که دارای تاریخ انقضا است، پیش از رسیدن آن مهلت نیاز به احراز هویت مجدد با استفاده از sudo tailscale up --login-server https://headscale.example.com --force-reauth دارد و سرور بدون سری (headless) که کسی آن را مجدداً احراز هویت نکند، پس از انقضای ثبت‌نام از شبکه خارج خواهد شد.

هنگامی که شخصی لپ‌تاپ خود را گم می‌کند، این کار را به‌صورت دستی انجام دهید. sudo headscale nodes list شناسه (ID) را به شما می‌دهد، سپس sudo headscale nodes expire -i 3 آن نود را از سیستم خارج (log out) می‌کند و 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 به بعد، مسیر ارتقا سخت‌گیرانه است. پرش از یک نسخه فرعی (minor version) مسدود شده است و بازگشت به نسخه فرعی قدیمی‌تر نیز امکان‌پذیر نیست. هر بار فقط یک نسخه فرعی ارتقا دهید، پیش از هر مرحله یک نسخه پشتیبان تهیه کنید و ابتدا یادداشت‌های انتشار (release notes) همان نسخه را مطالعه کنید؛ زیرا در همان نسخه، رفتار سیاست‌های ACL تغییر کرده و چندین کلید پیکربندی جابه‌جا شده‌اند. نسخه 0.29.6 همچنین شامل به‌روزرسانی‌های امنیتی برای اعتبارسنجی گواهی‌ها و وابستگی‌ها است، بنابراین نصب‌های فعلی 0.29 باید این نسخه اصلاحی (patch release) را دریافت کنند.

FAQ

آیا headscale بلافاصله پس از نصب فایل .deb اجرا می‌شود؟

بله. این بسته به محض نصب، سرویس را روی /etc/headscale/config.yaml پیش‌فرض اجرا می‌کند که فقط روی loopback گوش می‌دهد و server_url را روی http://127.0.0.1:8080 تنظیم می‌کند. در نصب تازه، سرویس فعال نمی‌شود، بنابراین تا زمانی که sudo systemctl enable headscale را اجرا نکنید، در زمان بوت شروع نخواهد شد. آدرس پیش‌فرض برای کلاینت‌ها کاربردی ندارد، بنابراین server_url، listen_addr و base_domain را ویرایش کنید، سپس sudo systemctl restart headscale را اجرا کرده و با sudo systemctl is-active headscale تأیید کنید. این کار باید با restart انجام شود: headscale فایل را فقط هنگام شروع می‌خواند و enable --now روی سرویسی که در حال اجراست، آن را برای بوت فعال می‌کند اما ری‌استارت نمی‌کند، بنابراین مقادیر قدیمی همچنان فعال می‌مانند. اگر پس از ری‌استارت سرویس با خطا مواجه شد، sudo journalctl -u headscale -n 50 --no-pager مشکل را مشخص می‌کند؛ در این مرحله، خطا تقریباً همیشه یک خطای YAML است، زیرا headscale پیش از bind کردن پورت، کل فایل را پارس می‌کند.

آیا همچنان باید کلاینت معمولی Tailscale را روی دستگاه‌هایم نصب کنم؟

بله. Headscale فقط جایگزین سرور کنترل می‌شود. هر گره کلاینت رسمی Tailscale را اجرا می‌کند و شما با استفاده از sudo tailscale up --login-server https://headscale.example.com آن را به سرور خود متصل می‌کنید. این فلگ در کلاینت استاندارد وجود دارد، بنابراین نیازی به پچ کردن یا بازسازی چیزی نیست.

آیا ترافیک من از سرور headscale عبور می‌کند؟

معمولاً خیر. Headscale شبکه را هماهنگ کرده و کلیدها و آدرس‌ها را توزیع می‌کند، در حالی که مسیر داده‌ها مستقیماً از طریق WireGuard بین گره‌های شما برقرار است. ترافیک فقط زمانی مسیر انحرافی طی می‌کند که دو گره نتوانند مستقیماً به یکدیگر متصل شوند و به یک رله DERP متوسل شوند؛ در پیکربندی پیش‌فرض، این رله‌ها همان رله‌های عمومی Tailscale هستند. برای اینکه ببینید آیا یک همتا direct است یا روی relay قرار دارد، tailscale status را روی یک گره اجرا کنید.

چرا گره من پس از ثبت‌نام آفلاین می‌ماند؟

گره‌ای که در headscale nodes list ظاهر می‌شود اما آنلاین نمی‌شود، نیاز به بررسی اتصال کنترل، از جمله reverse proxy دارد. این اتصال یک HTTP upgrade است که به صورت POST با هدر Upgrade: tailscale-control-protocol ارسال می‌شود و nginx آن را رد می‌کند مگر اینکه هدرهای Upgrade و Connection را صراحتاً با proxy_set_header فوروارد کنید، که پیکربندی بالا این کار را از طریق بلاک map $http_upgrade $connection_upgrade انجام می‌دهد. حذف این هدرها همچنین مانع از ثبت‌نام گره‌های جدید می‌شود. Caddy این کار را بدون پیکربندی اضافی انجام می‌دهد، که آن را به روشی سریع برای تست اینکه آیا مشکل از پروکسی است یا خیر، تبدیل می‌کند.

آیا برای headscale به نام دامنه و TLS نیاز دارم؟

برای این سناریو، بله: از یک نام دامنه و HTTPS استفاده کنید. گواهی‌ها می‌توانند آدرس‌های IP خام را نیز پوشش دهند، اما فایل پیکربندی بیان می‌کند که DERP به TLS نیاز دارد. استفاده از یک دامنه به همراه Caddy حدود پنج دقیقه زمان می‌برد و یک endpoint با HTTPS به شما می‌دهد که به‌طور خودکار تمدید می‌شود. استفاده از HTTP ساده ممکن است، اما مستندات headscale اکیداً استفاده از HTTPS روی پورت 443 را برای محیط عملیاتی توصیه می‌کند و اشاره دارد که کلاینت Tailscale در شرایط خاصی HTTPS روی پورت 443 را فرض می‌گیرد.

آیا این مقاله مفید بود؟