Next.js 연동 구조와 SELinux Enforcing 동작 흐름¶
Next.js는 운영 환경에서 프론트엔드 서버 런타임(Node.js 프로세스) 으로 동작하며,
외부 트래픽의 진입점은 항상 Nginx가 담당함.
SELinux Enforcing 환경에서 Nginx의 proxy_pass가 Next.js로 정상 동작하기 위해
어떤 보안 검사가 수행되며, 왜 막히고, 무엇을 허용해야 하는지를 구조적으로 설명함.
설정 나열이 목적이 아님
“왜 이 설정이 필요한가”를 이해시키기 위한 문서임
1. 기본 전제 (이 문서를 읽기 전 상태)¶
다음 조건을 전제로 설명함.
- SELinux: Enforcing
- Nginx: 정상 기동 (
httpd_t) - Next.js: 정상 기동 (PM2,
127.0.0.1:3000listen) - Firewall:
- 80 / 443 만 외부 허용
- 3000 포트 외부 미개방
- Next.js 프론트엔드 서버는 외부 트래픽을 직접 받지 않음
2. 전체 트래픽 흐름 (정상 구조)¶
[ Client ]
↓
[ Nginx (httpd_t) ]
↓ proxy_pass
[ 127.0.0.1:3000 ]
↓
[ Next.js Frontend Server (PM2) ]
이 구조에서 외부에서 접근 가능한 것은 Nginx 뿐임.
Next.js 포트(예: 3000)는 내부 전용이며, 외부 노출 대상으로 취급하지 않음.
3. Firewall와 SELinux의 역할 차이 (가장 중요한 구분)¶
운영 사고의 상당수는 이 둘을 혼동하면서 발생함.
3.1 Firewall의 역할¶
| 항목 | 의미 |
|---|---|
| 기준 | 네트워크 |
| 판단 대상 | 패킷 |
| 질문 | “외부에서 이 포트로 들어와도 되는가?” |
→ 외부 접근 제어 담당
3.2 SELinux의 역할¶
| 항목 | 의미 |
|---|---|
| 기준 | 프로세스 |
| 판단 대상 | 프로세스 ↔ 포트 |
| 질문 | “이 프로세스가 이 포트로 connect 해도 되는가?” |
→ 내부 접근 제어 담당
핵심 정리¶
firewall는 “들어오게 할지”
SELinux는 “누가 쓰게 할지”를 결정함
4. 왜 proxy_pass가 SELinux에서 막히는가?¶
Nginx는 SELinux에서 httpd_t 타입으로 실행됨.
SELinux는 다음 질문을 던짐:
“
httpd_t프로세스가 tcp/3000 포트로 connect 해도 되는가?”
기본 정책의 현실¶
httpd_t→ 80, 443 (허용)httpd_t→ 3000 (❌ 기본적으로 차단)
따라서 다음 현상이 발생할 수 있음.
- Nginx는 정상 기동
proxy_pass대상(127.0.0.1:3000) 연결만 실패- 결과는 502/504 형태로 표면화됨
5. semanage port의 진짜 의미 (오해 금지)¶
다음 명령은 접근 허용 명령이 아님.
추가
sudo semanage port -a -t http_port_t -p tcp 3000
수정
sudo semanage port -m -t http_port_t -p tcp 3000
이 명령이 하는 일¶
“tcp/3000 포트는
http 계열 프로세스(httpd_t)가 connect 가능한 포트다
라고 SELinux에게 ‘포트 타입’으로 분류해준다”
하지 않는 일¶
- 포트 개방 ❌ (firewalld 영역)
- 외부 접근 허용 ❌ (firewalld 영역)
- Next.js 보안 완화 ❌ (오히려 Enforcing 유지에 필요한 정리)
👉 “사용 권한 분류(포트 타입 지정)”일 뿐임
6. 언제 semanage port 설정이 필요한가? (조건 명확화)¶
아래 조건이 모두 만족될 때만 의미 있음.
✅ 의미 있는 경우 (권장 시나리오)¶
- Next.js가
127.0.0.1:3000에서만 listen - firewall에서 3000 포트 미개방
- Nginx가 같은 서버에서 실행
proxy_pass http://127.0.0.1:3000- SELinux Enforcing
- Nginx(
httpd_t)가 내부적으로 3000에 connect 필요
👉 이 경우에만 아래 설정이 논리적으로 정확함.
추가
sudo semanage port -a -t http_port_t -p tcp 3000
수정
sudo semanage port -m -t http_port_t -p tcp 3000
❌ 의미 없거나 위험한 경우 (금지/불필요)¶
- Next.js 포트를 외부에 직접 열어둔 경우
- Nginx 없이 Next.js 단독 서비스
- SELinux Disabled / Permissive
- “에러 나니까 일단 넣는” 경우
👉 이 접근은 보안 모델 붕괴로 이어질 가능성이 높음.
7. 자주 발생하는 잘못된 사고 흐름¶
❌ 잘못된 대응:
- proxy_pass 안 됨
- SELinux 로그 무시
setenforce 0- “SELinux는 쓰면 안 된다” 결론
⭕ 올바른 대응:
- proxy_pass 안 됨
- SELinux audit 로그 확인
- “httpd_t → tcp/3000 connect 차단” 인지
- semanage 또는 boolean으로 정책 허용
- Enforcing 유지
8. 운영 기준 요약¶
- Next.js 포트는 외부에 열지 않음
semanage port는 포트 개방이 아님proxy_pass동작을 위한 SELinux 내부 권한 정리일 뿐- firewall / SELinux 역할을 혼동하지 않음
SELinux를 끄는 순간
“우리는 왜 Enforcing을 쓰는가?”라는 질문이 무의미해짐
9. 같은 카테고리의 다른 해결책: httpd_can_network_connect (Boolean)¶
SELinux Enforcing 환경에서 Nginx(httpd_t)의 proxy_pass가 막힐 때,
해결 방법은 크게 2가지 축으로 분류됨.
9.1 해결책 2가지 축 (Port Type vs Boolean)¶
-
semanage port ... -t http_port_t→ httpd_t가 “특정 포트”로 connect 가능하도록 포트 타입을 분류함 → 허용 범위가 좁고, 최소 권한 원칙에 가까움 -
setsebool -P httpd_can_network_connect 1→ httpd_t의 “네트워크 connect 자체”를 허용하는 Boolean → 허용 범위가 넓고, 서버 성격에 따라 더 실용적일 수 있음
즉, httpd_can_network_connect는 완전히 다른 문제가 아니라
“proxy_pass + SELinux” 흐름과 동일 카테고리(SELinux 내부 정책 허용) 에 속하며,
단지 허용 방식이 다른 것임.
9.2 언제 어떤 방식을 선택하는가 (운영 기준)¶
A) semanage port 방식 (포트 타입 분류) — 기본 권장¶
정해진 포트(예: 3000)로만 proxy_pass가 필요한 구조에서 적합함.
- Next.js가
127.0.0.1:3000에서만 listen - firewall에서 3000 포트는 외부 미개방
- Nginx가 동일 서버에서
proxy_pass http://127.0.0.1:3000수행
이 경우:
추가
sudo semanage port -a -t http_port_t -p tcp 3000
수정
sudo semanage port -m -t http_port_t -p tcp 3000
B) httpd_can_network_connect 방식 (Boolean) — 조건부 허용¶
서버가 Reverse Proxy / Gateway 성격이 강하고, Nginx가 다양한 내부 포트/백엔드로 connect 해야 하는 구조에서는 boolean 방식이 운영상 더 단순할 수 있음.
sudo setsebool -P httpd_can_network_connect 1
sudo systemctl restart nginx
9.3 반드시 기억할 점 (오해 금지)¶
semanage port는 방화벽 개방이 아니라 “포트 타입 분류”setsebool은 방화벽 개방이 아니라 “프로세스 권한 허용”- 외부 노출 여부는 firewalld(방화벽) 가 결정함
firewall = “들어오게 할지”
SELinux = “누가 쓰게 할지”
10. 최종 결론¶
semanage port는 보안 완화가 아니라 보안 유지 수단임- Nginx + Next.js + SELinux Enforcing은 완전히 공존 가능
- 이해 없이 설정만 하면 반드시 사고 남
이 문서를 이해했다면
더 이상 proxy_pass + SELinux로 삽질할 일은 없다