# Zeroserve: eBPF로 스크립팅할 수 있는 무설정 웹 서버

> Clean Markdown view of GeekNews topic #30239. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=30239](https://news.hada.io/topic?id=30239)
- GeekNews Markdown: [https://news.hada.io/topic/30239.md](https://news.hada.io/topic/30239.md)
- Type: GN+
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2026-06-07T09:10:23+09:00
- Updated: 2026-06-07T09:10:23+09:00
- Original source: [su3.io](https://su3.io/posts/introducing-zeroserve)
- Points: 1
- Comments: 1

## Topic Body

- 작고 빠른 **HTTPS 서버**인 zeroserve는 웹사이트 tarball을 받아 HTTP/2와 TLS 1.3으로 제공하고, tarball 안의 **eBPF 프로그램**을 사용자 공간 샌드박스 미들웨어로 요청마다 실행함  
- 구성 파일 없이 eBPF 프로그램이 요청별 라우팅, 헤더, 인증, 속도 제한, 프록시를 결정해 nginx·Caddy의 선언형 설정과 별도 스크립팅 계층을 하나로 합침  
- 사이트는 단일 **tar 파일**로 인덱싱되고 디스크에 풀리지 않으며, tarball 교체와 `SIGHUP`으로 사이트·스크립트·TLS 자료를 연결 손실 없이 원자적으로 교체함  
- 단일 코어 HTTPS 벤치마크에서 zeroserve는 소형 정적 파일 36,681 req/s, 10ms eBPF 동적 JSON 46,945 req/s, 소형 프록시 26,486 req/s를 기록했지만, **100KB 프록시**는 nginx가 5,882 req/s로 우위임  
- zeroserve는 nginx와 Caddy의 대안을 목표로 단일 tarball 배포, 프로그램형 설정, 사용자 공간 eBPF, 현대적 TLS를 결합하지만, 큰 프록시 응답에는 nginx가 더 적합함  
  
---  
  
### 개요  
- [zeroserve](https://github.com/losfair/zeroserve)는 웹사이트 tarball 하나를 HTTP/2와 TLS 1.3으로 제공하는 작고 빠른 무설정 HTTPS 서버임  
- tarball 안에 넣은 eBPF 프로그램은 모든 요청에서 사용자 공간 샌드박스 미들웨어로 실행되며, 요청 재작성, 인증, 속도 제한, 백엔드 리버스 프록시 처리 가능  
- 단일 코어 기준으로 소형·대형 정적 파일, 스크립트 미들웨어, 소형 응답 프록시 대부분의 워크로드에서 nginx보다 높은 성능을 보이는 목표의 서버임  
- eBPF 스크립트는 네이티브 코드로 JIT 컴파일되고 사용자 공간에서 샌드박싱되며, 요청마다 실행할 만큼 낮은 비용을 목표로 함  
- 네트워크와 디스크 작업은 [monoio](https://github.com/bytedance/monoio) 런타임을 통해 `io_uring`으로 제출됨  
- TLS 1.3, HTTP/2, Encrypted Client Hello, SNI 인증서 선택, JA4 핑거프린팅 지원  
- 전체 사이트와 TLS 자료는 tarball 하나에서 제공되며, `SIGHUP`으로 핫 리로드 가능  
  
### 구성 모델: 프로그램이 곧 설정  
- zeroserve는 nginx와 Caddy의 대안을 목표로 하며, 핵심 설계 선택은 구성 방식임  
- nginx와 Caddy는 `location` 블록, `rewrite` 규칙, `map` 지시어, `try_files` 같은 선언형 설정 언어를 제공하고, 한계에 도달하면 Lua나 Caddy 플러그인 같은 선택적 스크립팅 런타임을 옆에 붙이는 구조임  
- 그 구조에서는 동작이 자체 제어 흐름을 가진 지시어 계층과 요청 생명주기의 특정 지점에서 실행되는 스크립트 계층으로 나뉨  
- zeroserve에는 구성 파일이 없으며, eBPF 프로그램 하나가 모든 요청을 보고 라우팅, 헤더, 인증, 속도 제한, 프록시를 결정함  
  
### 단일 tarball을 그대로 제공  
- 전체 사이트는 하나의 `tar` 파일이며, zeroserve는 로드 시 `path -> byte-range` 맵을 만들고 tarball 자체에 바이트 범위 읽기를 수행해 파일 제공  
- 어떤 파일도 디스크에 풀리지 않기 때문에 사이트는 단일 파일 안에만 존재하며, 잘못된 `location` 규칙이 노출할 문서 루트가 없음  
- 배포는 단일 파일의 원자적 교체 방식이며, 새 버전 배포는 tarball 교체 뒤 `SIGHUP` 전송  
- 디렉터리 패키징과 실행 명령은 다음 형식임  
  
```bash  
zeroserve --pack ./public > site.tar  
zeroserve --addr 0.0.0.0:8080 site.tar  
```  
  
- 핫 리로드 명령은 다음 형식임  
  
```bash  
killall -SIGHUP zeroserve  
```  
  
- 리로드는 같은 프로세스 안에서 사이트, 스크립트, TLS 자료를 원자적으로 교체하고 연결 손실 없이 동작함  
- 각 인스턴스는 단일 스레드 이벤트 루프이며, 프로세스 하나 기준으로는 제한이지만 확장 단위가 “더 많은 프로세스”일 때 맞는 형태로 제시됨  
  
### 사용자 공간 eBPF 스크립팅  
- `.zeroserve/scripts/` 아래에 둔 모든 `.c` 파일은 패키징 시점에 `clang`과 `llc`로 eBPF 오브젝트로 컴파일되고 모든 요청에서 실행됨  
- eBPF는 커널 BPF 서브시스템이나 `CAP_BPF` 없이 일반 비권한 프로세스 안의 [async-ebpf](https://crates.io/crates/async-ebpf) 런타임에서 사용자 공간으로 실행됨  
- async-ebpf는 [uBPF](https://github.com/iovisor/ubpf)를 내장해 바이트코드를 네이티브 x86-64 머신 코드로 JIT 컴파일함  
- 포인터 케이지(pointer cage)는 JIT 컴파일된 코드의 모든 메모리 접근을 프로그램 전용 아레나로 마스킹해 잘못된 접근을 스크립트 메모리 안에 가둠  
- 스크립트는 zeroserve의 단일 이벤트 루프에서 직접 실행되며, 느린 스크립트가 다른 연결을 멈추지 않도록 타이머가 JIT 컴파일된 네이티브 코드를 실행 중간에 인터럽트하고 제어를 이벤트 루프로 돌려줄 수 있음  
- 프로그래밍 모델은 파일명 정렬 순서로 실행되는 스크립트 체인이며, 스크립트들은 요청별 메타데이터 맵을 공유함  
- 스크립트가 `zs_respond`나 `zs_reverse_proxy`를 호출하면 체인은 단락 종료됨  
- `zs.response.header.*` 아래 키는 모든 응답의 헤더가 되며, 다른 키는 HTML 파일의 `&lt;zs-meta&gt;visitor&lt;/zs-meta&gt;` 같은 플레이스홀더를 출력 시점에 치환하는 작은 템플릿 패스에 사용됨  
- [헬퍼 표면](https://github.com/losfair/zeroserve/blob/main/sdk/zeroserve.h)은 요청 메서드·경로·쿼리·헤더·피어 주소 읽기, URI 재작성, 헤더 설정·삭제를 지원함  
- 암호화와 인코딩 헬퍼는 SHA-256, HMAC-SHA256, base64, hex, `getrandom` 제공  
- JSON 헬퍼는 요청 본문 파싱, 문서 트리 생성·수정, `zs_json_respond` 응답 지원  
- 속도 제한은 피어 IP나 API 키 같은 임의 키 기반의 토큰 버킷을 지원하며, 상태는 핫 리로드 뒤에도 유지됨  
- AWS SigV4 헬퍼는 S3와 기타 AWS 서비스 통신용 서명 `Authorization` 헤더와 presigned URL 지원  
- OIDC 로그인은 Authorization Code + PKCE 기반 relying-party 흐름을 제공하며, 전체 로그인 세션을 sealed XChaCha20-Poly1305 쿠키에 담아 서버를 상태 비저장으로 유지한 채 정적 사이트를 “Google로 로그인” 뒤에 둘 수 있음  
- 동적 엔드포인트는 특정 경로에서 스크립트가 직접 응답하는 방식이며, 예시에서는 `/health` 요청에 `application/json` 헤더와 `{"status":"ok"}` 본문을 반환함  
- 각 스크립트는 기본 256KB 메모리 상한 아래 실행되며, 런타임은 오래 실행되는 스크립트를 실행기에서 시간 분할하고 폭주 스크립트를 스로틀링함  
- 스크립트는 `zs_call`로 서로 호출할 수 있으며, 호출 깊이는 제한됨  
- 무한 루프에 빠진 스크립트는 자기 요청만 지연시키며, 선점 타이머가 이를 인터럽트해 서버가 다른 요청을 계속 처리함  
- TLS 계층은 TLS 1.3 전용이며 BoringSSL로 종료됨  
- Encrypted Client Hello는 실제 SNI가 평문으로 나타나지 않게 하며, 디렉터리 기반 SNI 인증서 선택과 스크립트에 노출되는 JA4 클라이언트 핑거프린팅 제공  
- 투명 ECH 릴레이 모드는 복호화할 수 없는 핸드셰이크를 실제 업스트림으로 바이트 단위 그대로 전달해 보호된 이름이 공개 이름 뒤에 섞일 수 있게 함  
  
### 성능  
- ## 벤치마크 조건  
  - zeroserve, nginx 1.26, Caddy 2.11을 8코어 Ryzen 7 3700X에서 같은 콘텐츠와 같은 자체 서명 인증서로 HTTPS 제공 비교  
  - zeroserve 인스턴스가 설계상 단일 스레드이므로 비교 기준은 코어당 성능임  
  - 모든 서버는 `taskset`으로 CPU 하나에 고정됐고, nginx는 `worker_processes 1`, Caddy는 `GOMAXPROCS=1`, zeroserve는 기존 단일 스레드 구조 사용  
  - 부하는 다른 코어에서 `wrk -t4 -c100`으로 생성했고, 10초 실행 3회의 중앙값 사용  
  - `wrk`는 HTTP/1.1을 사용하므로 수치는 TLS 1.3 위의 HTTP/1.1이며, 긴 keep-alive 연결로 핸드셰이크 비용을 분산한 이미 열린 HTTPS 연결의 정상 상태 비용임  
- ## 소형 정적 파일 174B  
  | 서버 | req/s | p99 |  
  | --- | ---: | ---: |  
  | zeroserve | **36,681** | 5.4 ms |  
  | nginx | 31,226 | 7.8 ms |  
  | Caddy | 12,830 | 22 ms |  
  - zeroserve는 단일 코어에서 nginx보다 약 17% 빠르게 소형 파일을 제공했고, 꼬리 지연도 더 낮음  
  - HTML 페이지, 소형 JSON, CSS 같은 정적 사이트 기본 사례가 zeroserve 튜닝 대상임  
- ## 대형 정적 파일 100KB  
  | 서버 | req/s | 처리량 | p99 |  
  | --- | ---: | ---: | ---: |  
  | zeroserve | **8,000** | 782 MB/s | 22 ms |  
  | nginx | 7,600 | 773 MB/s | 28 ms |  
  | Caddy | 6,084 | 590 MB/s | 44 ms |  
  - 세 서버의 결과는 가까웠고, zeroserve가 단일 코어에서 약 780 MB/s로 약간 앞섬  
  - nginx의 대형 파일 강점인 `sendfile()`은 TLS 아래에서 사용되지 않으며, 바이트를 사용자 공간에서 암호화해야 하므로 세 서버 모두 암호화와 쓰기 루프에 묶임  
  - kernel TLS를 세 서버 모두 끈 상태에서 zeroserve의 `io_uring` 읽기·쓰기 경로가 약간 더 빠른 결과임  
  
### eBPF vs Lua  
- 스크립팅 비교 대상은 웹 서버 안에서 빠른 코드를 실행하는 일반적 방식인 nginx + LuaJIT `ngx_http_lua_module`임  
- zeroserve는 기본값으로 스크립트 선점 타이머를 2ms마다 설정하며, 세밀한 간격은 문제 스크립트를 빠르게 스로틀링하지만 정상 스크립트에도 비용을 줌  
- 기본 2ms에서는 완전 동적 응답 기준 eBPF가 약 32k req/s로 nginx Lua의 41k req/s보다 낮음  
- `--preempt-timer-interval-ms`를 10으로 올리면 스크립팅 처리량이 약 40% 회복되고 결과가 뒤집힘  
- ## 요청별 헤더 주입 미들웨어  
  | 엔진 | req/s | p99 |  
  | --- | ---: | ---: |  
  | zeroserve eBPF 10ms | **43,709** | 5.1 ms |  
  | zeroserve eBPF 2ms 기본값 | 31,334 | 6.7 ms |  
  | nginx Lua `header_filter` | 28,653 | 8.4 ms |  
  - 스크립트가 실행되지만 정적 파일은 계속 제공되는 미들웨어 사례에서 10ms eBPF가 nginx Lua보다 약 50% 높고 꼬리 지연도 더 낮음  
- ## 완전 동적 JSON 응답  
  | 엔진 | req/s | p99 |  
  | --- | ---: | ---: |  
  | zeroserve eBPF 10ms | **46,945** | 4.5 ms |  
  | nginx Lua `content_by_lua` | 41,231 | 6.4 ms |  
  | zeroserve eBPF 2ms 기본값 | 32,393 | 6.7 ms |  
  - 10ms 간격의 조정된 eBPF는 완전 합성 응답에서도 nginx의 `content_by_lua`보다 높은 처리량을 기록함  
  - 두 엔진 모두 네이티브 코드로 컴파일되며, LuaJIT는 트레이싱 JIT이고 async-ebpf는 uBPF를 통해 eBPF를 JIT 컴파일함  
  - TLS 암호화가 공통 요청 비용인 조건에서 조정된 eBPF 경로가 처리량에서 앞섬  
  - 2ms 기본값에서는 eBPF가 미들웨어 우위는 유지하지만 합성 응답 선두는 내주므로, 운영 스크립트에는 10ms 사용 권장  
  
### 리버스 프록시로 사용  
- zeroserve는 `zs_reverse_proxy("http://127.0.0.1:9000")`를 스크립트에서 호출해 백엔드로 프록시함  
- 업스트림 연결 풀은 백엔드당 최대 128개 연결과 30초 유휴 재사용을 지원함  
- 공정 비교를 위해 nginx는 기본적으로 요청마다 업스트림 연결을 닫는 특성을 고려해 `keepalive 128`, `proxy_http_version 1.1`, 비운 `Connection` 헤더를 명시 사용함  
- Caddy는 기본 동작대로 연결 재사용  
- 각 프록시는 단일 코어에서 TLS를 종료하고 공유 평문 백엔드로 전달했으며, 백엔드는 별도 2코어 서버로 자체 100k req/s를 유지해 프록시 오버헤드만 측정함  
- ## 소형 174B 응답 프록시  
  | 프록시 | req/s | p50 | p99 |  
  | --- | ---: | ---: | ---: |  
  | zeroserve | **26,486** | 3.3 ms | 8 ms |  
  | nginx | 21,761 | 4.2 ms | 10.5 ms |  
  | Caddy | 7,683 | 10.3 ms | 33 ms |  
  - zeroserve의 풀링된 `io_uring` 프록시는 nginx보다 약 22% 앞섰고 Caddy 대비 약 3.4배 처리량을 기록함  
  - API 호출, 소형 JSON, 앱 서버 HTML 같은 일반적 프록시 워크로드에서 zeroserve가 TLS 종료와 백엔드 전달을 더 빠르게 수행함  
- ## 100KB 응답 프록시  
  | 프록시 | req/s | 처리량 |  
  | --- | ---: | ---: |  
  | nginx | **5,882** | 585 MB/s |  
  | Caddy | 4,285 | 406 MB/s |  
  | zeroserve | 3,631 | 359 MB/s |  
  - 프록시 본문이 커지면 nginx의 버퍼링이 바이트를 더 효율적으로 이동해 앞서고, Caddy가 중간, zeroserve가 뒤처짐  
  - 프록시 응답이 크면 nginx가 더 나은 도구이며, 작고 많은 응답이면 zeroserve가 더 빠름  
  
### 메모리  
- 유휴 상태의 단일 zeroserve 인스턴스는 약 15MB PSS를 사용하며, nginx의 약 6MB보다 많고 Caddy의 약 60MB보다 적음  
- 실행 단위가 전체 프로세스라는 점이 중요하며, 코어마다 복사본을 실행할 때 같은 바이너리를 매핑해 코드 페이지를 공유함  
- 추가 프로세스는 자체 워킹셋 외에는 적은 메모리를 더함  
  
### 공개  
- zeroserve는 GitHub에서 오픈소스로 공개된 프로젝트임

## Comments



### Comment 59053

- Author: neo
- Created: 2026-06-07T09:10:24+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=48425723) 
- **TechEmpower 웹 서버 벤치마크**가 사라지면서, 이런 새 프로젝트들이 스스로를 입증할 기회가 줄어든 것 같음  
  수정: 내가 뒤처진 것 같고, 요즘 뜨는 건 [https://www.http-arena.com/leaderboard/](<https://www.http-arena.com/leaderboard/>)인 듯함. 행운을 빔
  - 죽었다는 게 무슨 뜻인지 모르겠음. [https://www.techempower.com/benchmarks/#section=data-r23](<https://www.techempower.com/benchmarks/#section=data-r23>)에 아직 있고, 마지막 벤치마크도 2025년 2월임  
    다만 원래도 자주 돌리는 편은 아니고, 라운드 기록을 보면 1년에 한 번 이하로 실행됨
  - **LLM UI/UX**가 너무 별로임. 이런 것에 주말 하루이틀만 써도 사용자 경험을 꽤 개선할 수 있을 텐데 왜 안 하는지 모르겠음

- 이런 시도가 **LLM 덕분에** 비교적 싸고 빠르게 탐색 가능해져서 나오는 걸 보는 게 좋음  
  다만 여기서 느낀 점은 nginx 자체가 꽤 인상적이라는 것임. 또 눈에 띈 대목은, 이 프로젝트가 nginx와 Caddy의 대안이며 설정 방식에 베팅한다는 설명이었음  
  nginx와 Caddy는 선언형 설정 언어를 제공하고, 그 한계에 닿으면 Lua나 Caddy 플러그인 같은 스크립트 런타임을 옆에 붙이는 구조라 동작이 두 계층으로 나뉨  
  하지만 그 베팅은 잘못된 것 같음. 사람들은 오래전부터 **코드보다 설정**을 선호했고, 내장 기능만으로도 충분한 경우가 많아서 C 코드를 쓸 필요가 없음
  - 그렇게 확신하긴 어려움  
    모든 설정 파일 형식은 처음엔 단순하게 시작하는 것 같음. YAML도 기본은 꽤 합리적이었는데, 사람들이 앵커와 별칭으로 더 복잡한 걸 원하기 시작했음  
    GitLab조차 조건문과 변수 비슷한 자체 형식을 갖고 있고, 특정 위치에서만 동작하는 해킹에 가까움. Apache도 XML 기반 설정 형식에서 비슷한 길을 갔음  
    결국 설정 관리를 위한 수많은 **맞춤형 프로그래밍 언어**가 생김. 기업 환경에서는 직접 편집하지 않고 Ansible 워크플로를 스크립트로 짜서 원격 수술을 함  
    차라리 서버에 Lua나 Python 같은 인터프리터를 내장해 설정 관리를 하게 했으면 이 과정을 건너뛸 수 있었고, 맞춤 설정 파일을 프로그램으로 고치는 것보다 단순했을 것임  
    물론 맞춤형 시도들이 일반 언어보다 특정 용도에 최적화됐다고 말할 수는 있지만, 그런 주장은 애초에 그 장치가 필요 없었을 장난감 예제의 좁은 범위에만 맞음  
    Windows INI 파일을 기억하는지. 코드가 코드이고 데이터가 데이터였던 좋은 시절이었음
  - 앞으로 96시간 안에 누군가 LLM으로 nginx나 Caddy 설정 파일을 zeroserve가 쓸 수 있는 코드로 **변환해 포장하는 도구**를 만들 수 있을 것 같음  
    더 단순하게는 Kubernetes 클러스터의 Ingress 매니페스트를 모두 읽어 pack을 다시 만들 수도 있음  
    요점은 도구와 설정 사이의 인터페이스도 또 하나의 API일 뿐이고, 시스템 운영자는 이미 더 높은 수준의 구성물로 시스템 상태를 기술하고 있으며, 설정을 이루는 구체적인 바이트는 그 결과물이라는 점임
  - 복잡성을 추상화하고 **매크로**로 “설정 파일”식 구성을 달성하는 건 어떨까 싶음
  - AI가 점점 더 **사람의 말 → 기계의 효과**를 가능하게 하면서 이 선호가 바뀔지 살펴볼 가치는 있어 보임  
    AI 입장에서는 그 방식이 더 다루기 쉬울 수 있음. AI는 양쪽 모두 처리할 수 있으니, 그런 전환이 명확히 좋은 아이디어로 자리 잡기까지는 시간이 오래 걸릴 수 있음
  - 왜 그렇게 LLM에 공을 돌리고 싶어 하는지 모르겠음. 글 작성에 LLM 도움을 받았다고 해서, 실험까지 LLM이 대신 했다는 뜻은 아님

- 아이디어는 마음에 듦  
  다만 eBPF 디렉터리에 `.c` 파일 대신 **`.rs` 파일**을 넣을 수 있으면 더 안심될 것 같음. 이미 Rust 프로젝트이기도 하니  
  그리고 왠지 커널 가속 웹 서버를 기대했음. eBPF로 안전하게 할 수 있다면 정말 대단할 듯함  
  또 단일 스레드라니? Linux에서 포크하고 들어오는 연결 큐를 공유하는 건 거의 사소한 일이고, Rust로도 몇 줄이면 될 것임. **SO_REUSEPORT**를 쓰면 나머지는 커널이 처리함  
  참고로 io_uring을 밀 생각이라면 kTLS도 같이 밀어야 한다고 봄. 핸드셰이크 이후 사용자 공간 SSL 처리를 피할 수 있으면 설계가 크게 단순해짐
  - 고마움. **fork + SO_REUSEPORT**를 구현할 예정임  
    지금까지는 이런 용도로 nftables를 써와서 직접 필요하지 않았음

- 아주 멋짐. 이것을 **XDP 프로그램**이나 소켓 맵에 붙는 프로그램 같은 다른 BPF 프로그램 타입과 결합해서, L7 HTTP 기능을 더 아래 계층으로 통합할 수 있을지 궁금함

- 아이디어는 좋지만 **정적 파일**에 집중해야 할지는 모르겠음. 요즘은 그 목적으로 서버를 새로 띄우는 경우가 드묾
  - 지난주에 Ghost를 정적으로 변환하면서 딱 그렇게 했고, 자체 포함 바이너리 하나가 더 빠르지 않을까 반쯤 생각하고 있었음  
    그래서 이건 나를 위해 만들어진 것처럼 느껴지지만, 내가 일반적인 사용자가 아니라는 건 인정함
  - 도메인에 따라 다름. 여러 과학 분야에서는 큰 데이터셋을 **정적 파일 형식**으로 효율적으로 제공함. 예를 들면 [https://zarr.dev/](<https://zarr.dev/>)나 [https://parquet.apache.org/](<https://parquet.apache.org/>) 같은 것들임

- 좋아 보이고 기능도 괜찮음. 하지만 어딘가 너무 인위적으로 느껴져서 마음이 확 붙지는 않음  
  지표가 가짜인지, 편의 함수들이 실제로 동작하는지, 제대로 된 강화 작업이 있었는지 알 수 없음  
  바이브 코딩으로 만들고 README가 자동 생성된 것까지는 받아들일 수 있음. 그런데 발표 블로그 글까지 AI가 만든 것이고, 소프트웨어 품질에 대한 이해가 나와 같은지 판단할 근거가 전혀 없음  
  이상한 세상임. 몇 년 전 AI 고지 없이 발표됐다면 의심 없이 받아들였을 텐데, 지금은 멋진 README와 그럴듯한 명령줄 매개변수가 보이면 README가 **환각**한 것이고 실제로는 옵션이 없을지도 모른다고 바로 의심하게 됨
  - 작성자임. 이 프로젝트의 몇몇 핵심 부분, 예를 들면 **async-ebpf**는 그런 코딩 에이전트들이 나오기 훨씬 전에 작성됐음  
    zeroserve 자체를 만들 때는 AI 도움을 많이 쓰지만, AI 출력은 직접 확인하고 책임도 내가 짐
  - 벤치마크를 보면, 174B짜리 작은 정적 파일에서 zeroserve는 36,681 req/s와 p99 5.4ms, nginx는 31,226 req/s와 p99 7.8ms, Caddy는 12,830 req/s와 p99 22ms임  
    zeroserve는 단일 코어에서 작은 파일을 nginx보다 약 17% 빠르게 제공하고 꼬리 지연도 더 좁음. HTML 페이지, 작은 JSON, CSS가 zeroserve가 맞춘 경우임  
    100KB 큰 정적 파일에서는 zeroserve가 8,000 req/s, 782 MB/s, p99 22ms이고 nginx는 7,600 req/s, 773 MB/s, p99 28ms, Caddy는 6,084 req/s, 590 MB/s, p99 44ms임  
    그래도 나는 이런 신생 프로젝트보다 감사받고, 실전에서 검증되고, 강화된 **오래된 프로젝트**를 택하겠음. 위험을 감수할 만큼 개선 폭이 크지 않음
  - 정말 안타까운 상황임. 최근에 **ffmpeg-wasm** 프로젝트가 있었고 테스트해보니 동작은 했음. 하지만 바이브 코딩 AI였고, 나는 AI를 견딜 수 없음. 동작해도 마찬가지임  
    가능한 한 구식 시대에 남기로 했음. 똑똑한 사람들이 소프트웨어를 공개하고, 똑똑한 사람들이 유지보수함. 그들에게 AI는 필요 없음. 그게 내 틈새임  
    우리가 사라질 수도 있지만 그래도 그쪽이 더 좋음. 다만 그런 똑똑한 사람들이 문서를 쓴다는 전제가 붙음. 문서 쓰기를 싫어하는 똑똑한 사람도 많음  
    오래전에 문서가 없는 소프트웨어는 아무리 훌륭해도 내 시간을 들일 가치가 없다고 정했음. 주로 애플리케이션 쪽 이야기이고, Linux 문서는 거의 보지 않았지만 남들은 아주 나쁘지는 않다고도 하니 알 수 없음

- 흥미로운 새 개념이고 마음에 듦  
  진짜 질문은 **개발자 헌신도와 커뮤니티**임. Caddy와 Nginx 쪽 사람들은 제품 지원을 꾸준히 해왔고, 이 프로젝트도 많은 집중과 관심이 필요할 것임

- 왜 **tarball**인가?
  - 바이트 범위로 리소스에 접근하기 쉬운 단순한 형식이고, 모두가 도구를 갖고 있으며, 무엇보다 압축하지 않기 때문임
  - “One tarball, served in place” 섹션 첫 문단에 따르면, 전체 사이트가 하나의 tar 파일이고 zeroserve는 로드 시 이를 색인해 경로에서 **바이트 범위 맵**을 만든 뒤 tarball 자체에 대해 바이트 범위 읽기를 수행해 파일을 제공함  
    디스크에는 아무것도 풀지 않음. 사이트가 그 파일 하나에 완전히 들어 있으므로, 잘못된 location 규칙이 노출할 문서 루트가 없고 배포도 단일 원자적 파일 교체가 됨  
    다만 그 설명도 LLM식 정당화일 수 있음. 글 곳곳에 “the right shape”나 “the surface is broad” 같은 표현이 흩어져 있음
