2 poin oleh GN⁺ 2024-09-26 | 1 komentar | Bagikan ke WhatsApp

My Blog Technology

Server web ini adalah server web minimal yang dirancang untuk meng-host blog saya. Sejak awal dibuat kokoh agar mampu bertahan di internet publik. Tidak memerlukan reverse proxy. Anda bisa melihatnya berjalan langsung di http://playin.coz.is/index.html. Saya sempat meminta Reddit untuk mencoba meretasnya dan berhasil mengumpulkan log permintaan yang menarik sekaligus berbahaya hingga ukuran gigabita. Sebagiannya disimpan di attempts.txt, dan nanti akan saya telusuri lagi untuk bersenang-senang.

Tapi.. kenapa?

Saya suka membuat alat saya sendiri, dan saya lelah mendengar bahwa semuanya harus "battle-tested". Kalau terjadi crash, lalu bagaimana? Bug bisa diperbaiki.

Spesifikasi

  • Khusus Linux
  • Implementasi HTTP/1.1, pipelining, dan koneksi keep-alive
  • Mendukung HTTPS (menggunakan BearSSL hingga TLS 1.2)
  • Dependensi minimal (libc dan BearSSL saat menggunakan HTTPS)
  • Timeout yang dapat dikonfigurasi
  • Log akses, log crash, rotasi log, pembatasan penggunaan disk
  • Tidak ada Transfer-Encoding: Chunked (merespons dengan 411 Length Required untuk mendorong klien mengirim ulang dengan Content-Length)
  • Satu core (akan diubah saat mendapatkan VPS yang lebih baik)
  • Belum ada caching file statis

Benchmark

Fokus proyek ini adalah ketangguhan, tetapi sama sekali tidak lambat. Perbandingan sederhana dengan nginx (endpoint statis, keduanya single-thread, batas 1K koneksi):

  • (blogtech)

    $ wrk -c 500 -d 5s http://127.0.0.1:80/hello
    
    • Latensi rata-rata: 6.66ms
    • Permintaan/detik: 76974.24
    • Transfer/detik: 6.09MB
  • (nginx)

    $ wrk -c 500 -d 5s http://127.0.0.1:8080/hello
    
    • Latensi rata-rata: 149.11ms
    • Permintaan/detik: 44227.78
    • Transfer/detik: 8.27MB

Konfigurasi nginx:

worker_processes 1;
events {
  worker_connections 1024;
}
http {
  server {
    listen 8080;
    location /hello {
      add_header Content-Type text/plain;
      return 200 "Hello, world!";
    }
  }
}

Build dan jalankan

Secara default, build server hanya untuk HTTP:

$ make

Perintah ini akan menghasilkan executable serve (build rilis), serve_cov (build cakupan), dan serve_debug (build debug). Build rilis mendengarkan di port 80, dan build debug di port 8080.

Untuk mengaktifkan HTTPS, Anda perlu meng-clone dan membangun BearSSL:

$ mkdir 3p
$ cd 3p
$ git clone https://www.bearssl.org/git/BearSSL
$ cd BearSSL
$ make -j
$ cd ../../
$ make -B HTTPS=1

Executable yang sama akan dihasilkan, tetapi koneksi aman akan tersedia di port 443 (rilis) atau 8081 (debug). Anda harus menempatkan file cert.pem dan key.pem di direktori yang sama dengan executable. Untuk mengubah nama dan lokasinya, modifikasi:

#define HTTPS_KEY_FILE "key.pem"
#define HTTPS_CERT_FILE "cert.pem"

Untuk menguji HTTPS secara lokal, buat sertifikat self-signed (beserta private key):

openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
openssl req -new -x509 -key key.pem -out cert.pem -days 365

Penggunaan

Server menyajikan konten statis dari folder docroot/. Untuk mengubahnya, modifikasi fungsi respond:

typedef struct {
  Method method;
  string path;
  int major;
  int minor;
  int nheaders;
  Header headers[MAX_HEADERS];
  string content;
} Request;

void respond(Request request, ResponseBuilder *b) {
  if (request.major != 1 || request.minor > 1) {
    status_line(b, 505); // HTTP Version Not Supported
    return;
  }

  if (request.method != M_GET) {
    status_line(b, 405); // Method Not Allowed
    return;
  }

  if (string_match_case_insensitive(request.path, LIT("/hello"))) {
    status_line(b, 200);
    append_content_s(b, LIT("Hello, world!"));
    return;
  }

  if (serve_file_or_dir(b, LIT("/"), LIT("docroot/"), request.path, NULLSTR, false))
    return;

  status_line(b, 404);
  append_content_s(b, LIT("Nothing here :|"));
}

Di sini Anda dapat menambahkan endpoint dengan mencabangkan field request.path. Path hanyalah slice dari buffer permintaan. URI tidak di-parse.

Pengujian

Saya rutin menjalankan server dengan valgrind dan sanitizers (address, undefined), lalu menargetkannya dengan wrk. Saya juga menambahkan pengujian otomatis di tests/test.py untuk memeriksa kepatuhan terhadap spesifikasi HTTP/1.1. Saya menjaga beban tetap ada dengan meng-host situs web saya sendiri dan mempostingnya di berbagai tempat. Semua bot di internet yang memindai situs web rentan menjadi fuzzer yang hebat.

Masalah yang diketahui

  • Server merespons klien HTTP/1.0 dengan HTTP/1.1

Kontribusi

Saya terutama bekerja di branch DEV dan sesekali menggabungkannya ke MAIN. Saat membuka pull request, akan lebih mudah jika menargetkan DEV.

Ringkasan GN⁺

  • Proyek ini adalah server web yang menargetkan dependensi minimal dan ketangguhan.
  • Mendukung HTTP/1.1 dan HTTPS, serta menyediakan berbagai fitur logging dan timeout yang dapat dikonfigurasi.
  • Hasil benchmark menunjukkan waktu respons yang lebih cepat daripada nginx.
  • Dirancang agar pengembang dapat menikmati proses membuat alat mereka sendiri dan memperbaiki bug.
  • Proyek serupa dengan fungsi sebanding mencakup Nginx dan Apache HTTP Server.

1 komentar

 
GN⁺ 2024-09-26
Komentar Hacker News
  • Tidak perlu reverse proxy: Menggunakan Jetty untuk menerapkan aplikasi ke internet tanpa reverse proxy dan tidak mengalami masalah

    • Banyak pendapat yang menyarankan penggunaan reverse proxy tanpa alasan spesifik terkait keamanan atau performa
    • Meragukan apakah reverse proxy benar-benar diperlukan
  • Server web C buatan sendiri: Membuat server web C yang pernah digunakan untuk menjalankan situs web komersial

    • Menangani banyak trafik dengan RAM 128MB dan 1 CPU
    • Menyebut bahwa lingkungan internet 20 tahun lalu tidak seagresif sekarang
    • Bot berperan sebagai fuzzer yang sangat baik, tetapi fuzzing yang sebenarnya juga tetap diperlukan
  • Kepuasan membangun layanan: Sangat memuaskan membangun layanan dasar dengan menggunakan API sistem

    • Terkejut karena fungsi poll() menunjukkan performa yang tinggi
    • Fungsi per koneksi serta struct dan array terkait mirip dengan nginx, redis, dan memcached
    • Pekerjaan yang luar biasa
  • Perkenalan proyek kecil: Memperkenalkan proyek menarik yang dimulai saat waktu luang

  • Rekomendasi framework Kore: Jika menulis aplikasi C dan merasa tidak nyaman menulis bagian yang terekspos ke publik, merekomendasikan framework Kore

    • Fitur seperti pengelolaan sertifikat ACME, Pgsql, curl, dan WebSocket sudah terintegrasi
    • Dapat membangun dan menjalankan modul dengan mencampurkan Lua/Python dan C
  • Berbagi tautan menarik: Instance althttpd milik sqlite.org menangani lebih dari 500 ribu permintaan HTTP per hari

    • Menyajikan 200GB konten dari Linode seharga $40/bulan
    • 19% permintaan HTTP mengakses repositori kode sumber Fossil melalui CGI
  • Kesenangan membuat alat sendiri: Lelah dengan pendapat bahwa semua hal harus "battle-tested"

    • Bug bisa diperbaiki
  • Ceramah Chaos Communication Congress: Mengingat ceramah tentang blog/server web yang ditulis dalam C dengan fitur keamanan bawaan

    • Mencakup fitur seperti penyimpanan immutable, penurunan hak akses, dan tidak adanya akses ke sertifikat TLS
  • Situs web yang stabil: Situs web yang tidak crash meskipun tampil di halaman depan

  • Kembali ke dasar: Menyukai pendekatan kembali ke dasar dengan hanya menggunakan yang diperlukan

    • Mempertanyakan dampak fitur perangkat lunak yang tidak perlu terhadap performa
    • Menyampaikan ucapan selamat kepada pengembang