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

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] 둘입니다.
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 nginxnginx-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-stablenginx 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 nginxnginx-r1.28.0rpm -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 맨 위 (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 -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsystemctl reload nginx새로 넣은 [load_module] 줄은 재시작 없이 reload로 반영되었습니다. 오류 기록에는 njs 가상 머신을 초기화한 줄이 남았고, 자바스크립트 오류는 없었습니다.
grep 'js vm init' /var/log/nginx/error.log | head -12026/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-njsnginx를 업데이트할 때는 njs 패키지도 새 nginx 판과 짝인 판으로 함께 올라가야 합니다. 업데이트 전에 [dnf list --showduplicates]로 새 nginx 판의 njs 짝이 저장소에 있는지 확인합니다.
🔢 FAQ & 추천 콘텐츠









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






