Lika Liku Berkutat dengan Server On-Premise
Pengalaman deployment aplikasi anti mainstream

Anak Elektro yang tersesat di Dunia Koding

Pendahuluan
Beberapa waktu lalu saya sempat membangun sebuah aplikasi ERP (Enterprise Resource Planning) untuk perusahaan manufaktur. Tapi proyek ini bukan hanya sekedar soal kode dan fitur saja, namun hingga merambah ke bagian infrastruktur server dan jaringan.
Nah menariknya, pihak klien ingin punya server sendiri. Bukan sewa, bukan cloud, apalagi shared hosting, tapi benar-benar server fisik yang bisa dipegang dan disentuh. Jadi, selain membangun aplikasi, saya juga harus membangun infrastruktur servernya from scratch.
Proyek ini berjalan kurang lebih selama 3 bulan, termasuk tahap pengembangan dan pemeliharaan. Setelah itu, baru lah masuk ke tahap yang belum pernah saya alami sebelumnya yaitu pemasangan server on-premise.
Sebelum melangkah lebih jauh, kami menanyakan beberapa hal penting kepada klien, seperti:
- Apakah ada tenaga IT yang akan mengurus server
- Apakah sudah memiliki IP Public
- Apakah sudah memiliki jaringan internet yang mumpuni
Dari situ, satu persatu jawaban mulai terungkap. Ternyata tidak ada tenaga IT. Artinya, segala urusan server, mulai dari setup, konfigurasi, hingga maintenance akan dikembalikan kepada saya dan tim. Untuk koneksi internet katanya sih sudah di siapkan dengan kecepatan 100mbps beserta dengan IP publik. Tapi entah kenapa saya punya firasat buruk soal IP publik, karena dari jawabannya seperti meragukan. Kalau dipikir-pikir, siapa juga yang mau langganan IP publik mahal-mahal cuma untuk satu aplikasi saja - seperti tidak masuk akal bukan? Dari situ saya pun menyadari bahwa saya harus punya rencana cadangan untuk berjaga-jaga kalau memang ternyata klien tidak punya IP publik.
Explorasi Strategi
Setelah berbagai kebingungan saya lalui, akhirnya saya membuka ChatGPT, sekedar untuk mencari pencerahan saja. Namun siapa sangka, obrolan yang awalnya cuma "iseng nanya" malah jadi diskusi panjang. Dari sana, saya mendapatkan tiga opsi strategi yang bisa jadi cadangan.
Strategi 1: Instalasi Lokal
Strategi pertama ini merupakan yang paling mudah untuk dilakukan. Karena kita hanya perlu menyiapkan router saja untuk membuat jaringan lokal dan menghubungkan server ke jaringan tersebut. Lalu pengguna hanya tinggal terhubung ke jaringan untuk mengakses aplikasinya. Walaupun mudah dan sederhana - strategi ini memiliki kekurangan yaitu aplikasi tidak dapat diakses jika perangkat sudah terputus dari jaringan lokal tersebut.
Strategi 2: Tunneling
Alternatif kedua terdengar lebih "magic" . Namanya adalah tunneling - sebuah cara untuk mengekspose aplikasi lokal ke publik tanpa perlu IP publik. Terlihat magic bukan? Gimana sih cara kerjanya? Sederhananya, tunneling itu seperti membuat terowongan khusus dari server lokal ke server publik. Sehingga jika ada trafik yang masuk ke server lokal maka akan lewat server publik, lalu ke terowongan tadi, terus baru sampe ke server lokal. Untuk melakukan tunneling ada beberapa cara seperti menggunakan Cloudflare Tunnel atau Ngrok.
Gambar Analogi Tunneling
Namun saya memutuskan untuk memilih Cloudflare Tunnel. Kenapa? Sederhana saja - gratis, stabil, dan dapat langsung terintegrasi dengan domain yang sudah kami miliki. Selain itu, saya juga sering melakukan manajemen DNS menggunakan Cloudflare sehingga lebih familiar saja.
Strategi 3: VPN
Strategi terakhir yaitu menggunakan VPN. Pasti sudah tidak asing kan dengan VPN? Bukan untuk membuka situs yang terblokir, tapi untuk membuat seolah-olah berada di jaringan lokal. Sehingga walaupun tidak terhubung ke jaringan lokal, pengguna tetap dapat mengakses aplikasi.
Namun opsi ini tidak kami prioritaskan. Alasannya sederhana, agak ribet untuk pengguna awam. Karena untuk terhubung ke VPN harus menyalakan aplikasi vpn, kemudian memasukkan username dan password, lalu memilih jaringan yang ingin diakses.
Implementasi Server
Tahap implementasi dimulai dengan hal yang paling mendasar yaitu mengatur IP server agar bersifat statis. Langkah ini dilakukan di dua sisi, pertama di server dengan konfigurasi netplan, yang kedua di sisi router dengan preserve IP. Dengan konfigurasi tersebut, kita tidak perlu khawatir lagi IP akan berubah kalau sewaktu-waktu server mati.
network: version: 2 renderer: networkd ethernets: eno8403: dhcp4: false addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: - 8.8.8.8
Langkah selanjutnya yaitu melakukan forwarding dari IP publik ke IP server lokal. Di sisi dashboard router terdapat dua jenis IP yang tersedia yaitu IP 10.x.x.x untuk VOIP dan IP 36.x.x.x untuk Internet. Artinya saya dapat menggunakan IP 36.x.x.x karena sekilas terlihat seperti IP publik. Namun disinilah masalah muncul.
Masalah 1: IP Publik
Ketika saya coba akses lewat browser, saya malah mendapatkan pesan error, bukan tampilan aplikasi yang seharusnya. Saya sempat berpikir apakah mungkin ada konfigurasi yang salah. Akhirnya saya mencoba untuk mengecek kembali dari awal, bertanya ke AI, membaca forum, hingga melihat kembali konfigurasi pada router. Namun hasilnya tetap sama saja. Dari situ saya mulai curiga, akhirnya saya coba untuk mengecek IP saya yang terhubung ke internet lewat situs whatismyipaddress.com. Dan benar saja, ternyata hasilnya tidak sama dengan IP yang tertulis di router.
IP yang terlihat pada router ternyata bukan IP publik sesungguhnya, melainkan hanya sub-IP dari jaringan yang lebih besar milik ISP. Dengan kata lain, klien sebenarnya belum memiliki IP publik sesuai dengan firasat saya.
Strategi Alternatif
Karena klien tidak memiliki IP publik akhirnya saya harus menggunakan strategi alternatif yang sebelumnya sudah direncanakan. Klien ingin agar aplikasi dapat diakses dimana saja dengan mudah dan cepat, maka strategi tunneling adalah yang paling cocok.
Namun sebelum melakukan konfigurasi untuk tunneling, saya harus bisa mengakses servernya secara remote terlebih dahulu. Karena kalau tidak, akan sulit untuk melakukan konfigurasinya. Ketika saya coba melakukan ssh dari laptop, saya mendapatkan masalah baru lagi.
Masalah 2: Device Restriction
Respon dari ssh tersebut selalu gagal. Ketika saya coba untuk melakukan ping ke IP server pun selalu gagal. Dugaan saya adalah router milik klien memberikan pembatasan akses ke sesama device yang terhubung secara lokal. Akhirnya saya pun mencari alterantif tools yang memungkinkan saya untuk mengakses server secara remote tanpa menggunakan IP Publik. Dan pastinya yang gratis juga.
Setelah mencari sana sini, akhirnya saya menemukan sebuah tool bernama TailScale. Tool ini sangat sakti karena memiliki fitur remote access. Cara kerjanya seperti VPN, kita hanya perlu menginstall tailscale di masing-masing perangkat yang ingin dihubungkan. Lalu secara otomatis akan terhubung ke jaringan pribadi bernama Tailnet. Dari situ kita dapat mengakses masing-masing perangkat secara remote.
Gambar Daftar Device pada Tailnet
Sekarang saya sudah bisa melakukan remote access sehingga saya dapat melakukan konfigurasi Cloudflare Tunnel. Setelah berhasil melakukan konfigurasi Cloudflare Tunnel, saya mendapatkan kendala lagi.
Gambar Route Tunnel
Masalah 3: HestiaCP Tunneling
Kendala tersebut terjadi karena penggunaan HestiaCP sebagai Control Panel di server - yang ternyata tidak secara langsung mendukung tunneling ke aplikasi di dalamnya. Sehingga saya pun harus mempelajari bagaimana cara HestiaCP melakukan manajemen aplikasi.
Secara sederhananya, HestiaCP akan membuat konfigurasi Nginx untuk masing-masing aplikasi. Kemudian Nginx bertugas sebagai reverse proxy untuk semua trafik yang masuk. Tapi masalahnya, setiap aplikasi yang dikonfigurasi menggunakan HestiaCP, secara default hanya listen pada port 80 dan 443. Sedangkan untuk melakukan tunneling menggunakan cloudflare tunnel - tiap aplikasi harus memiliki port yang berbeda.
Gambar Analogi Reverse Proxy
Solusinya? membuat template konfigurasi HestiaCP sendiri untuk mengakomodasi hal tersebut. Dengan template tersebut, masing-masing aplikasi bisa listen port yang berbeda seperti 8000. 8001, 8002, dan seterusnya. Kemudian di dashboard cloudflare, saya atur agar setiap tunnel meneruskan trafik ke alamat dan port yang sesuai. Dengan konfigurasi seperti itu, aplikasi client kini bisa diakses secara publik, tanpa IP publik sama sekali.
#=========================================================================# # Cloudflare Tunnel Template Base (HTTP) #=========================================================================# server { listen 127.0.0.1:{PORT}; listen %ip%:{PORT}; server_name %domain_idn% %alias_idn%; root %docroot%/public; index index.php index.html index.htm; access_log /var/log/nginx/domains/%domain%.log combined; error_log /var/log/nginx/domains/%domain%.error.log error; include %home%/%user%/conf/web/%domain%/nginx.forcessl.conf*; client_max_body_size 50M; location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { allow all; access_log off; log_not_found off; } location ~ /\.(?!well-known\/) { deny all; return 404; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~* \.(ogg|ogv|svg|svgz|swf|eot|otf|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|jpg|jpeg|gif|png|webp|ico|bmp|mid|midi|wav|rtf|css|js|jar)$ { expires 30d; access_log off; log_not_found off; fastcgi_hide_header "Set-Cookie"; } location = /livewire/livewire.js { expires off; try_files $uri $uri/ /index.php?$query_string; } location = /livewire/livewire.min.js { expires off; try_files $uri $uri/ /index.php?$query_string; } location ~ [^/]\.php(/|$) { include /etc/nginx/fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_pass %backend_lsnr%; fastcgi_read_timeout 120s; include %home%/%user%/conf/web/%domain%/nginx.fastcgi_cache.conf*; } location /error/ { alias %home%/%user%/web/%domain%/document_errors/; } include /etc/nginx/conf.d/phpmyadmin.inc*; include /etc/nginx/conf.d/phppgadmin.inc*; include %home%/%user%/conf/web/%domain%/nginx.conf_*; }
Kesimpulan
Dari proyek ini, saya belajar bahwa membangun aplikasi bukan hanya soal menulis kode dan mendeploynya ke server. Terkadang, tantangan justru datang dari hal-hal yang berada di luar scope pengembangan.
Pengalaman ini mengajarkan saya pentingnya problem-solving mindset dan fleksibilitas. Bagaimana kita dapat berpikir cepat untuk mengambil sebuah keputusan.