Nginx를 이용한 Nexus 리버스 프록시 구성
Maven 3.8.1부터 HTTP 저장소가 기본 차단되었는데, Nexus는 HTTP로만 동작합니다. HTTPS를 적용하려면 어떻게 해야 할까요?
Nginx 리버스 프록시 는 Nexus 앞에서 HTTPS 종료(SSL Termination)를 처리하고, 도메인 기반 접근과 포트 숨김을 한 번에 해결합니다. Nexus 자체에 SSL을 설정할 필요 없이, Nginx가 외부와 HTTPS로 통신하고 내부에서는 HTTP로 Nexus에 전달하는 구조입니다.
왜 리버스 프록시가 필요한가
Nexus는 기본적으로 HTTP와 고번호 포트(예: 8081, 40000)로 동작합니다. 이 상태로 운영하면 세 가지 문제가 발생합니다.
| 문제 | 설명 |
|---|---|
| Maven 3.8.1+ HTTP 차단 | Maven 3.8.1부터 HTTP 저장소를 기본적으로 차단합니다. settings.xml에서 별도로 mirror 설정을 하지 않는 한, HTTP URL로는 의존성을 받아올 수 없습니다 |
| ** 포트 번호 노출** | http://nexus.example.com:40000 같은 URL은 기억하기 어렵고, 방화벽 정책 관리가 복잡해집니다 |
| ** 보안 취약** | 아이디/비밀번호가 평문으로 전송되어, 네트워크 스니핑에 노출될 수 있습니다 |
Maven 3.8.1 이후부터
super POM에 HTTP 저장소를 차단하는 mirror 설정이 기본 포함되었습니다. 따라서 HTTPS를 적용하지 않으면Could not transfer artifact오류가 발생합니다. 이것이 Nexus에 HTTPS를 적용해야 하는 가장 직접적인 이유입니다.
리버스 프록시를 사용하면 이 문제들을 한 번에 해결할 수 있습니다.
- SSL 종료(Termination): Nginx가 HTTPS를 처리하고, Nexus에는 HTTP로 전달합니다. Nexus 자체에 SSL을 설정할 필요가 없습니다.
- ** 도메인 네임 적용 **:
https://nexus.example.com처럼 깔끔한 URL로 접근 가능합니다. - ** 포트 숨김 **: 외부에는 443(HTTPS) 포트만 노출합니다.
Nginx 설치
# Nginx 설치 (Rocky Linux / RHEL 계열)
yum install nginx -y
# 서비스 관리 명령어
systemctl start nginx # 시작
systemctl enable nginx # 부팅 시 자동 시작
systemctl status nginx # 상태 확인
systemctl restart nginx # 재시작
systemctl stop nginx # 중지
설치 후 브라우저에서 http://<서버IP>로 접속하여 Nginx 기본 페이지가 표시되는지 확인합니다.
| 경로 | 용도 |
|---|---|
/etc/nginx/nginx.conf | Nginx 메인 설정 파일 |
/etc/nginx/conf.d/ | 서버 블록(가상 호스트) 설정 디렉터리 |
/var/log/nginx/access.log | 접근 로그 |
/var/log/nginx/error.log | 오류 로그 |
SSL 인증서 준비
HTTPS를 적용하려면 SSL 인증서가 필요합니다. 발급받은 인증서 파일을 Nginx가 읽을 수 있는 경로에 저장합니다.
# SSL 인증서 저장 디렉터리 생성
mkdir -p /etc/nginx/ssl
# 인증서 파일 배치
# - certificate.crt : 서버 인증서 (중간 인증서 포함 시 체인 형태로 합침)
# - private.key : 개인 키
cp certificate.crt /etc/nginx/ssl/
cp private.key /etc/nginx/ssl/
# 개인 키 파일은 root만 읽을 수 있도록 권한 설정
chmod 600 /etc/nginx/ssl/private.key
사내 환경에서는 사설 CA(Certificate Authority)에서 발급한 인증서를 사용하는 경우가 많습니다. 이 경우 개발자 PC의 JVM truststore에 해당 CA 인증서를 등록해야 Maven에서 HTTPS 접근이 가능합니다.
Nginx 리버스 프록시 설정
설정 파일 작성
# /etc/nginx/conf.d/nexus.conf
# HTTP → HTTPS 리다이렉트
server {
listen 80;
server_name nexus.example.com;
# 모든 HTTP 요청을 HTTPS로 리다이렉트
return 301 https://$host$request_uri;
}
# HTTPS 서버 블록
server {
listen 443 ssl http2;
server_name nexus.example.com;
# --- SSL 인증서 설정 ---
ssl_certificate /etc/nginx/ssl/certificate.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;
# TLS 1.2 이상만 허용 (1.0, 1.1은 보안 취약)
ssl_protocols TLSv1.2 TLSv1.3;
# --- 리버스 프록시 설정 ---
location / {
proxy_pass http://localhost:40000;
# Host 헤더 전달: Nexus가 요청의 원래 도메인을 알 수 있도록 함
proxy_set_header Host $host;
# 클라이언트의 실제 IP 전달: 프록시를 거치면 Nexus에는 127.0.0.1로 보이므로
proxy_set_header X-Real-IP $remote_addr;
# 프록시 체인에서의 클라이언트 IP 목록 전달
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 원래 프로토콜(https) 전달: Nexus가 리다이렉트 URL을 올바르게 생성하기 위해 필요
proxy_set_header X-Forwarded-Proto $scheme;
}
}
각 디렉티브의 역할
| 디렉티브 | 역할 |
|---|---|
listen 443 ssl http2 | 443 포트에서 SSL과 HTTP/2 프로토콜을 활성화합니다 |
server_name | 이 서버 블록이 처리할 도메인을 지정합니다 |
ssl_protocols | 허용할 TLS 버전을 지정합니다. TLSv1.0/1.1은 보안 취약점이 있어 제외합니다 |
proxy_pass | 요청을 전달할 백엔드(Nexus) 주소를 지정합니다 |
proxy_set_header Host | 클라이언트가 요청한 원래 도메인을 백엔드에 전달합니다. 이 헤더가 없으면 Nexus는 localhost로 요청이 온 것으로 인식합니다 |
proxy_set_header X-Real-IP | 클라이언트의 실제 IP를 전달합니다. 로그와 접근 제어에 사용됩니다 |
proxy_set_header X-Forwarded-For | 프록시 체인을 거친 클라이언트 IP 목록을 전달합니다 |
proxy_set_header X-Forwarded-Proto | 원래 요청의 프로토콜(http/https)을 전달합니다. Nexus가 내부적으로 URL을 생성할 때 올바른 프로토콜을 사용하게 됩니다 |
설정 적용
# 설정 파일 문법 검사
nginx -t
# 문법 오류가 없으면 Nginx 재시작
systemctl restart nginx
브라우저에서 https://nexus.example.com으로 접속하여 Nexus 웹 UI가 정상적으로 표시되는지 확인합니다.
트러블슈팅
502 Bad Gateway
Nginx는 정상이지만 백엔드(Nexus)에 연결할 수 없을 때 발생합니다.
# Nexus가 실행 중인지 확인
systemctl status nexus.service
# Nexus 포트가 열려 있는지 확인
ss -tlnp | grep 40000
# Nginx 오류 로그 확인
tail -f /var/log/nginx/error.log
| 원인 | 해결 |
|---|---|
| Nexus 서비스가 중지됨 | systemctl start nexus.service로 시작합니다 |
proxy_pass의 포트가 Nexus 실행 포트와 불일치 | nexus-default.properties의 application-port와 동일한지 확인합니다 |
| SELinux가 Nginx의 네트워크 연결을 차단 | setsebool -P httpd_can_network_connect 1을 실행합니다 |
Rocky Linux / RHEL 계열에서는 SELinux가 기본 활성화되어 있습니다. Nginx가 백엔드로 TCP 연결하려면
httpd_can_network_connect불리언을 허용해야 합니다. 이것은 매우 자주 발생하는 문제입니다.
SSL 인증서 오류
브라우저에서 NET::ERR_CERT_AUTHORITY_INVALID 또는 Maven에서 PKIX path building failed 오류가 발생하는 경우입니다.
| 원인 | 해결 |
|---|---|
| 자체 서명(self-signed) 인증서 사용 | 사내 CA 인증서를 클라이언트 PC의 신뢰 저장소에 등록합니다 |
| 중간 인증서 누락 | certificate.crt 파일에 서버 인증서와 중간 인증서를 순서대로 합쳐서 체인 인증서로 구성합니다 |
| Maven JVM에서 인증서를 신뢰하지 않음 | JVM의 cacerts에 인증서를 추가합니다: keytool -importcert -alias nexus -file certificate.crt -keystore $JAVA_HOME/lib/security/cacerts |
Nginx 설정 반영이 안 되는 경우
# 설정 파일 문법 검사 (오류 시 상세 메시지 출력)
nginx -t
# 정상이면 설정 리로드 (서비스 중단 없이 반영)
nginx -s reload
systemctl restart nginx는 Nginx 프로세스를 완전히 재시작합니다. 운영 중에는nginx -s reload로 무중단 반영하는 것이 안전합니다.
주의할 점
SELinux가 Nginx 네트워크 연결을 차단
Rocky Linux/RHEL 계열에서 가장 자주 빠지는 함정입니다. Nginx를 설치하고 proxy_pass를 설정했는데 502 Bad Gateway가 나오면, 십중팔구 SELinux가 원인입니다. setsebool -P httpd_can_network_connect 1을 실행해야 Nginx가 백엔드로 TCP 연결을 할 수 있습니다.
X-Forwarded-Proto 헤더 누락
proxy_set_header X-Forwarded-Proto $scheme을 빠뜨리면, Nexus가 내부적으로 URL을 생성할 때 http://로 리다이렉트합니다. 브라우저에서 HTTPS로 접속했는데 HTTP로 리다이렉트되는 현상이 발생하면 이 헤더를 확인합니다.
정리
| 항목 | 설명 |
|---|---|
| 리버스 프록시 목적 | HTTPS 적용, 도메인 네임, 포트 숨김 |
| SSL Termination | Nginx가 HTTPS 처리, Nexus에는 HTTP로 전달 |
| 필수 헤더 | Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto |
| HTTP 리다이렉트 | return 301 https://$host$request_uri |
| SELinux 설정 | setsebool -P httpd_can_network_connect 1 |
| 무중단 반영 | nginx -s reload (restart 대신) |