nginx njs: 모듈 설치와 js_set 설정, reload 적용으로 자바스크립트 변수 만들기

공정위 광고 문구 Ver 3.1
공정위 광고 문구 Ver 3.2(모바일 전용)
테스트 환경 RHEL 계열AlmaLinux 9.8Nginx 1.28 + Apache 2.4njs 0.9.4WP Rocket 3.23.5.12026-10-17 확인

nginx njs는 nginx 설정 안에서 자바스크립트 함수로 요청을 처리하거나 변수 값을 만드는 nginx 공식 모듈입니다. Nginx + Apache 구성 서버에서 nginx 설정만으로는 바꿀 수 없는 요청 주소의 대소문자를 맞추기 위해 njs 모듈을 설치된 nginx와 같은 판으로 설치하고, js_set으로 만든 변수를 캐시 파일 경로에 넣어 재시작 없이 reload로 적용했습니다.

예로 든 함수는 한글 주소의 퍼센트 인코딩을 소문자로 바꾸는 한 줄짜리이며, 요청 객체에서 머리글이나 인자 값을 읽어 변수를 만드는 방식도 같습니다.

1️⃣ nginx njs란: 자바스크립트로 nginx 기능을 확장하는 모듈

njs는 Node.js처럼 혼자 실행되는 자바스크립트 실행 환경이 아니며, 시작 스크립트나 자체 이벤트 루프가 없고, nginx가 설정에 지정된 함수를 호출할 때만 코드가 실행된 뒤 처리가 nginx로 돌아갑니다.

nginx가 자바스크립트 함수를 호출하는 자리는 HTTP 요청과 응답 처리 단계, TCP·UDP 세션 처리 단계, 변수 값 계산, 주기 타이머로 정해져 있습니다. 함수는 nginx가 넘기는 요청 객체에서 주소·머리글·인자를 읽고, 결과를 응답이나 변수 값으로 반환합니다.

HTTP 쪽 지시어는 [js_import]로 스크립트 파일을 불러오고, [js_set]으로 변수 값을, [js_content]로 응답 본문을 만들며, [js_header_filter]와 [js_body_filter]로 응답 머리글과 본문을 가공합니다. 이번 적용에 사용한 지시어는 [js_import]와 [js_set] 둘입니다.

🧭 nginx가 njs 함수를 호출하는 자리
설명 다이어그램
📌 호출 자리
📥 요청
🖥️ nginx
처리 단계 · 설정에 지정된 자리
js_set변수 값 계산
js_content응답 본문
js_header_filter · js_body_filter응답 머리글 · 본문 가공
호출→
📜 njs 함수
nginx가 넘기는 요청 객체
주소 · 머리글 · 인자 읽기
↩️ 변수 값으로 반환
↩️ 응답으로 반환
↩️ 가공한 머리글 · 본문으로 반환
❌ Node.js처럼 혼자 실행되지 않음시작 스크립트 · 자체 이벤트 루프 없음
반환→
🖥️ nginx
이어서 처리
변수 값이번 적용 · 캐시 파일 경로에 넣음
응답 본문함수가 만든 본문으로 응답
응답 머리글 · 본문가공한 머리글과 본문으로 응답
📤 응답
[js_set]은 nginx가 변수 값을 계산하는 자리에서 함수를 호출하며, 함수가 반환한 값이 변수 값이 되어 처리가 nginx로 돌아갑니다.
[js_content]는 응답 본문을 만드는 자리에서 함수를 호출하며, 함수가 요청 객체를 읽어 만든 응답을 nginx가 전송합니다.
[js_header_filter]와 [js_body_filter]는 응답을 내보내는 단계에서 함수를 호출해 응답 머리글과 본문을 가공하며, 가공이 끝나면 처리가 nginx로 돌아갑니다.

njs 모듈의 기본 엔진은 ECMAScript 5.1(strict mode)에 일부 ECMAScript 6 이후 기능을 더한 범위로 구현되어 있습니다. 정규식 치환과 함수 정도의 문자열 처리는 이 범위 안에서 동작합니다.

2️⃣ njs가 필요한 경우: nginx 설정만으로 바꿀 수 없는 변수 값

워드프레스 플러그인 WP Rocket은 한글 주소 글의 캐시 폴더 이름을 퍼센트 인코딩 소문자로 만들고, 브라우저는 같은 주소를 대문자로 인코딩해 요청합니다. 이 서버에서 워드프레스 사이트가 운영되고 있습니다.

nginx가 요청 주소 그대로 캐시 파일 경로를 만들면 대소문자가 어긋나 파일을 찾지 못하고, 요청은 Apache와 PHP로 넘어갑니다.

nginx 설정만으로는 이 값을 소문자로 바꿀 수 없습니다. [map]은 정해 둔 값 가운데 하나를 고를 뿐 문자열을 변환하지 못하며, 설치 전 [nginx -V] 출력과 모듈 폴더에는 perl이나 lua 모듈도 없었습니다.

바꿀 주소가 몇 개뿐이라면 [map] 대응표로도 처리할 수 있지만, 새 글이 생길 때마다 표를 다시 만들고 reload해야 합니다. 주소마다 다른 값을 같은 규칙으로 바꿔야 하는 경우에는 [js_set] 함수 하나로 새 글과 태그, 카테고리 주소까지 처리하게 됩니다.

perl 모듈의 [perl_set]도 같은 자리에 사용할 수 있으며 저장소에 nginx와 짝을 이루는 패키지가 있지만, nginx 공식 문서는 perl 모듈을 실험적 모듈로 안내하고 있습니다.

3️⃣ nginx njs 설치: 설치된 nginx와 같은 판으로

모듈 패키지 이름만으로 설치하면 njs만 추가될 것 같지만, 저장소의 최신 njs가 최신 nginx를 요구해 nginx까지 함께 업그레이드됩니다. 설치 전 확인에서 판을 적지 않은 설치 명령은 nginx 1.28.0을 1.30.6으로 올리는 계획을 표시했습니다.

그래서 지금 설치된 nginx 판부터 확인합니다.

rpm -q nginx
nginx-1.28.0-1.el9.ngx.x86_64

저장소에는 nginx 판마다 짝이 되는 njs 패키지가 따로 있으며, 판 번호의 + 앞이 nginx 판이고 뒤가 njs 판입니다.

dnf list --showduplicates nginx-module-njs | grep '1.28.0+'
nginx-module-njs.x86_64         1:1.28.0+0.9.4-1.el9.ngx           @nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.8.10-1.el9.ngx          nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.9.0-1.el9.ngx           nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.9.1-1.el9.ngx           nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.9.2-1.el9.ngx           nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.9.3-1.el9.ngx           nginx-stable
nginx-module-njs.x86_64         1:1.28.0+0.9.4-1.el9.ngx           nginx-stable

nginx 1.28.0과 짝인 판은 0.8.10부터 0.9.4까지 여섯 개이며, 맨 위 @nginx-stable 줄이 설치를 마친 판입니다. 설치는 그중 최신인 0.9.4를 판 번호까지 적어 진행합니다.

dnf install nginx-module-njs-1:1.28.0+0.9.4-1.el9.ngx

설치한 패키지가 요구하는 nginx 판은 rpm으로 확인할 수 있습니다.

rpm -q --requires nginx-module-njs | grep nginx
nginx-r1.28.0
rpm -ql nginx-module-njs | grep -v build-id
/usr/bin/njs
/usr/lib64/nginx/modules/ngx_http_js_module-debug.so
/usr/lib64/nginx/modules/ngx_http_js_module.so
/usr/lib64/nginx/modules/ngx_stream_js_module-debug.so
/usr/lib64/nginx/modules/ngx_stream_js_module.so
/usr/share/doc/nginx-module-njs
/usr/share/doc/nginx-module-njs/CHANGES
/usr/share/doc/nginx-module-njs/COPYRIGHT

설치된 파일은 HTTP 모듈과 TCP·UDP를 처리하는 stream 모듈, 각각의 디버그 판, 명령줄 도구 njs입니다. 이번 설정에서 불러오는 파일은 HTTP 모듈인 [ngx_http_js_module.so] 하나입니다.

4️⃣ js_set 설정: 모듈 불러오기부터 캐시 파일 경로까지

패키지를 설치해도 nginx는 모듈을 자동으로 불러오지 않으며, nginx.conf 맨 위에 [load_module] 줄이 있어야 합니다. 공식 문서 기준 [load_module]은 main 영역 지시어이므로 events·http 블록 밖에 둡니다.

📂 /etc/nginx/설정 폴더
nginx.conf맨 위 load_module — 모듈 불러오기
njs/rocket.js함수 lc — 퍼센트 인코딩만 소문자로
conf.d/
rocket-njs.confhttp 블록 — js_import · js_set
example.com.confserver 블록 — 캐시 파일 경로에 $rocket_uri
# /etc/nginx/nginx.conf 맨 위 (events·http 블록 밖)
load_module modules/ngx_http_js_module.so;

변환 함수는 설정 파일과 따로 .js 파일에 두고, 마지막 줄의 export default로 내보낸 함수를 nginx 설정에서 불러오게 됩니다.

// /etc/nginx/njs/rocket.js — 퍼센트 인코딩 %XX 만 소문자로
function lc(r) {
    return r.variables.request_uri.replace(/%[0-9A-F]{2}/g, function (m) { return m.toLowerCase(); });
}
export default { lc };

함수는 요청 객체 r에서 [request_uri] 변수를 읽고, 퍼센트 뒤 두 자리가 대문자인 곳만 소문자로 바꿔 반환합니다. 영문 글자는 그대로 두므로 대문자가 섞인 영문 주소는 바뀌지 않으며, WP Rocket이 캐시 폴더 이름을 만드는 규칙과 같습니다.

# http 블록 안 (conf.d 의 .conf 파일)
js_import rkt from /etc/nginx/njs/rocket.js;
js_set $rocket_uri rkt.lc;

[js_import]의 rkt는 모듈 안 함수를 부르는 이름이고, [js_set]이 그 함수의 결과를 [$rocket_uri] 변수로 만듭니다. 공식 문서 기준 이 함수는 요청에서 변수가 처음 참조될 때 실행되며, 동기 처리만 지원합니다.

# server 블록 — 캐시 파일 경로의 $request_uri 를 $rocket_uri 로
set $rocket_file '/wp-content/cache/wp-rocket/example.com${rocket_uri}index$rocket_mobile-https.html';

바뀐 곳은 캐시 파일 경로를 만드는 이 한 줄뿐이며, 로그인 쿠키와 쿼리, POST 요청을 캐시에서 제외하는 판정은 그대로 둡니다.

5️⃣ 적용과 확인: reload 뒤 오류 기록과 응답 머리글

설정 검사를 먼저 실행하고, 통과하면 reload합니다.

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
systemctl reload nginx

새로 넣은 [load_module] 줄은 재시작 없이 reload로 반영되었습니다. 오류 기록에는 njs 가상 머신을 초기화한 줄이 남았고, 자바스크립트 오류는 없었습니다.

grep 'js vm init' /var/log/nginx/error.log | head -1
2026/10/17 18:21:35 [notice] 27992#27992: js vm init njs: 0000559FDF6D0E00

줄 끝의 njs는 사용 중인 엔진 이름입니다. 같은 줄은 [nginx -t]로 설정을 검사할 때도 기록되므로, reload 시각과 맞춰 확인합니다.

curl -sI 'https://example.com/%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%BA%90%EC%8B%9C/' | grep -i 'x-rocket\|content-type'
content-type: text/html
x-rocket-nginx-serving-file: HIT

대문자로 인코딩된 한글 주소에도 nginx가 캐시 파일을 응답했다는 표시 머리글이 붙었습니다. 쿼리나 로그인 쿠키가 붙은 요청과 POST 요청은 적용 뒤에도 표시 머리글 없이 PHP로 넘어갔습니다.

6️⃣ njs 되돌리기와 nginx 업데이트

되돌릴 때는 캐시 파일 경로의 [$rocket_uri]를 [$request_uri]로 바꾸고, [js_import]·[js_set] 설정 파일과 [load_module] 줄을 뺀 뒤 설정 검사를 거쳐 reload합니다.

# server 블록 — 원래 변수로
set $rocket_file '/wp-content/cache/wp-rocket/example.com${request_uri}index$rocket_mobile-https.html';

패키지는 남겨 두어도 [load_module] 줄이 없으면 nginx가 불러오지 않으며, 완전히 지울 때만 패키지를 제거합니다.

dnf remove nginx-module-njs

nginx를 업데이트할 때는 njs 패키지도 새 nginx 판과 짝인 판으로 함께 올라가야 합니다. 업데이트 전에 [dnf list --showduplicates]로 새 nginx 판의 njs 짝이 저장소에 있는지 확인합니다.

🔢 FAQ & 추천 콘텐츠

nginx 공식 문서는 1.0.0 판부터 기본 njs 엔진을 지원 중단 예정(deprecated)으로 두고, 새 설정에는 ES2023을 지원하는 QuickJS 엔진을 권합니다. 엔진은 0.8.6 판부터 있는 [js_engine qjs] 지시어로 지정합니다. 이 글의 0.9.4 설치본은 기본 njs 엔진으로 적용했으며, QuickJS로 바꿔 시험하지는 않았습니다.

nginx 없이 njs 코드를 개발하고 디버깅할 때 사용하는 독립 명령줄 도구입니다(공식 문서 기준). nginx-module-njs 패키지에 함께 설치되며, [njs -v]로 판을 확인하면 모듈과 같은 0.9.4가 표시됩니다.

HTTP 요청만 처리한다면 [ngx_http_js_module] 하나로 충분합니다. 패키지에는 TCP·UDP 세션을 처리하는 [ngx_stream_js_module]도 들어 있으며, 공식 설치 문서는 둘 가운데 필요한 모듈을 [load_module]로 불러오도록 안내합니다.

🧭 WP Rocket·Perfmatters 관련 글 글 15 · 도구 3
🗂️ What is WP?
📋 WP Rocket 설정 가이드 📄 Perfmatters 가이드 📄 WP Rocket With Perfmatters 📄 WP Rocket MCP Server 📄 WP Rocket 한글 URL 📄 nginx njs 📄 WP Rocket 다국어 캐시 📄 gclid 캐시
📄 WP Rocket 속도 테스트 📝 캐시·최적화 플러그인 📝 속도 개선 사례
📋 캐시: 정의와 모든 분야 📄 웹사이트 캐시 & 서버 내부 캐시
📋 BEST 호스팅 TOP 7 📄 빠른 호스팅 2026
🛠️ 워드프레스 감지 🛠️ 후이즈 도메인 조회 🛠️ 내 아이피 확인
WP Rocket 설정 가이드: 메뉴별 기본 세팅과 20% Promo Code
WordPress · WP Rocket
WP Rocket 설정 가이드: 메뉴별 기본 세팅과 20% Promo Code
WP Rocket 메뉴별 기본 세팅과 요금을 정리한 글입니다.
글 보기 →현재 콘텐츠
Perfmatters 플러그인 리뷰 & 가이드: 5년 동안 사용한 워드프레스 성능 최적화 설정 방법
WordPress · Perfmatters
Perfmatters 플러그인 리뷰 & 가이드: 5년 동안 사용한 워드프레스 성능 최적화 설정 방법
Perfmatters 메뉴별 권장 설정과 Script Manager 사용 방법입니다.
글 보기 →현재 콘텐츠
WP Rocket With Perfmatters 사용 방법: 최적화 기능 설정 가이드
WordPress · Perfmatters
WP Rocket With Perfmatters 사용 방법: 최적화 기능 설정 가이드
WP Rocket과 Perfmatters를 함께 쓸 때의 설정 방법입니다.
글 보기 →현재 콘텐츠
WP Rocket MCP Server: AI 도구로 캐시와 설정 다루기
WordPress · MCP
WP Rocket MCP Server: AI 도구로 캐시와 설정 다루기
AI 도구에서 WP Rocket 캐시와 설정을 다루는 방법입니다.
글 보기 →현재 콘텐츠
WP Rocket 한글 URL 요청 흐름 다이어그램
WordPress · WP Rocket
WP Rocket 한글 URL
한글 주소 요청의 인코딩 대소문자 때문에 nginx가 캐시 파일을 찾지 못하는 원인과 njs로 고치는 방법입니다.
글 보기 →현재 콘텐츠
nginx njs 변수와 캐시 파일 경로 다이어그램
Server · nginx
nginx njs: 모듈 설치와 js_set 설정, reload 적용으로 자바스크립트 변수 만들기
nginx 설정 안에서 자바스크립트 함수로 변수를 만드는 njs 모듈을 설치하고 js_set 변수를 reload로 적용하는 방법입니다.
글 보기 →현재 콘텐츠
WP Rocket 다국어 캐시 글 저장 흐름 다이어그램
WordPress · WP Rocket
WP Rocket 다국어 캐시
임시글 저장 때 번역판 캐시가 언어 폴더째 삭제되는 원인과 그것을 막는 코드입니다.
글 보기 →현재 콘텐츠
광고 쿼리가 붙은 요청이 CDN 사본이 없을 때 원본 서버로 전달되고, nginx에서 Apache로 넘어간 뒤 WP Rocket이 광고 쿼리를 빼고 같은 캐시 파일로 응답하는 흐름
Server · 캐시
gclid 캐시: 광고 클릭 쿼리와 페이지 캐시 키, 첫 바이트 실측
광고 클릭 주소 끝에 붙는 gclid 쿼리를 무시하고 쿼리 없는 주소의 캐시 파일로 응답하는 동작을 첫 바이트로 측정한 글입니다.
글 보기 →현재 콘텐츠

ℹ️ 제휴 안내
본 사이트의 콘텐츠에는 제휴 링크가 포함되어 있습니다. 방문자가 이 링크를 통해 상품 또는 서비스를 구매하면 본 사이트는 판매처로부터 수수료를 지급받습니다. 이 과정에서 구매자가 지불하는 금액(이벤트 할인 시 금액이 내려갑니다↓)은 오르지 않습니다. 게시된 가격·할인·재고 정보는 작성 시점 기준이며 실제와 다를 수 있으므로, 구매 전 판매처에서 최종 확인하시기 바랍니다. 상품 선정과 평가는 자체 기준에 따라 작성되며, 수수료 지급 여부가 소개 순서나 평가 내용에 영향을 주지 않습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

인간임을 증명하세요: 3   +   4   =