Relay TCP sederhana di atas Tailscale (tsnet). Dipakai untuk mengakses service di VPS lewat jaringan Tailscale, bukan lewat IP publik VPS. Satu binary static, jalan di Termux (32/64-bit) dan VPS (x86/x86_64/ARM). Mendukung satu port, daftar port, rentang port, atau semua port sekaligus.
[Local / Termux] [VPS]
localhost:3982 ──── Tailscale ────► tailnet:3982 ──► 127.0.0.1:3982
--mode target --mode tunnel
| Mode | Dijalankan di | Fungsi |
|---|---|---|
tunnel |
VPS (sumber service) | Listen di Tailnet, meneruskan ke --target (default 127.0.0.1) |
target |
Local / Termux | Listen di lokal, meneruskan ke --target lewat Tailnet |
--listen adalah alamat lokal tempat server dibuka. --target adalah tujuan akhir. Port di --target bersifat opsional: kalau tidak ditulis, port tujuan sama dengan port listen.
Binary otomatis sesuai arsitektur perangkat:
curl -fsSL https://raw.githubusercontent.com/FgsiDev/tsrelay/main/install.sh | bashNama file output sendiri:
curl -fsSL https://raw.githubusercontent.com/FgsiDev/tsrelay/main/install.sh | bash -s -- nama-fileBinary yang tersedia di Release:
| File | Perangkat |
|---|---|
tsrelay-linux-amd64 |
VPS x86_64 |
tsrelay-linux-386 |
VPS x86 32-bit |
tsrelay-linux-arm64 |
Termux 64-bit, VPS ARM |
tsrelay-linux-armv7 |
Termux 32-bit |
tsrelay-linux-armv6 |
ARM 32-bit lama |
Buat auth key di Tailscale admin console (Settings → Keys). Disarankan reusable.
Di VPS:
export TS_AUTHKEY=tskey-auth-xxxx
./tsrelay --mode tunnel --listen :3982 --target 127.0.0.1Kalau service di VPS memakai port lain: --target 127.0.0.1:8080.
Di Local / Termux:
export TS_AUTHKEY=tskey-auth-xxxx
./tsrelay --mode target --listen :3982 --target 100.x.x.x100.x.x.x adalah IP Tailscale VPS. Hostname MagicDNS juga bisa. Setelah itu localhost:3982 langsung mengakses service di VPS.
Contoh SSH ke VPS lewat relay (SSH di port 22, dibuka lokal di 2222 karena Termux tanpa root tidak boleh bind port di bawah 1024):
./tsrelay --mode target --listen :2222 --target 100.x.x.x:22
ssh root@127.0.0.1 -p 2222Format --listen:
| Nilai | Artinya |
|---|---|
:2222 atau 2222 |
Satu port |
2222,8080,3000 |
Beberapa port |
8000-8100 |
Rentang port |
2222,8000-8100 |
Gabungan |
127.0.0.1:2222,8080 |
Bind ke alamat tertentu |
127.0.0.1 atau all |
Mode otomatis: port mengikuti port yang terbuka di target (lihat bawah) |
Contoh:
# tiga port, port tujuan sama dengan port listen
./tsrelay --mode target --listen 2222,8080,3000 --target 100.x.x.x
# rentang port
./tsrelay --mode target --listen 8000-8100 --target 100.x.x.x
# mode otomatis: port buka/tutup mengikuti target
./tsrelay --mode target --listen 127.0.0.1 --target 100.x.x.xAturan:
--targettanpa port:localhost:Xditeruskan ke100.x.x.x:Xuntuk setiap port X yang dibuka.--targetdengan port (100.x.x.x:22) hanya boleh dipakai dengan satu port listen. Kalau dipakai bersama banyak port, program langsung berhenti dengan pesan error.- Port yang gagal dibuka atau sudah terpakai dilewati dan dilaporkan di log. Program tetap jalan selama minimal satu port berhasil.
- Port tujuan yang tidak ada servicenya akan menghasilkan
connection refuseddi log. Itu normal, relay hanya meneruskan. - Jumlah listener dibatasi setengah dari batas file descriptor perangkat, supaya masih ada fd untuk koneksi.
Kalau --listen hanya berisi IP (atau all), TSRelay memantau port di target secara berkala:
- Target membuka port baru → port yang sama otomatis dibuka di lokal (
+ port 8080 dibuka). - Target menutup port → port lokal otomatis ditutup (
- port 8080 ditutup).
./tsrelay --mode target --listen 127.0.0.1 --target 100.x.x.xCara kerja dan batasan:
- Pemantauan dilakukan dengan mencoba konek ke tiap port target (default 1-65535, tiap 10 detik). Port yang terbuka langsung dibuatkan listener. Port ditutup setelah 3 kali scan berturut-turut tidak terlihat terbuka (sekitar 30 detik), supaya gangguan jaringan sesaat tidak memutus relay.
- Scan pertama bisa memakan waktu kalau banyak port yang di-drop firewall (tiap port menunggu timeout). Persempit dengan
--scan, mis.--scan 1-10000,25565, supaya lebih cepat dan ringan. - Port di bawah 1024 tidak bisa dibuka di lokal tanpa root (Termux). Port itu dilewati dan dicatat di log. Pakai mode statis dengan port lain, mis.
--listen :2222 --target 100.x.x.x:22. - Port yang sudah dipakai program lain di lokal juga dilewati, dan dicoba lagi kalau port itu muncul kembali di target.
- Pengecekan membuka lalu langsung menutup koneksi ke tiap port terbuka. Service yang hanya menerima satu klien, atau yang mencatat tiap koneksi, bisa terpengaruh.
--targettidak boleh memakai port di mode otomatis.- Di mode
tunnel(VPS), mode otomatis memantau127.0.0.1dan membuka tiap port yang terbuka itu ke seluruh Tailnet. Pastikan itu memang yang kamu mau.
| Flag | Default | Keterangan |
|---|---|---|
--mode |
tunnel |
tunnel atau target |
--listen |
:3982 |
Port listen: satu, daftar, rentang. IP saja atau all = mode otomatis. Lihat bagian Multi-port |
--scan |
1-65535 |
Mode otomatis: port target yang dipantau |
--scan-interval |
10s |
Mode otomatis: jeda antar scan |
--scan-timeout |
700ms |
Mode otomatis: timeout cek tiap port |
--scan-workers |
512 |
Mode otomatis: jumlah cek port paralel (otomatis dikurangi sesuai batas fd) |
--target |
- | IP atau hostname tujuan, port opsional. Wajib di mode target. Di tunnel default 127.0.0.1 |
--hostname |
tsrelay |
Nama node di dashboard Tailscale |
--auth-key |
$TS_AUTHKEY |
Auth key Tailscale. Hanya wajib saat login pertama |
--state-dir |
~/.tsrelay |
Lokasi identitas node (node key) |
--ephemeral |
false |
Node otomatis hilang dari dashboard saat offline |
TSRelay mendaftar sebagai satu node Tailscale. Identitasnya disimpan di --state-dir.
- Selama
~/.tsrelaytidak dihapus, setiap restart tetap menjadi machine dan IP yang sama. - Setelah login pertama,
TS_AUTHKEYtidak diperlukan lagi. - Satu state hanya boleh dipakai satu proses (ada lock file). Instance kedua dengan state yang sama akan ditolak.
- Jangan menyalin folder state ke perangkat lain. Itu penyebab status Duplicate node key di dashboard.
- Jangan jalankan dari folder berbeda dengan
--state-dir ., karena tiap folder dianggap node baru. - Di container tanpa penyimpanan permanen (Railway, Hugging Face Spaces), pakai
--ephemeralatau arahkan--state-dirke volume permanen.
--listen :3982membuka port ke semua interface. Kalau hanya perlu diakses dari perangkat itu sendiri, pakai--listen 127.0.0.1:3982. Hal yang sama berlaku untuk mode multi-port:127.0.0.1:2222,8080.- Di mode
tunnel, port hanya terbuka di Tailnet, bukan di IP publik VPS. - Jangan commit auth key ke repo. Simpan di environment variable.
Termux atau VPS sederhana:
nohup ./tsrelay --mode target --listen :3982 --target 100.x.x.x > tsrelay.log 2>&1 &systemd (VPS):
# /etc/systemd/system/tsrelay.service
[Unit]
Description=TSRelay
After=network-online.target
[Service]
Environment=TS_AUTHKEY=tskey-auth-xxxx
ExecStart=/usr/local/bin/tsrelay --mode tunnel --listen :3982 --target 127.0.0.1
Restart=always
User=root
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload && sudo systemctl enable --now tsrelayButuh Go versi terbaru (sesuai syarat tailscale.com).
go mod tidy
CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o tsrelay .Semua arsitektur sekaligus:
chmod +x build.sh && ./build.sh # hasil di dist/Workflow ada di .github/workflows/release.yml.
- Push ke
mainyang mengubahmain.go: build semua arsitektur, lalu membuat Release baru bernamav1.0.<nomor run>besertaSHA256SUMS.txt. - Push tag
v*: nama tag itu yang dipakai sebagai nama Release. - Pull request: hanya build, tanpa release.
- Run manual lewat tab Actions (Run workflow) juga tersedia.
| Masalah | Penyebab dan solusi |
|---|---|
| Muncul machine baru di dashboard | State hilang atau berpindah folder. Pakai --state-dir tetap (default ~/.tsrelay) |
Duplicate node key |
State yang sama dipakai di lebih dari satu perangkat. Hapus node di dashboard, hapus ~/.tsrelay, login ulang per perangkat |
state dir ... sedang dipakai instance lain |
Masih ada proses tsrelay yang jalan. pkill tsrelay lalu coba lagi |
TS_AUTHKEY belum diisi |
Login pertama butuh auth key. export TS_AUTHKEY=... |
Authkey is set; but state is Starting. Ignoring authkey |
Normal kalau state sudah ada |
gagal connect target ... connection was refused |
Koneksi sampai ke mesin tujuan, tapi tidak ada service di port itu. Cek port tujuan (mis. SSH di 22, bukan 2222) dan pastikan servicenya jalan |
gagal connect target (timeout) |
Cek IP target, pastikan node tujuan online dan, di mode tunnel, tunnel di VPS jalan |
bind: permission denied |
Port di bawah 1024 butuh root. Pakai port 1024 ke atas, mis. --listen :2222 |
... bukan alamat milik perangkat ini |
--listen berisi IP mesin lain. --listen = alamat lokal (127.0.0.1, 0.0.0.0, atau kosong). IP tujuan ditulis di --target |
--target dengan port hanya untuk satu port listen |
Multi-port dan mode otomatis tidak bisa dipetakan ke satu port tujuan. Tulis --target tanpa port |
too many open files |
Terlalu banyak port listen untuk batas fd perangkat. Pakai daftar/rentang port yang lebih kecil atau --scan yang lebih sempit |
port N dilewati: ... permission denied (mode otomatis) |
Port di bawah 1024 tidak bisa dibuka tanpa root. Normal, bisa diabaikan |
| Mode otomatis tidak membuka port yang seharusnya ada | Cek --scan mencakup port itu, dan firewall target mengizinkan koneksi dari Tailscale. Tunggu satu siklus scan |
tidak ada port yang berhasil dibuka |
Semua port gagal bind (sudah terpakai atau tidak diizinkan). Lihat pesan error di baris yang sama |
/proc/net/route permission denied, SO_BINDTODEVICE |
Normal di Android/Termux, bisa diabaikan |
DNS hostname gagal di Termux (mode tunnel) |
Binary static Go tidak menemukan /etc/resolv.conf. Pakai IP di --target |
| GitHub | github.com/FgsiDev |
| Kontak | https://whatsapp.com/channel/0029VapkSr45q08hPPPVqy26 |
| Repo | FgsiDev/tsrelay |
Bug atau saran fitur? Buka Issues atau kirim pull request.
MIT © 2026 FgsiDev