HN पर साझा: C web server का उपयोग करके वेबसाइट होस्ट करना
(github.com/cozis)My Blog Technology
यह web server मेरे ब्लॉग को होस्ट करने के लिए डिज़ाइन किया गया एक न्यूनतम web server है। इसे शुरू से ही इस तरह मज़बूती से बनाया गया है कि यह सार्वजनिक इंटरनेट पर टिक सके। reverse proxy की आवश्यकता नहीं है। आप इसे काम करते हुए http://playin.coz.is/index.html पर देख सकते हैं। मैंने मज़े के लिए Reddit पर लोगों से इसे hack करने की कोशिश करने को कहा और दिलचस्प व दुर्भावनापूर्ण request logs को gigabytes में इकट्ठा किया। उनमें से कुछ को attempts.txt में रखा है, और बाद में मज़े के लिए और भी देखूँगा।
लेकिन.. क्यों?
मुझे अपने खुद के tools बनाना पसंद है, और मैं यह सुन-सुनकर थक गया था कि हर चीज़ को "battle-tested" होना चाहिए। अगर crash हो जाए तो क्या? bugs को ठीक किया जा सकता है।
विनिर्देश
- केवल Linux
- HTTP/1.1, pipelining, keep-alive connections implemented
- HTTPS समर्थन (BearSSL का उपयोग करके TLS 1.2 तक)
- न्यूनतम dependencies (HTTPS के लिए libc और BearSSL)
- configurable timeouts
- access logs, crash logs, log rotation, disk usage limits
Transfer-Encoding: Chunkedनहीं (411 Length Requiredके साथ response देता है ताकि clientContent-Lengthके साथ फिर से भेजे)- single core (बेहतर VPS मिलने पर बदलेगा)
- static file caching नहीं (अभी)
बेंचमार्क
इस project का फोकस robustness है, लेकिन यह किसी भी तरह से धीमा नहीं है। nginx के साथ एक सरल तुलना (static endpoint, दोनों single-threaded, 1K connection limit):
-
(blogtech)
$ wrk -c 500 -d 5s http://127.0.0.1:80/hello- औसत latency: 6.66ms
- requests/sec: 76974.24
- transfer/sec: 6.09MB
-
(nginx)
$ wrk -c 500 -d 5s http://127.0.0.1:8080/hello- औसत latency: 149.11ms
- requests/sec: 44227.78
- transfer/sec: 8.27MB
nginx configuration:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location /hello {
add_header Content-Type text/plain;
return 200 "Hello, world!";
}
}
}
build और run
डिफ़ॉल्ट रूप से server build केवल HTTP के लिए है:
$ make
यह command serve (release build), serve_cov (coverage build), serve_debug (debug build) executable files बनाता है। release build port 80 पर listen करता है, और debug build port 8080 पर।
HTTPS सक्षम करने के लिए BearSSL को clone और build करना होगा:
$ mkdir 3p
$ cd 3p
$ git clone https://www.bearssl.org/git/BearSSL
$ cd BearSSL
$ make -j
$ cd ../../
$ make -B HTTPS=1
वही executable files बनती हैं, लेकिन अब port 443 (release) या 8081 (debug) पर secure connections संभव हैं। cert.pem और key.pem files को executable के उसी directory में रखना होगा। नाम और location बदलने के लिए यह संशोधित करें:
#define HTTPS_KEY_FILE "key.pem"
#define HTTPS_CERT_FILE "cert.pem"
स्थानीय रूप से HTTPS के साथ test करने के लिए self-signed certificate (और 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
उपयोग
server docroot/ folder से static content serve करता है। इसे बदलने के लिए respond function को संशोधित करें:
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 :|"));
}
यहाँ आप request.path field पर switch करके endpoints जोड़ सकते हैं। path सिर्फ request buffer का एक slice है। URI parse नहीं किया जाता।
testing
मैं नियमित रूप से server को valgrind और sanitizers (address, undefined) के साथ चलाता हूँ और wrk से target करता हूँ। साथ ही HTTP/1.1 spec compliance जाँचने के लिए tests/test.py में automated tests जोड़ रहा हूँ। मैं अपनी वेबसाइट को इसी पर होस्ट करके और इधर-उधर पोस्ट करके stress बनाए रखता हूँ। इंटरनेट पर कमजोर websites scan करने वाले सभी bots बेहतरीन fuzzers बन जाते हैं।
ज्ञात समस्याएँ
- server HTTP/1.0 clients को HTTP/1.1 में response देता है
योगदान
मैं ज़्यादातर DEV branch पर काम करता हूँ और कभी-कभी MAIN में merge करता हूँ। pull request खोलते समय DEV को target करना आसान रहेगा।
GN⁺ का सारांश
- यह project न्यूनतम dependencies और robustness पर केंद्रित एक web server है।
- यह HTTP/1.1 और HTTPS का समर्थन करता है, और विभिन्न logging features व configurable timeouts देता है।
- benchmark परिणाम nginx की तुलना में तेज़ response time दिखाते हैं।
- इसे इस तरह डिज़ाइन किया गया है कि developers अपने tools बना सकें और bugs को ठीक करने की प्रक्रिया का आनंद ले सकें।
- समान features वाले projects में Nginx और Apache HTTP Server शामिल हैं।
1 टिप्पणियां
Hacker News की राय
reverse proxy की ज़रूरत नहीं: Jetty का उपयोग करके reverse proxy के बिना भी ऐप को इंटरनेट पर deploy किया गया और कोई समस्या नहीं हुई
खुद बनाया गया C web server: एक C web server बनाया गया था जिसने commercial website चलाई थी
service बनाने की संतुष्टि: system API का उपयोग करके बुनियादी services बनाना बहुत संतोषजनक है
poll()function का इतना अच्छा performance देखकर हैरानी होती हैछोटे प्रोजेक्ट का परिचय: फुर्सत के समय में शुरू किया गया एक मज़ेदार प्रोजेक्ट पेश किया गया
Kore framework की सिफारिश: अगर C app लिखते समय public-facing हिस्सा लिखना असुविधाजनक लगे, तो Kore framework की सिफारिश की जाती है
दिलचस्प लिंक साझा: sqlite.org का althttpd instance हर दिन 5 लाख से ज़्यादा HTTP requests संभालता है
अपने tools बनाने का आनंद: इस बात से थकान है कि हर चीज़ को "battle-tested" होना चाहिए
Chaos Communication Congress का व्याख्यान: security features के साथ C में लिखे गए blog/web server पर एक talk की याद दिलाता है
स्थिर website: ऐसा website जो front page पर दिखने पर भी crash नहीं होता
बुनियाद की ओर वापसी: सिर्फ़ ज़रूरी चीज़ों का उपयोग करके basics पर लौटने वाला तरीका पसंद आया