SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-28

Headscale: Jalankan Server Kontrol Tailscale Sendiri

Pelajari cara menjalankan server kontrol Tailscale sendiri di VPS: pasang headscale dari .deb resmi, atur server_url sebelum memulai, lalu gabungkan node pertama.

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

Apa itu headscale

Headscale adalah implementasi self-hosted dari server kontrol Tailscale. Dengan demikian, mesin yang mengoordinasikan jaringan privat Anda adalah VPS milik Anda sendiri. Proyek ini dikembangkan oleh komunitas dan tidak dijalankan oleh Tailscale Inc. Setiap mesin tetap menjalankan client resmi tailscale, yang diarahkan ke server Anda menggunakan satu flag, --login-server.

Server kontrol adalah komponen yang mengetahui siapa saja yang menjadi bagian dari jaringan. Server ini memberikan setiap node alamat dari 100.64.0.0/10, mendistribusikan public key, dan memberi tahu node cara menemukan satu sama lain. Tunnel tetap menggunakan WireGuard dan dibangun secara langsung antarnode. Trafik antara dua mesin Anda tidak melewati mesin headscale, kecuali jalur langsung tidak dapat dibangun sehingga node beralih ke relay.

Setiap instance headscale melayani satu tailnet (satu jaringan Tailscale). Proyek ini menyatakan bahwa model tersebut sesuai untuk penggunaan pribadi atau organisasi kecil. Dengan tiga atau empat mesin, VPN WireGuard biasa pada VPS milik Anda sendiri membutuhkan lebih sedikit software untuk dijalankan dan lebih sedikit komponen yang dapat mengalami masalah. Headscale mulai bermanfaat ketika Anda tidak lagi ingin menulis blok [Peer] secara manual untuk setiap laptop baru. Jika Anda menginginkan control plane self-hosted, tetapi lebih memilih client sendiri dan antarmuka web untuk mengelola peer daripada pengganti langsung Tailscale, NetBird pada satu VPS adalah alternatif yang layak dipertimbangkan. Untuk perbandingan yang lebih luas antara kedua model tersebut, lihat perbedaan WireGuard dan Tailscale.

Hal yang diperlukan sebelum instalasi

  • VPS yang menjalankan Ubuntu 24.04 dengan alamat IPv4 publik dan akses sudo. Jika server masih baru, ikuti sepuluh menit pertama pada VPS baru terlebih dahulu.
  • Data A DNS yang mengarah ke alamat tersebut. Panduan ini menggunakan headscale.example.com.
  • Domain atau subdomain kedua untuk MagicDNS. Panduan ini menggunakan tailnet.example.net. Domain atau subdomain tersebut tidak boleh sama dengan domain pada server_url.
  • Satu mesin klien untuk bergabung, yang menjalankan Linux, macOS, Windows, Android, atau iOS.

Instal headscale dari .deb resmi

Proyek ini menerbitkan paket .deb pada halaman rilis GitHub. Per Juli 2026, rilis saat ini adalah 0.29.3. Periksa arsitektur Anda terlebih dahulu karena nama file memuat informasi tersebut.

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

Perintah tersebut menampilkan amd64 pada VPS x86 biasa dan arm64 pada paket bergaya Ampere atau Graviton. Masukkan hasilnya ke variabel di bawah ini.

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

./ di depan nama file diperlukan. Tanpanya, apt akan mencari paket bernama headscale.deb di repositori Anda dan gagal.

Paket ini membuat pengguna sistem headscale, menulis /etc/headscale/config.yaml default, dan memasang unit systemd. Paket ini tidak memulai service, dan urutan tersebut sudah benar. Konfigurasi yang disertakan mengarahkan server_url ke http://127.0.0.1:8080, yang bukan alamat yang dapat dijangkau oleh klien mana pun milik Anda. Karena itu, service yang dimulai sekarang akan salah konfigurasi meskipun berhasil berjalan. Menjalankan sudo systemctl is-active headscale pada tahap ini menampilkan inactive. Itu memang diharapkan, bukan kesalahan.

Konfigurasikan server_url sebelum memulai service

Edit /etc/headscale/config.yaml dengan sudo nano /etc/headscale/config.yaml, atau terapkan tiga perubahan yang sama menggunakan sed. Simpan salinan file asli karena file tersebut panjang dan memiliki banyak komentar. File itu adalah referensi terbaik untuk pengaturan lainnya.

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 adalah alamat yang ditulis headscale ke setiap registrasi client. Setelah itu, client akan selalu terhubung ke string tersebut. Karena itu, nilainya harus berupa nama publik dengan https:// di depannya, bukan 127.0.0.1.

listen_addr adalah alamat tempat proses melakukan binding. Biarkan pada loopback. Reverse proxy pada server yang sama menangani TLS (transport layer security) dan meneruskan koneksi ke alamat tersebut. Dengan demikian, tidak ada koneksi dari luar server yang perlu mencapai port 8080.

base_domain adalah suffix MagicDNS, yaitu domain yang digunakan untuk nama node Anda. Nilainya harus berupa fully qualified domain name tanpa titik di akhir. Domain ini juga harus berbeda dari domain pada server_url karena kedua namespace tersebut akan bertabrakan jika sama.

Biarkan bagian database apa adanya. Konfigurasi default menggunakan SQLite pada /var/lib/headscale/db.sqlite, di dalam direktori yang dibuat dan dimiliki oleh package. SQLite sudah memadai untuk tailnet sebesar ini.

Mulai headscale dan pastikan layanan berjalan

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 menampilkan active, sedangkan curl menampilkan 200. enable --now melakukan kedua tugas tersebut: memulai service dan menandainya agar dimulai setelah reboot.

Jika is-active menampilkan failed, baca journal dengan sudo journalctl -u headscale -n 50 --no-pager. Kegagalan pada tahap ini hampir selalu disebabkan oleh file konfigurasi, karena headscale mem-parsing seluruh file sebelum membuka socket. Indentasi yang salah atau key yang tidak dikenal akan menghentikan proses sebelum port apa pun berada dalam status listening. Perbaiki file tersebut, lalu jalankan sudo systemctl restart headscale. Setiap perubahan konfigurasi berikutnya memerlukan restart yang sama. Client akan terhubung kembali secara otomatis setelahnya. Jika unit systemd masih baru bagi Anda, menjalankan service dan timer sendiri dengan systemd membahas perintah yang digunakan di sini.

Periksa file status saat shell masih terbuka:

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

Kedua baris diawali headscale, yaitu user tanpa hak istimewa yang dibuat oleh package tersebut. noise_private.key adalah identitas server bagi client. Jangan hapus file itu. Jika Anda menghapusnya, headscale akan membuat identitas baru dan setiap node harus melakukan registrasi ulang.

Pasang TLS di depan headscale

Klien harus mengakses server_url melalui HTTPS. Caddy adalah cara paling singkat karena dapat meminta dan memperbarui sertifikat secara otomatis.

sudo apt install -y caddy

Ganti /etc/caddy/Caddyfile dengan blok dari dokumentasi 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 mencetak adapted config to JSON jika file berhasil diproses. Peringatan bahwa file belum diformat hanya bersifat kosmetik. Dari laptop Anda, curl -sS -o /dev/null -w '%{http_code}\\n' https://headscale.example.com/health juga seharusnya mencetak 200. Pemeriksaan tunggal ini membuktikan bahwa DNS, firewall, sertifikat, dan proxy bekerja bersama dengan benar.

Berikut detail proxy yang sering menghabiskan waktu berjam-jam. Koneksi kontrol Tailscale menggunakan HTTP upgrade, dimulai dengan POST, bukan GET, dan nilai header Upgrade adalah tailscale-control-protocol. Caddy meneruskannya tanpa konfigurasi tambahan. nginx tidak melakukannya, sehingga front end nginx memerlukan peta upgrade berikut:

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;
    }
}

Jika baris tersebut dihilangkan, permintaan biasa tetap berhasil. Karena itu, /health mengembalikan 200 dan semuanya tampak normal, tetapi koneksi kontrol yang berumur panjang tidak pernah terbentuk. Akibatnya, node mendaftar lalu tetap offline. Jika Anda memilih nginx, Certbot di Ubuntu 24.04 dengan nginx membahas bagian sertifikat.

Port yang perlu dibuka di UFW

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

Port 443 membawa seluruh komunikasi klien. Port 80 hanya digunakan untuk HTTP challenge ACME (automatic certificate management environment) dan pengalihan ke HTTPS. Caddy juga memerlukannya untuk memperoleh sertifikat.

Port 8080 tetap ditutup. listen_addr adalah 127.0.0.1:8080, sehingga proxy mengakses headscale melalui antarmuka loopback dan tidak memerlukan aturan firewall. Membuka port 8080 ke Internet hanya memberikan klien saluran kontrol tanpa enkripsi dan tidak memberikan manfaat. Perlu diingat bahwa sebagian besar penyedia menjalankan firewall kedua pada panel kontrol mereka, terpisah dari UFW. Akibatnya, port dapat terbuka pada server tetapi tetap tertutup di perimeter jaringan. Dasar-dasar firewall UFW pada VPS menjelaskan sintaks aturan secara lebih terperinci.

Buat pengguna dan kunci preauth

sudo headscale users create alice
sudo headscale users list

Perintah headscale adalah klien. Perintah ini berkomunikasi dengan daemon yang sedang berjalan melalui unix socket di /var/run/headscale/headscale.sock. Socket tersebut bermode 0770 dan dimiliki oleh grup headscale. Ada dua konsekuensi. Perintah gagal jika service dihentikan. Ini adalah alasan lain mengapa urutan dalam panduan ini penting. Perintah ini juga memerlukan sudo, kecuali Anda menambahkan akun sendiri ke grup headscale.

users list menampilkan ID di samping setiap nama. Anda memerlukan nomor tersebut karena perintah key menerima ID pengguna numerik, bukan nama.

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

Kunci hanya ditampilkan satu kali. Salin sekarang. Preauth key hanya dapat digunakan satu kali dan berlaku selama satu jam, kecuali Anda menentukan lain. Karena itu, --expiration 24h layak ditetapkan saat Anda masih melakukan pengujian. Tambahkan --reusable untuk membuat kunci yang mendaftarkan beberapa mesin. Perlakukan kunci tersebut seperti kata sandi karena siapa pun yang memilikinya dapat bergabung ke jaringan Anda.

Hubungkan klien pertama Anda dengan --login-server

Pada mesin yang ingin Anda gabungkan:

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 menampilkan alamat yang ditetapkan headscale, misalnya 100.64.0.1. Kembali ke server, sudo headscale nodes list menampilkan node beserta ID, pengguna, dan status online-nya.

Nilai --login-server harus sama persis dengan server_url, termasuk skema dan tanpa garis miring di akhir. Keduanya dibandingkan sebagai string. Ketidaksesuaian membuat klien mendaftarkan diri ke satu alamat, lalu diperintahkan untuk berkomunikasi dengan alamat lain.

Mesin yang sebelumnya masuk ke layanan hosted Tailscale akan tetap menggunakan login tersebut. Jalankan sudo tailscale logout terlebih dahulu pada mesin itu, lalu jalankan tailscale up dengan --login-server.

Jika --auth-key dihilangkan, klien akan menampilkan URL. Buka URL tersebut. Halamannya menampilkan identifier untuk upaya pendaftaran tersebut, yang kemudian Anda setujui di server:

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

Formulir ini lebih praktis untuk laptop pribadi. Preauth key lebih sesuai untuk apa pun yang dijalankan melalui skrip karena tidak memerlukan manusia untuk memantaunya. Setelah VPS itu sendiri menjadi node, VPS juga dapat membawa trafik Internet dari mesin Anda yang lain melalui konfigurasi exit node. Perbedaannya, Anda menyetujui route yang diiklankan di server dengan perintah headscale, bukan melalui konsol admin hosted.

DERP dan komponen yang meneruskan trafik saat jalur langsung gagal

DERP (designated encrypted relay for packets) adalah jalur cadangan. Jika dua node tidak dapat membuka koneksi WireGuard langsung, biasanya karena keduanya berada di balik NAT (network address translation) yang ketat, keduanya akan mengirim paket melalui relay. Relay tidak menyimpan key, sehingga tidak dapat membaca trafik Anda. Namun, relay dapat mengetahui node mana yang berkomunikasi dan jumlah data yang dipindahkan.

Pahami fungsi konfigurasi default. Headscale dikirim dengan konfigurasi yang mengarah ke https://controlplane.tailscale.com/derpmap/default menggunakan auto_update_enabled: true dan update_frequency: 3h. Dengan demikian, control plane berada di bawah kendali Anda, sedangkan relay menggunakan relay milik Tailscale. Bagi sebagian besar pengguna, kompromi ini wajar. Jika tidak, jalankan relay sendiri.

Untuk menjalankan relay sendiri, tetapkan enabled: true di bawah derp.server dalam config.yaml, mulai ulang headscale, lalu buka port STUN (session traversal utilities for NAT) menggunakan sudo ufw allow 3478/udp. File konfigurasi menyatakan persyaratan ini dengan jelas: server_url harus menggunakan https karena DERP memerlukan TLS. Mengosongkan daftar derp.urls akan menghapus relay Tailscale dari peta. Jika Anda melakukannya tanpa relay tertanam yang berfungsi, pasangan node yang tidak dapat terhubung secara langsung tidak akan dapat terhubung sama sekali.

Dari sisi client, tailscale netcheck menampilkan latensi ke setiap region relay yang diketahuinya, dan tailscale status menandai setiap peer sebagai direct dengan alamat atau relay dengan kode region. Peer yang tetap berada pada relay menunjukkan masalah NAT, bukan masalah headscale. Peer yang berstatus direct tetapi masih lambat merupakan masalah yang berbeda, dan jawaban yang biasanya berlaku adalah MTU, bukan tunnel itu sendiri.

Mengapa node ditampilkan sebagai offline?

Proxy membuang upgrade. Ini adalah penyebab yang paling umum. Indikasinya, semua hal lain terlihat normal: /health mengembalikan 200, headscale nodes list menampilkan node, tetapi node tidak pernah online. Koneksi kontrol berupa POST yang membawa Upgrade: tailscale-control-protocol. Proxy yang tidak meneruskan koneksi tersebut akan memutus satu-satunya kanal yang melaporkan status node. Bandingkan konfigurasi nginx Anda dengan blok map di atas, atau gunakan Caddy untuk memastikan proxy bukan penyebabnya.

server_url berubah setelah node didaftarkan. Node terus mencoba terhubung menggunakan nilai yang diterimanya saat pendaftaran. Jika Anda mengubah nilai tersebut, jalankan sudo tailscale up --login-server https://headscale.example.com --force-reauth pada setiap node.

Client tidak berjalan. Pada node, jalankan sudo systemctl is-active tailscaled dan sudo journalctl -u tailscaled -n 50 --no-pager. Client yang tidak dapat me-resolve atau menjangkau domain Anda akan mencatat percobaan ulang di sana.

Key telah kedaluwarsa. Penjelasannya ada di bagian berikutnya.

Untuk memantau sisi server saat melakukan pengujian, jalankan sudo journalctl -u headscale -f pada VPS dan restart tailscaled pada client. Node yang berhasil menjangkau headscale akan segera menghasilkan baris log. Jika tidak ada aktivitas, berarti request tidak sampai. Periksa DNS, firewall, dan proxy sebelum memeriksa headscale.

Masa berlaku key dan node yang berhenti bekerja beberapa minggu kemudian

Ada dua masa berlaku yang berbeda. Jika tertukar, waktu akan terbuang.

Preauth key memang dirancang untuk cepat kedaluwarsa. Nilai defaultnya adalah satu jam dan satu kali penggunaan. Jika tailscale up menolak key tersebut, buat key baru di server, bukan dengan mengubah apa pun pada client.

Node key adalah bagian yang berlaku lebih lama. Bagian node pada config.yaml menetapkan expiry: 0, dan 0 berarti tidak ada masa berlaku default: node yang telah didaftarkan tetap valid sampai Anda membuatnya kedaluwarsa. Node yang memiliki tag tidak pernah kedaluwarsa. Tetapkan expiry: 180d jika Anda ingin masa berlaku registrasi berakhir secara otomatis, dan pahami konsekuensinya: setiap node tanpa tag kemudian memerlukan sudo tailscale up --login-server https://headscale.example.com --force-reauth sesuai jadwal tersebut, dan server headless yang tidak diautentikasi ulang oleh siapa pun akan terputus dari jaringan dengan sendirinya.

Lakukan secara manual jika seseorang kehilangan laptop. sudo headscale nodes list menampilkan ID node tersebut, lalu sudo headscale nodes expire -i 3 mengeluarkan node itu dari sesi, dan sudo headscale nodes delete -i 3 menghapusnya sepenuhnya dari jaringan.

Pencadangan dan pemutakhiran

/var/lib/headscale dan /etc/headscale secara bersama-sama mencakup seluruh server. Hentikan service sebelum menyalinnya, karena SQLite mungkin masih memproses operasi tulis dan database yang disalin saat sedang digunakan dapat menjadi tidak konsisten.

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

Pindahkan kedua file tersebut ke luar server. File-file itu berisi private key dan semua registration, sehingga harus dilindungi dengan tingkat kehati-hatian yang sama seperti server itu sendiri. pencadangan restic dari VPS menjelaskan cara melakukannya secara terjadwal dan terenkripsi.

Pemutakhiran mengulangi proses instalasi: download .deb dan sudo apt install ./headscale.deb versi baru, lalu restart dan jalankan kembali pemeriksaan is-active dan /health. Sejak versi 0.29, jalur pemutakhiran menerapkan aturan yang ketat. Melewati versi minor akan diblokir, demikian juga melakukan downgrade ke versi minor yang lebih lama. Pindahkan versi minor satu per satu, buat backup sebelum setiap langkah, dan baca release notes untuk versi tersebut terlebih dahulu, karena release yang sama mengubah perilaku kebijakan ACL dan memindahkan beberapa configuration key.

FAQ

Mengapa headscale gagal berjalan tepat setelah saya menginstal .deb?

Paket tersebut menginstal unit, tetapi membiarkan service dalam keadaan berhenti. Selain itu, /etc/headscale/config.yaml bawaan adalah template, bukan konfigurasi yang dapat digunakan. Edit server_url, listen_addr, dan base_domain terlebih dahulu, lalu jalankan sudo systemctl enable --now headscale dan konfirmasikan dengan sudo systemctl is-active headscale. Jika masih gagal, sudo journalctl -u headscale -n 50 --no-pager menunjukkan masalahnya. Pada tahap ini, penyebabnya hampir selalu kesalahan YAML karena headscale mengurai seluruh file sebelum melakukan bind pada port.

Apakah saya tetap perlu menginstal klien Tailscale biasa pada mesin saya?

Ya. Headscale hanya menggantikan server kontrol. Setiap node menjalankan klien resmi dari Tailscale, lalu Anda mengarahkannya ke server dengan sudo tailscale up --login-server https://headscale.example.com. Flag tersebut tersedia pada klien standar, sehingga tidak ada yang perlu ditambal atau dibangun ulang.

Apakah trafik saya melewati server headscale?

Biasanya tidak. Headscale mengoordinasikan jaringan serta membagikan key dan alamat, sedangkan jalur data menggunakan WireGuard secara langsung di antara node Anda. Trafik hanya mengambil jalur memutar ketika dua node tidak dapat saling menjangkau secara langsung dan beralih ke relay DERP. Dengan konfigurasi yang disertakan, relay tersebut adalah relay publik milik Tailscale. Jalankan tailscale status pada sebuah node untuk melihat apakah peer tertentu berstatus direct atau berada pada relay.

Mengapa node saya tetap offline setelah melakukan registrasi?

Node yang muncul di headscale nodes list tetapi tidak pernah online biasanya kehilangan koneksi kontrolnya pada reverse proxy. Koneksi tersebut adalah HTTP upgrade yang dikirim sebagai POST dengan header Upgrade: tailscale-control-protocol. nginx akan membuangnya kecuali Anda menambahkan blok map $http_upgrade $connection_upgrade dan baris proxy_set_header yang sesuai. Caddy meneruskannya tanpa konfigurasi tambahan. Karena itu, Caddy dapat digunakan untuk menguji dengan cepat apakah masalahnya berada pada proxy.

Apakah saya memerlukan nama domain dan TLS untuk headscale?

Dalam praktiknya, ya. Klien terhubung ke string yang Anda masukkan di server_url. Sertifikat diterbitkan untuk nama, bukan alamat IP tanpa nama domain. File konfigurasi juga menyatakan bahwa DERP memerlukan TLS. Domain dan Caddy dapat disiapkan dalam waktu sekitar lima menit, lalu Anda mendapatkan endpoint HTTPS yang memperbarui sertifikatnya sendiri. Jika server kontrol dijalankan melalui HTTP biasa, setiap percakapan klien dengannya melintasi Internet tanpa enkripsi.