Rust Nginx
Halo Sobat, pada tulisan kali ini saya ingin mencoba belajar bahasa pemrograman Rust di Alpine Linux.
Bagi yang sudah terbiasa menggunakan PHP dan Nginx, belajar Rust bisa terasa sedikit berbeda. Jika pada PHP kita cukup membuat file .php kemudian menjalankannya melalui PHP-FPM dan Nginx, pada Rust kita akan mengenal konsep compile, binary executable, Cargo, serta cara menjalankan aplikasi sebagai proses tersendiri.
Di tutorial ini saya tidak langsung membuat aplikasi yang terlalu rumit. Kita akan mulai dari contoh sederhana, yaitu membuat sebuah web server kecil menggunakan Rust, kemudian menjalankannya di Alpine Linux dan menghubungkannya dengan Nginx.
Dengan cara ini, kita bisa melihat bagaimana Rust dapat berjalan berdampingan dengan konfigurasi web server yang sudah ada, termasuk PHP-FPM.
1. Tujuan Tutorial
Setelah mengikuti tutorial ini, kita akan mencoba beberapa hal berikut:
Menginstal Rust dan Cargo di Alpine Linux.
Mengecek versi Rust yang terpasang.
Membuat project Rust menggunakan Cargo.
Mengenal file Cargo.toml.
Mengenal file src/main.rs.
Membuat web server sederhana dengan Rust.
Menjalankan aplikasi Rust pada port 8080.
Melakukan build aplikasi menjadi binary.
Menjalankan binary hasil build.
Menghubungkan aplikasi Rust dengan Nginx menggunakan reverse proxy.
Menjalankan PHP dan Rust secara bersamaan pada server yang sama.
2. Persiapan
Saya menggunakan Alpine Linux yang sudah memiliki Nginx dan PHP-FPM. Jadi kita tidak perlu membangun web server dari awal.
Konsep yang akan digunakan kurang lebih seperti ini:
Internet
|
v
Nginx
|
+---- PHP-FPM
|
+---- Rust Application
|
+---- 127.0.0.1:8080
Nginx akan tetap menjadi pintu utama untuk menerima request dari browser. Jika request menuju PHP, Nginx meneruskannya ke PHP-FPM. Sedangkan request menuju /rust akan diteruskan ke aplikasi Rust yang berjalan pada port 8080.
3. Langkah 1 - Instal Rust di Alpine Linux
Hal pertama yang perlu dilakukan adalah memperbarui daftar repository Alpine.
apk update
Selanjutnya instal beberapa paket yang diperlukan. Pada tutorial ini kita akan menggunakan curl, compiler/build tools, Rust, dan Cargo.
apk add curl build-base rust cargo
Setelah proses instalasi selesai, kita dapat mengecek versi Rust.
rustc --version
Kemudian cek Cargo:
cargo --version
Jika keduanya menampilkan nomor versi, berarti Rust dan Cargo sudah berhasil terpasang.
rustc adalah compiler Rust, sedangkan Cargo adalah build system sekaligus package manager yang digunakan untuk mengelola project Rust.
4. Langkah 2 - Membuat Project Rust
Sekarang kita buat project Rust baru menggunakan Cargo.
cargo new hello_world
Perintah tersebut akan membuat folder bernama hello_world sekaligus membuat struktur awal project Rust.
Masuk ke folder tersebut:
cd hello_world
Struktur project yang dibuat oleh Cargo kurang lebih seperti berikut:
hello_world/
├── Cargo.toml
└── src/
└── main.rs
Di sini kita mulai melihat perbedaan dengan project PHP. Pada PHP kita mungkin langsung membuat file seperti index.php. Pada Rust, Cargo membuat struktur project dan mengatur proses build untuk kita.
5. Mengenal Cargo.toml
Sebelum masuk ke kode program, kita lihat terlebih dahulu file Cargo.toml.
File ini merupakan manifest project Rust. Di dalamnya terdapat informasi package, versi package, Rust Edition, dan dependency yang digunakan oleh aplikasi.
Buka file tersebut menggunakan Nano:
nano Cargo.toml
Pada Cargo versi modern, project baru menggunakan format seperti berikut:
[package]
name = "hello_world"
version = "0.1.0"
edition = "2024"
[dependencies]
Untuk tutorial sederhana ini, sebenarnya isi tersebut sudah cukup dan tidak perlu kita ubah.
Mari kita lihat bagian-bagiannya.
a. name
name = "hello_world"
Bagian ini merupakan nama package atau project Rust kita.
b. version
version = "0.1.0"
Ini adalah versi package atau aplikasi yang kita buat. Angka 0.1.0 bukan versi compiler Rust.
c. edition
edition = "2024"
Bagian ini menentukan Rust Edition yang digunakan oleh project.
Perlu diperhatikan bahwa edition = "2024" juga bukan berarti kita sedang menentukan versi compiler menjadi Rust 2024. Edition adalah aturan bahasa dan fitur yang digunakan oleh project.
Rust Edition 2024 tersedia pada Rust 1.85 dan menjadi default untuk project baru pada Cargo modern.
d. dependencies
[dependencies]
Bagian ini digunakan untuk mendefinisikan library atau crate tambahan yang digunakan oleh project.
Pada contoh kali ini kita tidak membutuhkan library tambahan karena web server sederhana yang kita buat hanya menggunakan library standar Rust.
Jadi untuk sementara [dependencies] dibiarkan kosong.
Jika selesai melihat file tersebut, kita bisa keluar dari Nano.
Ctrl + O
Enter
Ctrl + X
Sebenarnya kita tidak perlu melakukan perubahan apa pun pada Cargo.toml. Langkah ini sengaja saya sertakan supaya sejak awal kita mengenal file konfigurasi utama project Rust.
6. Langkah 3 - Mengenal src/main.rs
Sekarang kita masuk ke file utama aplikasi.
nano src/main.rs
Project yang dibuat dengan cargo new biasanya sudah memiliki kode sederhana seperti berikut:
fn main() {
println!("Hello, world!");
}
Fungsi main() merupakan titik awal program ketika aplikasi dijalankan.
Jika kita menjalankan project tersebut menggunakan Cargo, Rust akan menjalankan fungsi main().
Untuk mencobanya, kita bisa menjalankan:
cargo run
Hasilnya kurang lebih:
Hello, world!
Sampai tahap ini kita baru membuat program command-line sederhana. Sekarang kita akan mengubahnya menjadi web server kecil.
7. Langkah 4 - Membuat Web Server Sederhana dengan Rust
Kita akan membuat server HTTP sederhana menggunakan library standar Rust.
Hapus isi src/main.rs kemudian masukkan kode berikut:
Kode tersebut memang terlihat lebih panjang dibandingkan program Hello, world!. Namun sebenarnya konsep dasarnya tetap sederhana.
Kita membuat sebuah TCP listener pada 127.0.0.1:8080, membaca request dari client, kemudian mengirimkan response HTTP yang berisi halaman HTML.
Halaman HTML yang dikirim oleh Rust sengaja dibuat sedikit lebih menarik agar ketika dibuka melalui browser, kita dapat langsung melihat bahwa aplikasi Rust berhasil berjalan.
8. Memahami Bagian Kode Rust
a. Import library standar
use std::io::{Read, Write};
use std::net::TcpListener;
Kita menggunakan beberapa fungsi dari standard library Rust.
Read digunakan untuk membaca data dari koneksi, sedangkan Write digunakan untuk mengirim data kembali kepada client.
Sementara itu TcpListener digunakan untuk membuka port dan menunggu koneksi masuk.
b. Membuka port 8080
let listener = TcpListener::bind("127.0.0.1:8080").expect("Gagal menjalankan server");
Bagian ini membuat aplikasi mendengarkan koneksi pada:
127.0.0.1:8080
Artinya aplikasi Rust hanya mendengarkan koneksi dari komputer/server itu sendiri.
Ini sengaja kita lakukan karena nantinya Nginx yang akan menerima koneksi dari internet dan meneruskannya ke aplikasi Rust.
Dengan pola seperti ini, port aplikasi Rust tidak harus dibuka langsung ke internet.
c. Menunggu koneksi
for stream in listener.incoming() {...
}
Program akan terus menunggu koneksi yang masuk.
Ketika ada browser atau client yang melakukan request, koneksi tersebut akan diproses oleh bagian di dalam loop.
d. Membaca request
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
Bagian ini menyediakan buffer sebesar 1024 byte untuk membaca data request HTTP dari client.
Untuk pembelajaran dasar, kita tidak perlu langsung membuat parser HTTP yang kompleks.
e. Membuat halaman HTML
Kita kemudian membuat sebuah string HTML menggunakan raw string Rust:
let html = r#"..."#;
Penggunaan raw string membuat kita lebih mudah menuliskan HTML dan CSS yang memiliki banyak tanda kutip.
HTML tersebut kemudian dikirim langsung oleh aplikasi Rust kepada browser.
Pada contoh ini saya membuat tampilan berupa card dengan ikon Rust, judul, informasi teknologi yang digunakan, status server, serta alamat 127.0.0.1:8080.
f. Mengirim HTTP Response
Setelah HTML dibuat, kita membentuk response HTTP:
let response = format!(
"HTTP/1.1 200 OK\r\n\
Content-Type: text/html; charset=UTF-8\r\n\
Content-Length: {}\r\n\
Connection: close\r\n\
\r\n\
{}",
html.len(),
html
);
Response tersebut terdiri dari HTTP status 200 OK, content type HTML, panjang data, kemudian isi halaman HTML.
Setelah itu response dikirim menggunakan:
stream.write_all(response.as_bytes()).unwrap();
Dengan demikian browser akan menerima halaman HTML dari aplikasi Rust.
9. Langkah 5 - Menjalankan Rust Server
Setelah file selesai diedit, simpan dengan Nano:
Ctrl + O
Enter
Ctrl + X
Kemudian jalankan project:
cargo run
Jika berhasil, terminal akan menampilkan:
Rust server berjalan di http://127.0.0.1:8080
Jangan tutup terminal tersebut karena aplikasi masih berjalan di foreground.
10. Menguji Server dengan curl
Kita bisa membuka terminal lain dan mencoba melakukan request ke aplikasi Rust.
curl http://127.0.0.1:8080
Karena aplikasi mengembalikan HTML, terminal akan menampilkan source HTML halaman tersebut.
Jika ingin melihat apakah server benar-benar memberikan HTTP response yang benar, kita juga bisa menggunakan:
curl -I http://127.0.0.1:8080
Kurang lebih kita akan mendapatkan response seperti:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length:...
Connection: close
11. Kenapa Tidak Langsung Dibuka dari Internet?
Pada contoh ini kita menggunakan:
127.0.0.1:8080
bukan:
0.0.0.0:8080
Karena kita ingin Nginx menjadi reverse proxy di depan aplikasi Rust.
Dengan desain tersebut, alurnya menjadi:
Browser
|
v
Nginx: 80/443
|
v
Rust: 127.0.0.1:8080
Keuntungannya, aplikasi Rust tidak perlu berhubungan langsung dengan koneksi publik. Nginx tetap menangani akses dari luar, sedangkan Rust berjalan sebagai backend.
12. Langkah 6 - Build Rust Menjadi Binary
Salah satu hal menarik dari Rust adalah aplikasi dapat dikompilasi menjadi binary executable.
Untuk membuat build release, jalankan:
cargo build --release
Jika proses berhasil, Cargo akan membuat folder:
target/release/
Binary aplikasi kita berada di:
target/release/hello_world
Kita dapat melihatnya dengan:
ls -lh target/release/hello_world
Berbeda dengan aplikasi PHP yang biasanya dijalankan melalui PHP-FPM, pada tahap ini kita sudah memiliki binary hasil kompilasi Rust yang dapat dijalankan secara langsung.
13. Langkah 7 - Menjalankan Binary Rust
Sebelum menjalankan binary hasil build, pastikan instance cargo run yang sebelumnya masih berjalan sudah dihentikan terlebih dahulu dengan:
Ctrl + C
Kemudian jalankan binary:
./target/release/hello_world
Jika berhasil, aplikasi akan kembali mendengarkan port:
127.0.0.1:8080
Sampai tahap ini kita sudah tidak membutuhkan cargo run untuk menjalankan aplikasi hasil build tersebut.
14. Menjalankan Rust di Background
Untuk percobaan sederhana, kita dapat menjalankan binary menggunakan nohup.
Hentikan aplikasi yang sedang berjalan di foreground terlebih dahulu dengan Ctrl + C, kemudian jalankan:
Perintah tersebut membuat aplikasi tetap berjalan walaupun session terminal ditutup.
Output aplikasi diarahkan ke file:
app.log
Kita dapat melihat log menggunakan:
cat app.log
Atau jika ingin melihat log secara langsung ketika aplikasi berjalan:
tail -f app.log
15. Langkah 8 - Mengecek Apakah Rust Masih Berjalan
Kita dapat memeriksa proses Rust dengan:
ps | grep hello_world
Kita juga dapat mengecek apakah port 8080 sedang digunakan:
netstat -lntp | grep 8080
Jika perintah netstat belum tersedia pada sistem, cara lain adalah menggunakan:
ss -lntp | grep 8080
Tujuannya adalah memastikan aplikasi Rust benar-benar sedang mendengarkan koneksi pada port tersebut.
16. Langkah 9 - Menghubungkan Rust dengan Nginx
Sekarang bagian yang menarik. Kita akan membuat aplikasi Rust dapat diakses melalui Nginx.
Misalnya website kita sudah menggunakan Nginx dan PHP-FPM. Kita tidak perlu mengganti konfigurasi PHP yang sudah ada.
Kita cukup menambahkan location baru untuk Rust.
Tambahkan konfigurasi berikut pada server block Nginx:
Setelah konfigurasi Nginx ditambahkan, jangan langsung melakukan reload. Sebaiknya periksa terlebih dahulu apakah konfigurasi tersebut valid.
nginx -t
Jika tidak terdapat error, lakukan reload:
nginx -s reload
Reload berbeda dengan restart. Dengan reload, Nginx membaca konfigurasi baru tanpa perlu menghentikan seluruh service terlebih dahulu.
19. Mencoba dari Browser
Jika semuanya sudah berjalan, buka alamat:
https://domain-anda.com/rust
Jika konfigurasi benar, browser akan menampilkan halaman yang dibuat oleh aplikasi Rust.
Kurang lebih tampilannya akan berisi:
Ikon Rust 🦀
Judul Rust Berhasil Berjalan!
Keterangan bahwa aplikasi berjalan di Alpine Linux.
Badge Rust + Alpine Linux + Nginx.
Yang menarik, halaman tersebut bukan dibuat oleh PHP dan bukan pula file HTML statis yang dibaca langsung oleh Nginx. HTML tersebut dikirim langsung oleh aplikasi Rust.
20. Memahami Arsitektur yang Kita Buat
Setelah seluruh langkah selesai, arsitektur kita menjadi seperti ini:
INTERNET
|
v
+-----------+
| Nginx |
+-----------+
/ \
/ \
v v
PHP-FPM Rust:8080
|
v
HTML Response
Ketika user membuka halaman PHP, Nginx meneruskannya ke PHP-FPM.
Ketika user membuka /rust, Nginx meneruskan request tersebut ke aplikasi Rust pada 127.0.0.1:8080.
Dengan demikian kita tidak perlu memindahkan seluruh website PHP ke Rust hanya untuk mulai belajar Rust.
21. Perbedaan Pendekatan PHP dan Rust
Bagi pengguna PHP, mungkin perbedaan paling terasa adalah cara menjalankan aplikasinya.
PHP
Rust
Source code .php
Source code .rs
Dijalankan melalui PHP runtime
Dikompilasi menjadi binary
PHP-FPM umum digunakan sebagai backend
Program Rust dapat berjalan sebagai proses/service sendiri
Dependency dapat dikelola Composer
Dependency dapat dikelola Cargo
composer.json
Cargo.toml
Konsepnya memang berbeda, tetapi ada beberapa kemiripan. Misalnya, Cargo dapat menangani dependency dan build project sehingga developer tidak perlu mengatur semuanya secara manual.
22. Kenapa Cargo Penting?
Kalau baru belajar Rust, kita akan cukup sering bertemu dengan Cargo.
Beberapa perintah yang paling sering digunakan antara lain:
a. Membuat project
cargo new hello_world
Membuat project baru.
b. Menjalankan project
cargo run
Melakukan compile dan menjalankan aplikasi.
c. Build development
cargo build
Melakukan build untuk development.
d. Build release
cargo build --release
Melakukan build release yang menghasilkan binary pada folder target/release.
e. Memeriksa kode
cargo check
Memeriksa kode tanpa perlu menghasilkan binary release.
f. Menghapus hasil build
cargo clean
Menghapus hasil build sebelumnya.
Jika nantinya kita mulai menggunakan library dari luar, dependency tersebut juga akan ditulis pada Cargo.toml.
23. Apakah Contoh Web Server Ini Cocok untuk Production?
Tidak.
Contoh yang kita buat sengaja dibuat sesederhana mungkin agar kita dapat memahami dasar cara kerja Rust dan HTTP.
Server tersebut belum memiliki banyak fitur yang dibutuhkan oleh web server production, misalnya:
HTTP parser yang lengkap.
Routing yang lebih baik.
Concurrent request handling yang proper.
Connection management.
Logging production.
Error handling yang lengkap.
HTTPS secara langsung.
Middleware.
Authentication.
Graceful shutdown.
Untuk aplikasi sebenarnya, kita biasanya akan menggunakan framework atau library HTTP yang memang dirancang untuk kebutuhan tersebut.
Namun untuk belajar dasar Rust, contoh ini cukup menarik karena kita bisa melihat bagaimana sebuah program Rust dapat membuka port, menerima koneksi TCP, membaca request, dan mengirim response HTTP tanpa menggunakan framework besar.
24. Kenapa Belajar Rust Jika Sudah Bisa PHP?
Bagi pengguna PHP, menurut saya belajar Rust tidak harus berarti meninggalkan PHP.
PHP tetap sangat praktis untuk membuat website, CMS, dashboard, aplikasi bisnis, dan berbagai kebutuhan web lainnya.
Rust memberikan perspektif yang berbeda mengenai bagaimana aplikasi dikompilasi dan dijalankan.
Kita mulai mengenal konsep seperti:
Static typing.
Ownership.
Borrowing.
Memory safety.
Struct.
Enum.
Trait.
Concurrency.
Compile-time checking.
Justru karena sudah terbiasa dengan PHP, kita bisa menggunakan pengalaman tersebut sebagai pembanding ketika mempelajari Rust.
25. Pengembangan Selanjutnya
Contoh pada tutorial ini masih sangat sederhana. Setelah memahami dasar-dasarnya, project dapat dikembangkan lebih jauh.
Misalnya kita bisa mencoba membuat:
Web server dengan routing.
REST API menggunakan Rust.
Aplikasi CRUD.
Koneksi Rust ke MySQL atau MariaDB.
Autentikasi user.
Backend untuk aplikasi JavaScript.
Aplikasi dengan framework Rust.
Service atau API yang berjalan di belakang Nginx.
Dengan demikian, proses belajar tidak harus langsung dimulai dari project besar. Kita dapat memulai dari server kecil seperti ini, kemudian menambahkan kemampuan satu per satu.
26. Kesimpulan
Pada tutorial kali ini saya mencoba menjalankan Rust di Alpine Linux yang sebelumnya sudah digunakan untuk Nginx dan PHP-FPM.
Kita mulai dari instalasi Rust dan Cargo, membuat project menggunakan cargo new, mengenal Cargo.toml, membuat program pada src/main.rs, kemudian mengubahnya menjadi web server sederhana yang berjalan pada port 8080.
Setelah itu aplikasi Rust kita build menggunakan:
cargo build --release
Binary hasil build kemudian dapat dijalankan secara langsung dan dihubungkan dengan Nginx menggunakan reverse proxy.
Dengan pendekatan tersebut, server yang sebelumnya digunakan untuk PHP tidak harus dirombak. PHP-FPM tetap berjalan seperti biasa, sedangkan Rust dapat berjalan sebagai aplikasi backend tersendiri.
Bagi saya, cara seperti ini cukup menarik untuk mulai belajar Rust karena tidak perlu langsung membuat project besar. Kita bisa memulai dari aplikasi kecil, memahami bagaimana Cargo bekerja, memahami proses compile, kemudian secara bertahap belajar framework dan library Rust yang lebih lengkap.
Pada tahap berikutnya, project sederhana ini bisa dikembangkan menjadi aplikasi yang lebih serius, misalnya menggunakan routing, template HTML, koneksi database MySQL/MariaDB, REST API, atau bahkan membuat backend Rust yang kemudian digunakan bersama frontend JavaScript.
Komentar 0