Cloudflare Tunnel: Ekspos Layanan Rumahan Tanpa Membuka Port

Masalahnya: layanan jalan, tapi tidak bisa diakses dari luar

Skenario yang familiar: Anda menjalankan sesuatu di rumah — dasbor monitoring, Immich, n8n, atau aplikasi kecil di port 3000. Di jaringan lokal semua jalan. Begitu ingin diakses dari luar, temboknya muncul: IP publik dinamis, router di balik CGNAT provider, dan port forwarding yang tidak bisa dibuat karena modem tidak bisa diutak-atik.

Jalur klasiknya adalah port forwarding: buka port di router, arahkan ke mesin lokal. Cara ini bekerja, tapi ada harganya. Setiap port yang dibuka adalah permukaan serangan yang terlihat dari internet. Siapa pun bisa memindai IP Anda dan menemukan layanan itu. Belum lagi kalau provider memakai CGNAT — alamat IP yang Anda lihat di router bukan alamat publik yang bisa dijangkau, sehingga port forwarding tidak mungkin dilakukan sama sekali.

Cloudflare Tunnel membalik arah koneksinya. Bukan internet yang mengetuk masuk ke jaringan Anda, melainkan mesin Anda yang membuat koneksi keluar (outbound) ke jaringan Cloudflare, dan koneksi itu dipertahankan tetap hidup. Karena koneksi dibuat dari dalam ke luar, tidak ada port yang perlu dibuka di router atau firewall, dan CGNAT bukan lagi penghalang. Lalu lintas pengunjung masuk lewat nama domain Anda, melewati jaringan Cloudflare, lalu diteruskan lewat tunnel itu ke layanan lokal.

Syaratnya cuma dua: sebuah domain yang nameserver-nya sudah di Cloudflare, dan akun Cloudflare gratis (Free sudah cukup untuk kebutuhan ini).

Cara kerja tunnel, singkat saja

Satu daemon kecil bernama cloudflared berjalan di mesin Anda. Ia menghubungkan mesin ke edge Cloudflare terdekat lewat koneksi terenkripsi. Di sisi Cloudflare, sebuah hostname (misalnya app.domainanda.com) diikat ke tunnel tersebut. Pengunjung membuka hostname itu seperti situs biasa — mereka tidak pernah tahu dan tidak perlu tahu mesinnya ada di mana.

Dua hal yang perlu dipahami sejak awal:

  1. Layanan Anda tidak pernah terekspos langsung. Yang terlihat dari internet hanyalah edge Cloudflare. Port layanan tetap tertutup rapat.
  2. TLS diurus Cloudflare. Pengunjung mendapat HTTPS valid tanpa Anda mengurus sertifikat di mesin lokal. Komunikasi tunnel ke layanan lokal bisa HTTP biasa karena tidak pernah keluar dari mesin.

Langkah 1: instal cloudflared di Ubuntu 24.04

Ambil paket .deb resmi dari GitHub Cloudflare dan instal:

curl -L --output cloudflared.deb \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
cloudflared --version

Perintah curl -L mengikuti redirect GitHub ke file rilis terbaru. Kalau dpkg mengeluh soal dependensi yang hilang (jarang terjadi di Ubuntu 24.04), perbaiki dengan sudo apt --fix-broken install.

Langkah 2: login dan buat tunnel

Login menghubungkan cloudflared ke akun Cloudflare Anda. Perintah ini mencetak URL — buka di browser, pilih domain yang ingin dipakai, dan izinkan:

cloudflared tunnel login

Setelah itu, buat tunnel dengan nama yang jelas (satu tunnel bisa dipakai untuk banyak hostname sekaligus):

cloudflared tunnel create rumah

Perintah ini menghasilkan dua hal penting: sebuah ID tunnel, dan file kredensial di ~/.cloudflared/<ID-tunnel>.json. Jangan bagikan file JSON ini — ia adalah kunci akses tunnel Anda. Catat juga ID-nya, karena akan dipakai di konfigurasi.

Langkah 3: tulis konfigurasi ingress

Buat file ~/.cloudflared/config.yml. Di sinilah Anda memetakan hostname ke layanan lokal:

tunnel: <ID-tunnel>
credentials-file: /home/<user>/.cloudflared/<ID-tunnel>.json

ingress:
  - hostname: app.domainanda.com
    service: http://localhost:3000
  - hostname: foto.domainanda.com
    service: http://localhost:2283
  - service: http_status:404

Beberapa catatan soal file ini:

  • Ganti <ID-tunnel> dan <user> dengan nilai asli Anda. Path kredensial harus absolut.
  • Aturan ingress dibaca dari atas ke bawah; aturan terakhir wajib berupa catch-all (di sini http_status:404), kalau tidak cloudflared akan menolak konfigurasi.
  • service menunjuk ke layanan lokal Anda. Untuk aplikasi web biasa, http://localhost:<port> sudah cukup. Layanan lokal tidak perlu HTTPS sendiri — koneksi antara cloudflared dan aplikasi tidak keluar dari mesin.

Langkah 4: arahkan DNS ke tunnel

Untuk tiap hostname, buat record DNS yang menunjuk ke tunnel:

cloudflared tunnel route dns rumah app.domainanda.com
cloudflared tunnel route dns rumah foto.domainanda.com

Perintah ini membuat record CNAME di zona Cloudflare Anda yang mengarah ke <ID-tunnel>.cfargotunnel.com. Anda tidak perlu membuat record ini lewat dasbor — dan jangan diubah lewat dasbor, karena cloudflared yang mengelolanya.

Langkah 5: jalankan dan uji

Jalankan tunnel di foreground dulu untuk memastikan tidak ada salah ketik di konfigurasi:

cloudflared tunnel run rumah

Buka https://app.domainanda.com di browser. Kalau aplikasi lokal Anda muncul dengan HTTPS valid, konfigurasi sudah benar. Tekan Ctrl+C untuk berhenti, lalu pasang sebagai service agar jalan otomatis saat boot:

sudo cloudflared service install
sudo systemctl enable --now cloudflared
sudo systemctl status cloudflared

Catatan penting: service systemd berjalan dengan konteks berbeda dan secara konvensional membaca /etc/cloudflared/config.yml, bukan ~/.cloudflared/config.yml. Sebelum service install, salin konfigurasi dan file kredensial ke /etc/cloudflared/ (dan sesuaikan credentials-file di config.yml ke path barunya), lalu verifikasi dengan systemctl status cloudflared. Perintah service install membuat unit systemd cloudflared yang menjalankan tunnel dari konfigurasi tersebut. Sejak titik ini, tunnel aktif selama mesin menyala — termasuk setelah reboot.

Menambah layanan baru nanti

Satu tunnel bisa menampung banyak hostname. Untuk menambah layanan, cukup:

  1. Tambahkan satu blok hostname + service ke config.yml.
  2. Jalankan cloudflared tunnel route dns rumah <hostname-baru>.
  3. Restart service: sudo systemctl restart cloudflared.

Tidak ada port baru yang dibuka, tidak ada konfigurasi router yang disentuh.

Kapan tunnel lebih baik dari port forwarding — dan kapan tidak

Pilih tunnel ketika: Anda di balik CGNAT, tidak punya IP publik statis, tidak mau membuka port, atau ingin HTTPS gratis tanpa mengurus sertifikat. Ini juga pilihan tepat untuk layanan rumahan yang hanya dipakai segelintir orang.

Tetap pakai port forwarding atau VPS ketika: Anda butuh protokol non-HTTP yang tidak didukung tunnel (misalnya server game tertentu), atau tidak ingin lalu lintas bergantung pada pihak ketiga. Tunnel memang menambahkan satu perantara: kalau Cloudflare bermasalah, layanan Anda ikut tidak bisa diakses dari luar, meskipun mesin lokalnya sehat.

Satu peringatan keamanan yang penting: tunnel menghilangkan kebutuhan membuka port, tapi tidak menghilangkan kebutuhan mengamankan aplikasinya. Layanan yang terekspos lewat hostname publik tetap bisa diakses siapa pun yang tahu alamatnya. Untuk layanan privat (dasbor admin, panel internal), tambahkan proteksi di depan dengan Cloudflare Access — gratis untuk 50 pengguna — supaya hanya akun yang Anda izinkan bisa membuka halaman itu. Jangan pernah mengekspos SSH, panel database, atau layanan admin tanpa pengaman ke publik tanpa lapisan autentikasi.

Kalau ada yang tidak jalan

Error 502 dari Cloudflare: tunnel jalan, tapi layanan lokal tidak merespons. Periksa aplikasinya: curl http://localhost:3000 dari mesin yang sama. Kalau curl gagal, masalahnya di aplikasi, bukan di tunnel.

Error 1033: hostname belum terikat ke tunnel yang aktif. Pastikan route dns sudah dijalankan untuk hostname itu, dan service cloudflared sedang berjalan (systemctl status cloudflared).

Tunnel tidak mau start: lihat lognya, jangan menebak: sudo journalctl -u cloudflared -n 50 --no-pager. Penyebab paling umum adalah salah path kredensial atau salah ID tunnel di config.yml.

Perubahan config tidak berefek: ingat restart service setelah mengedit config.yml. Mode tunnel run manual tidak membaca ulang file secara otomatis.

Checklist penutup

  • cloudflared terinstal dan cloudflared --version menampilkan versi
  • Tunnel dibuat dan file kredensial tersimpan aman, tidak dibagikan
  • config.yml berisi hostname, service lokal, dan catch-all 404
  • DNS tiap hostname di-route dengan tunnel route dns
  • Uji lewat HTTPS publik berhasil, lalu service systemd aktif (systemctl status cloudflared)
  • Layanan privat dilindungi Cloudflare Access, bukan dibiarkan terbuka
  • Tidak ada port yang dibuka di router atau firewall untuk layanan ini

Komentar