웹 서버 배포 모델은 취미 수준에서 한계에 부딪힌다
사용자가 직접 자신의 서버에 호스팅할 수 있도록 배포되는 웹 애플리케이션은 정적 파일 서빙 및 캐싱 측면에서 큰 비효율성을 겪습니다. 엔터프라이즈 환경과 달리, 개인 서버 환경에서는 시스템 구성 요소가 단편화되어 있어 개발자가 최적의 성능을 내기 어렵고 잦은 호환성 문제를 감당해야 합니다.
2026-08 웹 서버 배포 모델은 취미 수준(개인 서버 규모)에서 한계에 부딪힌다.
만약 당신이 다른 사람들이 자신의 서버에 호스팅할 수 있도록 웹 기반 무언가를 만들고자 한다고 가정해 보자. 안타깝게도 이러한 생각을 하는 순간, 사설로 호스팅되는 다른 소프트웨어들이 활용할 수 있는 여러 효율적인 기법들을 당신의 코드베이스는 사용할 수 없게 된다. 그리고 다른 사람들이 이미 더 잘 만들어둔 여러 기능들을 당신이 직접 처음부터 다시 만들어야 하는 짐을 지게 된다.
요구 사항이 변경됨에 따라 추가할 수 있는 기본적인 구성부터 시작해 보자:
- TLS 처리: 애플리케이션과 분리하여 개인 키가 필요 이상으로 노출되지 않도록 보호한다. 이를 통해 인증서 획득 방식을 변경하더라도 애플리케이션 코드에 영향을 주지 않는다.
- 애플리케이션 자체
대부분의 경우 첫 번째 항목(TLS 처리)은 리버스 프록시(Reverse proxy)를 포함한 여러 기능을 갖춘 성능이 꽤 괜찮은 웹 서버일 가능성이 높다. 아주 흔한 기능 중 하나가 정적 파일(static files)을 제공하는 것인데, 현재 이는 당신의 애플리케이션이 처리하고 있다.
정적 파일 (Static files)
정적 파일 제공을 리버스 프록시로 오프로드하는 것은 나쁜 생각이 아니다. 리버스 프록시의 구현이 당신이 선택한 최신 힙한 프레임워크에 내장된 기능보다 훨씬 성능이 좋을 확률이 높다. 설령 그렇지 않더라도, 정적 파일 요청이 파이썬이나 노드(Node) 웹 서버가 동시에 처리할 수 있는 적은 양의 요청을 막아버리는 일(병목 현상)은 더 이상 발생하지 않을 것이다.
이 시도를 해본다고 가정하자. 당신의 앱이나 리버스 프록시 중 하나라도 컨테이너화되어 있거나 다른 방식으로 격리되어 있다면, 이제 당신의 앱을 설치하는 모든 관리자는 리버스 프록시가 앱에 포함된 정적 파일에 접근할 수 있도록 하나 또는 두 컨테이너 모두에 구멍(포트)을 뚫어야 한다.
앱을 마침내 출시한 후, 리버스 프록시로 오직 리버스 프록싱만 전담하고 쿠버네티스(Kubernetes)의 일부로만 배포되는 이른바 "클라우드 네이티브(cloud native)" 제품을 사용하는 사람으로부터 이슈 리포트를 받게 된다. 당신은 풀이 죽어 앱이 파일을 직접 제공하게 하는 옵션을 다시 추가하고, 사람들은 그 기능이 존재한다는 사실을 깨닫자마자 즉시 그것을 켠다. 당신이 타겟으로 하는 오디언스가 접근할 수 있는 저사양 하드웨어의 잠재력을 끌어내리는 비효율성의 단면에 기여했다는 사실을 깨닫고 눈물을 흘린다.
반면 "프로페셔널(전문가)" 규모에서는 어떨까? 정적 파일은 완전히 분리되어 배포된다. 십중팔구 S3 버킷이나 비슷한 곳에 배포되고 실제 CDN™ 의 뒷단에 위치하므로 이러한 문제가 애초에 발생하지 않는다.
미인증 캐싱 (Unauthenticated caching)
당신은 애플리케이션이 사람이나 봇에 의해 방대한 양의 '미인증(로그인 필요 없는) 방문'을 받을 것임을 인지한다. 미인증 방문은 항상 동일한 응답을 받으므로, 변경된 사항이 없다면 이 응답들을 매번 다시 계산할 실질적인 이유가 없다. 당신의 상황에서 1시간 정도면 "오래된(stale)" 페이지로 간주하기에 적절한 시간이라고 결정한다.
당신은 Varnish 캐시 웹사이트를 애정 어린 시선으로 바라보지만, 당신이 이미 존재하는 개인 사용자용 웹 서버라는 거대한 루브 골드버그 머신의 일부에 불과하기 때문에 이를 필수 요구 사항으로 둘 수 없다는 사실을 잘 알고 절망한다.
실망한 채로, 당신은 엔드포인트에 필요한 cache-control 및 vary 헤더를 추가한다. 그러다 no-vary-search 기능을 발견하지만, 그것이 크롬(Chrome)에서만 작동한다는 사실을 깨닫는다. 당신은 응답을 변경시킬 정확한 쿼리 매개변수 세트를 알고 있지만, 현재 위치에서는 아무것도 할 수 없다. 만약 당신이 Varnish에 의존할 수만 있었다면, 사용되지 않는 쿼리 매개변수들을 제거할 수 있었을 것이다. 그래야 링크 미리보기에 관한 죽은 농담을 되살리려는 짜증나는 사람들이 링크 끝에 ?qweqweawe를 추가하여 당신의 캐시를 우회하려는 시도를 막을 수 있을 텐데 말이다.
당신은 사용 중인 웹 서버 라이브러리에 캐싱 미들웨어가 있다는 것을 발견한다. 기능 목록을 읽어보니, 운이 좋으면 cache-control의 TTL과 vary 정도를 지원할 뿐 그 이상은 지원하지 않는다는 것을 깨닫는다. 당신은 아무도 이상한 짓(캐시 우회 등)을 시도하지 않기를 바라는 마음 한 스푼의 희망만을 품은 채 그것을 추가한다. 이미 좋은 캐시를 구축한 관리자들이 최고의 효율성을 위해 이를 미세 조정해주기를 바라며 구성 스위치와 문서를 제공하지만, 그들은 결코 그렇게 하지 않는다.
앱을 출시하자마자, Caddy 사용자로부터 이슈 리포트를 받게 된다. 그들이 믿고 의지했던 Caddy의 믿을 수 없을 정도로 형편없는 캐싱 플러그인이 마음대로 응답을 훼손해버렸기 때문이다. 또 다른 누군가는 엔진엑스(nginx)의 캐시를 활성화했지만 그들의 설치본은 끊임없이 지...