GN⁺: HN에 공개: C 웹 서버를 사용한 웹사이트 호스팅
(github.com/cozis)My Blog Technology
이 웹 서버는 내 블로그를 호스팅하기 위해 설계된 최소한의 웹 서버임. 처음부터 공용 인터넷에 견딜 수 있도록 견고하게 제작되었음. 리버스 프록시가 필요하지 않음. 실제 동작하는 모습을 http://playin.coz.is/index.html에서 볼 수 있음. Reddit에 해킹을 요청하여 재미있고 악의적인 요청 로그를 기가바이트 단위로 수집했음. 일부는 attempts.txt
에 저장했고, 나중에 재미로 더 찾아볼 예정임.
하지만.. 왜?
나는 나만의 도구를 만드는 것을 즐기며, 모든 것이 "전투 테스트"되어야 한다는 말을 듣는 것에 지쳤음. 충돌이 발생하면 어쩔 것인가? 버그는 수정할 수 있음.
사양
- Linux 전용
- HTTP/1.1, 파이프라이닝, keep-alive 연결 구현
- HTTPS 지원 (BearSSL을 사용하여 TLS 1.2까지)
- 최소한의 종속성 (HTTPS 사용 시 libc와 BearSSL)
- 구성 가능한 타임아웃
- 접근 로그, 충돌 로그, 로그 회전, 디스크 사용량 제한
-
Transfer-Encoding: Chunked
없음 (411 Length Required
로 응답하여 클라이언트가Content-Length
와 함께 다시 전송하도록 유도) - 단일 코어 (더 나은 VPS를 얻으면 변경될 예정)
- 정적 파일 캐싱 없음 (아직)
벤치마크
이 프로젝트의 초점은 견고성에 있지만, 결코 느리지 않음. nginx와의 간단한 비교 (정적 엔드포인트, 둘 다 단일 스레드, 1K 연결 제한):
-
(blogtech)
$ wrk -c 500 -d 5s http://127.0.0.1:80/hello
- 평균 대기 시간: 6.66ms
- 요청/초: 76974.24
- 전송/초: 6.09MB
-
(nginx)
$ wrk -c 500 -d 5s http://127.0.0.1:8080/hello
- 평균 대기 시간: 149.11ms
- 요청/초: 44227.78
- 전송/초: 8.27MB
nginx 설정:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location /hello {
add_header Content-Type text/plain;
return 200 "Hello, world!";
}
}
}
빌드 및 실행
기본적으로 서버 빌드는 HTTP 전용임:
$ make
이 명령은 serve
(릴리스 빌드), serve_cov
(커버리지 빌드), serve_debug
(디버그 빌드) 실행 파일을 생성함. 릴리스 빌드는 포트 80에서, 디버그 빌드는 포트 8080에서 청취함.
HTTPS를 활성화하려면 BearSSL을 클론하고 빌드해야 함:
$ mkdir 3p
$ cd 3p
$ git clone https://www.bearssl.org/git/BearSSL
$ cd BearSSL
$ make -j
$ cd ../../
$ make -B HTTPS=1
동일한 실행 파일이 생성되지만, 포트 443 (릴리스) 또는 8081 (디버그)에서 보안 연결이 가능함. cert.pem
과 key.pem
파일을 실행 파일과 동일한 디렉토리에 배치해야 함. 이름과 위치를 변경하려면 다음을 수정:
#define HTTPS_KEY_FILE "key.pem"
#define HTTPS_CERT_FILE "cert.pem"
로컬에서 HTTPS로 테스트하려면 자체 서명된 인증서(및 개인 키)를 생성:
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
openssl req -new -x509 -key key.pem -out cert.pem -days 365
사용법
서버는 docroot/
폴더에서 정적 콘텐츠를 제공함. 이를 변경하려면 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 :|"));
}
여기에서 request.path
필드를 전환하여 엔드포인트를 추가할 수 있음. 경로는 요청 버퍼의 슬라이스일 뿐임. URI는 파싱되지 않음.
테스트
서버를 valgrind와 sanitizers (주소, 정의되지 않음)로 정기적으로 실행하고 wrk
를 사용하여 타겟팅함. 또한 HTTP/1.1 사양 준수를 확인하기 위해 tests/test.py
에 자동화된 테스트를 추가하고 있음. 내 웹사이트를 호스팅하고 여기저기 게시하여 스트레스를 유지함. 인터넷에서 취약한 웹사이트를 스캔하는 모든 봇이 훌륭한 퍼저가 됨.
알려진 문제
- 서버가 HTTP/1.0 클라이언트에 HTTP/1.1로 응답함
기여
나는 주로 DEV 브랜치에서 작업하고 가끔 MAIN으로 병합함. 풀 리퀘스트를 열 때 DEV를 타겟으로 하면 더 쉬워질 것임.
GN⁺의 정리
- 이 프로젝트는 최소한의 종속성과 견고성을 목표로 하는 웹 서버임.
- HTTP/1.1과 HTTPS를 지원하며, 다양한 로그 기능과 구성 가능한 타임아웃을 제공함.
- 벤치마크 결과 nginx보다 빠른 응답 시간을 보여줌.
- 개발자들이 자신의 도구를 만들고 버그를 수정하는 과정을 즐길 수 있도록 설계됨.
- 비슷한 기능을 가진 프로젝트로는 Nginx와 Apache HTTP Server가 있음.
Hacker News 의견
-
역방향 프록시 필요 없음: Jetty를 사용해 역방향 프록시 없이 앱을 인터넷에 배포해도 문제가 없었음
- 보안이나 성능에 대한 구체적인 이유 없이 역방향 프록시를 사용하라는 의견이 많음
- 역방향 프록시가 정말 필요한지 의문을 가짐
-
자체 제작한 C 웹 서버: 상업용 웹사이트를 운영했던 C 웹 서버를 제작했음
- 128MB RAM과 1 CPU로 많은 트래픽을 처리했음
- 20년 전 인터넷 환경이 덜 적대적이었음을 언급함
- 봇이 훌륭한 퍼저(fuzzer) 역할을 하지만 실제 퍼징도 필요함
-
서비스 구축의 만족감: 시스템 API를 사용해 기본적인 서비스를 구축하는 것이 매우 만족스러움
- poll() 함수가 높은 성능을 보여주는 것에 놀람
- 연결별 함수와 관련 구조체, 배열이 nginx, redis, memcached와 유사함
- 훌륭한 작업임
-
작은 프로젝트 소개: 여가 시간에 시작한 재미있는 프로젝트를 소개함
-
Kore 프레임워크 추천: C 앱을 작성할 때 공개된 부분을 작성하는 것이 불편하다면 Kore 프레임워크를 추천함
- ACME 인증서 관리, Pgsql, curl, 웹소켓 등의 기능이 내장되어 있음
- Lua/Python과 C를 혼합하여 모듈을 빌드하고 실행할 수 있음
-
흥미로운 링크 공유: sqlite.org의 althttpd 인스턴스가 하루에 50만 개 이상의 HTTP 요청을 처리함
- $40/월 Linode에서 200GB의 콘텐츠를 제공함
- HTTP 요청의 19%가 CGI를 통해 Fossil 소스 코드 저장소에 접근함
-
자체 도구 제작의 즐거움: 모든 것이 "전투 테스트"되어야 한다는 의견에 지침
- 버그는 수정할 수 있음
-
Chaos Communication Congress 강연: 보안 기능이 포함된 C로 작성된 블로그/웹 서버에 대한 강연을 상기시킴
- 불변 저장소, 권한 축소, TLS 인증서 접근 불가 등의 기능이 포함됨
-
안정적인 웹사이트: 첫 페이지에 표시되어도 크래시하지 않는 웹사이트
-
기본으로 돌아가기: 필요한 것만 사용하여 기본으로 돌아가는 접근 방식을 좋아함
- 소프트웨어의 불필요한 기능이 성능에 미치는 영향을 의문시함
- 개발자에게 축하 인사를 전함