NGINX에서 njs를 사용해 SSR을 구축했습니다. 배운 점
Source: Dev.to
Source:
소개
NGINX 내부에 최소한의 SSR 런타임을 직접 구축했고 이제는 프로덕션에서 사용하고 있습니다.
한동안 njs와 함께 NGINX를 사용해 CSP 논스 생성 및 요청 수준 로직과 같은 작업을 수행해 왔습니다. 이 프로젝트는 그 CSP 처리를 확장하는 형태로 시작했으며, 결국 개인 웹사이트에서 실행되는 작은 실험으로 성장했습니다.
저장소:
런타임이 하는 일
- NGINX + njs (NGINX 내부의 JavaScript)
- 간단한 컴포넌트‑렌더링 패턴
- Node.js도, Next.js도 없음 – 오직 NGINX
런타임은 의도적으로 작고 명시적이며, 전체 프레임워크라기보다 렌더링 유틸리티에 가깝다.
렌더링 흐름
| 전통적인 SSR | → | 클라이언트 → Node SSR → HTML |
|---|---|---|
| NGINX‑기반 SSR | → | 클라이언트 → NGINX (njs) → HTML |
아이디어는 간단하다:
- 요청 처리 중에 JavaScript를 실행한다 (njs를 통해).
- HTML을 즉시 생성한다.
- HTML을 NGINX에서 직접 반환한다.
실제로 이것은 문자열‑우선 렌더링 모델이다: 가상 DOM이나 템플릿 엔진 없이 작은 헬퍼 함수를 사용해 순수 문자열로 HTML을 만든다.
NGINX에 대한 내 시각이 바뀐 이유
이전에는 NGINX를 주로 다음과 같이 사용했습니다:
- 리버스 프록시
- 헤더와 라우팅을 위한 장소
njs와 작업하면서 NGINX가 또한 다음을 할 수 있음을 알게 되었습니다:
- 요청 수준 로직 실행
- 동적 응답 생성
- 매우 가벼운 렌더링 레이어 역할
최소 환경이라는 제약이 오히려 가치 있는 요소가 되었습니다.
주요 인사이트
- SSR은 서버에서 HTML을 반환하는 것에 불과합니다. 그 외 모든 것은 그 위에 겹쳐집니다.
- 프로젝트는 SSR이 실제로 무엇인지와 우리가 보통 어떻게 구현하는지의 차이를 명확히 했습니다.
- 런타임을 동기 렌더링만, 외부 I/O 없음, 숨겨진 상태 없음, 결정론적 출력으로 제한함으로써 시스템은:
- 이해하기 쉬워짐
- 디버깅이 쉬워짐
- 더 예측 가능해짐
능력을 제거하는 것이 추상화를 추가하는 것보다 명확성을 향상시킬 수 있습니다.
장점 및 트레이드오프
| 얻은 것 | 잃는 것 |
|---|---|
| Node.js 런타임 없음 | 전체 JavaScript 런타임 |
| 매우 빠른 실행 경로 | 생태계 및 도구 |
| 최소한의 움직이는 부품 | 익숙한 디버깅 패턴 |
이것은 내 사고를 “애플리케이션 수준 설계”에서 “인프라 수준 설계”로 전환시켰다.
통합 장점
모든 것이 NGINX 내부에서 실행되기 때문에 CSP, 헤더, 요청 검증과 같은 문제들이 단일 레이어에 머물러 시스템이 더 일관되게 느껴진다.
개발 워크플로우
구현은 다음과 같이 협업했습니다:
- A 텍스트 지향 모델 (ChatGPT) for reasoning, structure, and constraints.
- A 코드 지향 에이전트 (Codex) for the actual implementation.
워크플로우:
- Define the system shape.
- Use Codex to fill in implementation details.
- Validate everything against real runtime behavior.
This separation proved more effective than trying to generate everything in one step.
이 접근 방식을 고려해야 할 때
적합한 경우:
- 작거나 대부분 정적인 사이트
- 단순한 렌더링 레이어
- HTML 및 보안에 대한 엄격한 제어가 필요한 경우
- 인프라‑레벨 실험
부적합한 경우:
- 복잡한 프론트엔드 애플리케이션
- 높은 인터랙티비티 요구
- 방대한 생태계에 의존하는 팀
NGINX를 설정해 본 적이 있다면, 이 설정이 익숙하게 느껴질 것입니다.
시작하기
- NGINX와 njs를 설치합니다.
- 저장소를 복제합니다.
- 제공된 구성을 로드합니다.
- 서버를 실행합니다.
전체 지침:
Conclusion
이 최소 SSR 런타임을 프로덕션에서 구축하고 실행하면서 렌더링을 인프라스트럭처까지 얼마나 밀어넣을 수 있는지, 그리고 제약이 시스템 설계에 어떻게 영향을 미치는지를 명확히 알게 되었습니다. 또한 프론트엔드가 끝나는 지점과 인프라스트럭처가 시작되는 지점에 대한 제 관점을 재정립하게 되었습니다. 때때로 레이어를 제거하는 것이 새로운 레이어를 추가하는 것보다 더 많은 것을 가르쳐 줍니다.