Skip to Content
Dev Environment & ToolsNginx Proxy Manager로 로컬 HTTPS 접속 주소 통일하기
🛠️ Dev Environment & Tools2023년 1월 19일

Nginx Proxy Manager로 로컬 HTTPS 접속 주소 통일하기

#dev-environment-tools#nginx-proxy-manager#reverse-proxy#zero-trust#local-development#docker

앞 글에서는 mkcert로 로컬 HTTPS 인증서를 만들고 런타임별 신뢰 설정을 맞췄습니다. 다음은 여러 서비스를 그 인증서로 연결하는 일이었습니다.

당시에는 프런트엔드와 백엔드 API, 모킹 서버를 함께 실행했습니다. 로컬 서비스끼리만 붙일 때도 있었지만 일부 API는 이미 실행 중인 개발 서버에 연결해야 했습니다. 서비스마다 HTTPS를 설정하기보다 앞에 프록시를 두고 인증서와 라우팅을 한곳에서 관리했습니다.

브라우저 접속 주소 통일

브라우저의 origin은 스킴·호스트·포트로 구분합니다. 같은 도메인이어도 :3000의 화면에서 :8080의 API를 호출하면 서로 다른 origin입니다.

프록시를 두면 브라우저는 하나의 HTTPS 주소로 요청하고, 프록시가 경로에 따라 뒤쪽 서비스를 선택할 수 있습니다. 아래 주소와 포트는 구성을 설명하기 위한 예시입니다.

브라우저 요청프록시 뒤의 대상
https://app.local.test/프런트엔드 개발 서버, 포트 3000
https://app.local.test/api/로컬 백엔드, 포트 8080
https://app.local.test/auth/로컬 또는 개발 환경 인증 서비스

쿠키는 포트별로 분리되지 않지만 요청의 origin은 달라질 수 있습니다. 접속 주소를 맞추면 프런트엔드와 API 사이의 CORS 구성을 줄일 수 있습니다. 다만 쿠키의 Domain·Path·SameSite와 SSO 리디렉션 허용 주소까지 자동으로 맞춰지는 것은 아니므로 로그인 흐름은 별도로 확인했습니다.

Nginx Proxy Manager 선택

로컬에서는 연결할 서비스와 포트를 자주 바꿔야 했습니다. Nginx Proxy Manager는 Docker로 실행할 수 있고, 웹 화면에서 프록시 호스트와 인증서를 등록할 수 있어 이런 설정을 바꾸기 편했습니다.

다음은 공식 실행 예시 를 바탕으로 로컬 접속용 포트 바인딩을 지정한 구성입니다. 프로젝트에 계속 사용할 때는 이미지 버전도 고정해 관리할 수 있습니다.

yaml
sample/compose.yaml
services: nginx-proxy-manager: image: jc21/nginx-proxy-manager:latest ports: - "127.0.0.1:80:80" - "127.0.0.1:81:81" - "127.0.0.1:443:443" volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt
bash
docker compose up -d

관리 화면은 http://localhost:81에서 열고 초기 계정 설정을 진행합니다. 두 볼륨에는 프록시 설정과 인증서 파일을 보관해 컨테이너를 다시 만들어도 사용할 수 있게 했습니다.

인증서와 프록시 호스트 등록

mkcert로 발급한 app.local.test용 인증서와 개인 키를 관리 화면의 Custom SSL Certificate로 등록합니다. 다음으로 Proxy Host를 만들고 SSL 탭에서 해당 인증서를 선택합니다.

프런트엔드가 호스트 장비의 3000번 포트에서 실행된다면 설정은 다음과 같습니다.

text
Domain Names: app.local.test Scheme: http Forward Hostname: host.docker.internal Forward Port: 3000

여기서 HTTPS는 브라우저와 프록시 사이에서 처리합니다. 이 로컬 구성에서는 뒤쪽 애플리케이션이 HTTP로 요청을 받으므로 서비스마다 인증서 경로를 지정할 필요가 없었습니다.

host.docker.internal은 Docker Desktop에서 컨테이너가 호스트에 접근할 때 사용하는 이름입니다. 다른 컨테이너 실행 환경에서는 호스트 접근 방식을 확인해야 합니다. 백엔드도 같은 Docker 네트워크 안에서 실행한다면 서비스 이름으로 연결할 수 있습니다.

경로별 서비스 연결

같은 Proxy Host의 Custom Locations에서 /api/ 같은 경로를 별도 서비스로 연결할 수 있습니다. 로컬 API와 개발 서버 API를 섞는 경우에도 각 경로가 어느 대상을 가리키는지 구분해 설정했습니다.

이때 브라우저 주소만 확인하면 부족합니다. 뒤쪽 애플리케이션이 /api/ 접두사를 포함한 경로를 기대하는지, 프록시에서 경로를 바꿔야 하는지도 맞춰야 합니다. 개발 서버를 연결할 때는 upstream의 HTTPS와 인증서 검증 설정도 별개로 확인해야 합니다.

연결 이후 확인

화면이 열린 뒤에는 API 요청과 로그인 리디렉션, 쿠키 전송을 확인했습니다. 화면 개발 서버가 WebSocket을 사용한다면 HMR 연결도 함께 봐야 합니다.

이 구성 덕분에 로컬 서비스마다 SSL을 설정하는 일을 줄이고, 브라우저가 접근하는 주소를 한곳에서 관리할 수 있었습니다. 대신 서비스의 포트나 경로가 바뀌면 프록시 규칙도 같이 수정해야 했습니다.

참고 자료

Last updated on