1994년에 동적 웹사이트를 만들고 싶으면 C 프로그램을 작성해 cgi-bin 디렉터리에 넣고 아파치가 요청마다 프로세스를 포크하게 했다. 한 개발자가 그로부터 30여 년이 지난 지금, 본질적으로 같은 기술로 상용 웹 제품을 출시했다. marketyour.games는 사용자 계정, 콘텐츠 크리에이터를 위한 검색 대시보드, 이를 정리하는 폴더, Stripe 결제, Postmark를 통한 트랜잭션 이메일을 갖춘 어엿한 현대적 서비스다. 점진적 향상(progressive enhancement) 원칙을 따르며 자바스크립트 없이도 동작한다. 제품의 기능은 현대적이지만, 만든 방식과 서빙하는 방식만큼은 옛날 그대로다.
BCHS라는 선택
저자가 택한 스택은 BCHS, 즉 OpenBSD·C·httpd·SQLite다. 프레임워크가 없으니 CGI 환경 변수를 읽고 응답하는 C 프로그램을 직접 쓴다. 템플릿 언어도 없어서 HTML을 C 코드로 직접 출력한다. 별도의 데이터베이스 서버 프로세스 대신 SQLite의 C API로 데이터베이스 파일을 직접 연다. 컨테이너도 없이 정적 링크된 바이너리 하나를 폴더에 떨어뜨리면 끝이다. 전체 구조가 '머릿속에 다 들어오는' 수준으로 단순하다는 것이 핵심 주장이다.
이 모델에서 배포는 파일 하나를 교체하는 일이다. 요청마다 새 프로세스가 뜨기 때문에 서버 재시작도, 다운타임도 없다. 새 요청이 자연스럽게 새 바이너리를 집어 든다. OpenBSD는 pledge와 unveil 같은 도구로 C 프로그램을 실제로 샌드박싱할 수 있게 해주고, httpd는 기본적으로 chroot 환경에서 서빙하므로 CGI 바이너리가 파일시스템의 제한된 영역에 갇혀 실행된다. 빌드 의존성으로는 libcurl과 libsodium 두 개만이 실제로 필요하며, 둘 다 프로젝트에 포함(vendored)해 함께 빌드한다. 클린 빌드는 몇 초, 재빌드는 0.5초 이내다. 정적 자산조차 전통적인 방식 대신 전부 실행 파일에 컴파일해 메모리에서 서빙한다.
CGI를 다시 보는 이유
저자의 논점은 CGI를 2000년대 초에 버린 이유 대부분이 2026년에는 더 이상 유효하지 않다는 것이다. CGI 1.1 명세는 2004년에 공표된 뒤 바뀌지 않았다. 익혀야 할 프레임워크도, 내재화할 API도 없고 HTTP를 이해하면 CGI를 이미 이해한 셈이라는 설명이다. 언어·플랫폼에 무관하니 한 번 배워두면 지식이 영원히 유효하다. 전형적인 현대 스택이 nginx를 앞단에 두고 Ruby·Python·Go·Rust로 짠 애플리케이션 서버로 리버스 프록시하는 구조, 즉 사실상 웹 서버 두 개를 두고 그중 하나가 비즈니스 로직까지 맡는 구조와 대비된다. CGI에서는 단일 웹 서버가 비즈니스 로직을 직접 호출하므로 역할 분담이 명확하다. 디버깅도 쉬워서, 애플리케이션이 그냥 셸에서 실행 가능한 평범한 프로그램이라 요청을 파이프로 넣고 stderr를 보며 gdb로 단계 실행할 수 있다. 저자는 이 구조를 벤더와 '깜짝 청구서'가 빠진 서버리스에 비유한다.
공급망 관점의 이점도 강조된다. 자율 에이전트가 늘고 패키지 저장소가 매주 공격받는 상황에서, 의존성이 거의 없다는 점은 안심이 된다는 것이다. 현대 스택은 직접 의존성 한둘이 수백 개의 간접 의존성을 끌어오고, 그 각각을 얼굴도 모르는 사람이 2015년부터 재사용한 비밀번호로 관리하기도 한다. 반면 이 제품의 공급망은 C 컴파일러와 세 개의 라이브러리뿐이며, 이를 뚫으려면 온 인터넷이 지켜보는 libcurl 같은 프로젝트를 침해해야 한다. 도구 환경도 미니멀하다. 저자는 플러그인 없는 순정 Vim을 쓴다. 스택이 단순하니 LSP도, 자동완성도, 포매터도, AI도 필요 없다. 그러면서도 필요할 때 쓸 수 있는 sanitizer, valgrind, gdb, ctags, cscope 같은 '잘 숙성된' 도구들은 패키지 설치 한 번 거리에 있고, Vim은 ctags·cscope와 Termdebug를 기본 지원한다.
솔직하게 짚은 한계
저자는 이 방식의 약점도 숨기지 않는다. CGI는 웹 서버와 애플리케이션 사이의 인터페이스일 뿐 프레임워크나 라이브러리가 아니어서 기본 제공되는 것이 거의 없다. 그래서 흔한 유틸리티들을 직접 작성해야 했고, cgi.h라는 단일 헤더 파일로 해결했지만 그것이 옳은 선택이었는지는 스스로도 확신하지 못한다. kcgi 같은 라이브러리가 있지만 채택하면 그 API와 보안 모델에 종속된다는 점이 걸린다. 그는 stb 라이브러리처럼 그냥 끌어다 쓸 수 있는 공용 유틸리티 모음이 생기길 바란다. 포크 비용에 대해서는, 과거만큼 비싸지 않고 현대 커널이 이를 크게 최적화하며, 정 문제가 되면 FastCGI로 비교적 쉽게 넘어갈 수 있다고 본다.
실무자에게 주는 함의
이 사례가 모든 팀에 그대로 적용되는 처방은 아니다. OpenBSD의 pledge·unveil에 기댄 보안 모델, C로 직접 쓰는 HTML, 직접 만들어야 하는 유틸리티는 분명한 학습·유지보수 비용을 동반하고, 여러 명이 협업하는 조직에서는 생산성 관점의 득실이 달라질 수 있다. 다만 '단일 바이너리 + 파일 교체 배포 + 최소 의존성'이라는 조합이 주는 운영 단순성과 공급망 안정성은 되새길 만하다. Postgres의 프로세스 관리와 잦은 업그레이드 부담을 SQLite가 없애주듯, 많은 소규모 상용 서비스에서 우리가 당연시해온 복잡성 상당수는 실제로는 선택 사항일 수 있다. 저자의 결론은 단순하다. 지금껏 출시한 무엇보다 움직이는 부품이 적었고, 이 스택을 또 쓰겠다는 것이다.