기존에 Docker 를 이용한 가상 호스트 환경에서 도메인을 운영하고 있었는데 (참조: Docker 를 사용한 가상 호스트(Virtual Host) 구축 및 서브 도메인 연결), HTTPS 서버를 구성할 필요가 생겼다. 검색을 해 보니 추가적인 비용 없이 간단하게 구성할 수 있는 방법으로 아마존 웹 서비스 (Amazon Web Service, AWS) 를 사용하는 방법이 있었고, 상세한 자료가 많아서 이를 따라 구축하였다 (참고: AWS SSL 적용 방법). 다만 가상 호스트 환경에서 HTTP 접속을 항상 HTTPS 접속으로 redirect 하기 위해서 추가적인 작업이 필요하여, 이 과정을 정리하였다. (수정: 아마존의 DNS 서비스인 Route53 을 사용 시 도메인 당 $0.5 의 비용이 있음)

아마존을 통한 HTTPS 인증 방식의 기본적인 구조

아마존에서 발급받은 인증서를 사용하기 위해서는 아마존의 로드 밸런서 (Elastic Load Balancer, ELB) 를 사용해야 한다. 이 로드 밸런서가 인증을 담당하고 HTTPS 트래픽을 실제 머신 (EC2) 으로 넘겨주는 것이다. 가장 기본적인 설정은 아래 그림과 같이, ELB 가 80 및 443 포트의 요청을 받으면 이를 모두 HTTP 요청으로 변환하여 백엔드 서버에 전달하는 것이다. 이렇게 하면 백엔드 서버를 수정하지 않고도 쉽게 HTTPS 요청을 받을 수 있는 장점이 있어 나와 같이 기존 HTTP 서버를 확장할 때 간편해 보인다.

graph LR A(HTTP request) -->|port 80| B[ELB] C(HTTPS request) -->|port 443| B B -->|port 80| D[EC2] style A fill:#BDD5EA,stroke-width:0px; style C fill:#BDD5EA,stroke-width:0px; style B fill:#eee,stroke:#999,stroke-width:1px; style D fill:#eee,stroke:#999,stroke-width:1px;

Nginx 서버의 설정 변경

위와 같은 설정을 마치면 HTTPS 요청을 잘 받는 것을 확인할 수 있다 (보안 정책에서 443 포트를 여는 것을 잊으면 안 된다). 두 번째로는 HTTP 요청이 들어와도 HTTPS 로 처리하도록 하는 작업이 필요한데, 예를 들어 blog.youngbin.kim 으로 접속을 할 경우 https://blog.youngbin.kim 으로 접속이 되도록 설정하는 것이다. 이 설정은 백엔드 서버에서 해 줘야 하는데, 문제는 ELB 가 모든 요청을 HTTP 로 변환해서 전달하기 때문에 서버에서는 들어온 요청이 원래 HTTPS 였는지 확인이 어렵다는 점이다. 이를 알려주기 위해서 ELB 에서는 X-Forwarded-Proto 헤더를 설정한다. (참고: Redirecting EC2 elb from http to https, How to force HTTPS behind AWS ELB) 이에 따라 nginx 서버 설정 파일에 아래와 같은 코드를 추가하여 HTTP 요청을 HTTPS 주소로 redirect 시켜줄 수 있다.

if ($http_x_forwarded_proto = 'http') {
    return 301 https://example.com$request_uri;
}

Nginx-proxy 이미지를 수정하여 HTTPS redirection 설정하기

일반적인 서버의 경우 위와 같은 처리를 해 주면 완료가 되지만, 나의 경우 nginx-proxy (jwilder/nginx-proxy) 를 이용한 virtual host 환경을 사용하고 있기 때문에 추가적인 처리가 필요하다. 이전 글 에서 언급했듯이 nginx-proxy 는 새로운 컨테이너가 로드될 경우 서버 설정 파일을 업데이트하는데, 이 과정은 새로운 컨테이너와 nginx.tmpl 파일을 기반으로 conf 파일을 새로 작성하는 것이다. 따라서 새로운 컨테이너가 추가될 때마다 기존 서버 설정이 nginx.tmpl 을 바탕으로 초기화되므로, 위 설정 코드를 nginx.tmpl 에 추가해 주어야 한다. 나의 경우 /app/nginx.tmpl 파일에서 HTTP 리퀘스트를 처리하는 부분location 위에 다음과 같은 코드를 추가하였다.

if ($http_x_forwarded_proto = 'http') {
     return 301 https://{{ trim $upstream_name }}$request_uri; 
}

카테고리:

업데이트: