본문 바로가기

보안

https 적용 및 nginx 설정하기

프로젝트 진행 중, 프론트 서버는 vercel을 이용해서 배포를 진행하여 https로 배포가 되어 있다.

이때, 백 서버는 http로 배포가 되어 있어, mixed content 문제가 발생했다. 이러한 이유로 백엔드 단에 https를 적용해야 하는 상황에 직면했다.

 

https 적용 방법

1. 가비아 + ACM + AWS Route 53 + AWS Load Balancer을 활용한다.

2. 가비아 + Nginx + Certbot/SSL 을 활용한다.

 

💥 도메인이 필요한 이유는 SSL(TLS) 인증서를 발급 받을 때, 도메인이 아니라 IP일 경우 인증서 발급이 제한되기 때문이다.


가비아 + ACM + AWS Route 53 + AWS Load Balancer

✔ 사전 지식

💬 AWS Route 53

AWS에서 제공하는 DNS(Domain Name System) 웹 서비스이다.

◼ 구매한 도메인에 대해 IP를 연결하고 DNS 서비스를 제공해준다.

 

💬 ACM (AWS Certificate Manager)

◼ ACM은 AWS에서 제공하는 SSL/TLS 인증서 관리 시스템이다.

◼ CA(인증 기관)에서 발급한 인증서(Certificates)를 ACM에 등록하면 인증서 관리 및 AWS 서비스와의 연결 등을 관리해준다. 즉, ACM은 CA 역할을 하는 서비스이다.

◼ ACM에 인증서를 등록해두면, AWS 서비스들에서 SSL/TLS 인증 설정을 할 때 ACM의 주소만 명시하면 되어 편리하다.

 

✔ DNS 등록하기

AWS Route 53 서비스로 이동한다.

 

✨ 호스팅 영역 생성

◼ 호스팅 영역 생성 버튼을 클릭한다.

 

◼ 가비아에서 구매한 도메인 이름을 등록하고 설명 작성(Option)을 완료하면 호스팅 영역 생성을 클릭한다.

◼ 호스팅 영역이 생성되면 초기에는 위와 같이 NS, SOA 유형 2개가 존재한다.

 

💬 DNS Recode Type

SOA(Start Of Authority):  도메인의 시작점

A(Host): 해당 도메인 주소가 가지는 IP (1:1)

CNAME(Canonical NAME): 별칭 레코드로 실제 호스트명(A 레코드)과 연결되는 별칭, 별명을 정의 해주는 레코드이다. A 레코드와 비슷한 성격을 띄고 있으나, CNAME의 경우 도메인에 대한 IP를 넣어주는 것이 아닌 별칭을 넣어 해당 별칭에 대한 IP를 가져온다.

NS(Name Server): 영역을 풀이할 수 있는 DNS 서버 목록

 

✨ A 레코드 등록

◼ 레코드 생성 버튼을 클릭한다.

 

◼ 레코드 이름으로 도메인 이름을 작성하고, 값 부분에 aws ec2의 public ip 주소를 입력한다.

 

◼ 위와 같이 A 레코드가 추가된 것을 확인할 수 있다.

 

✨ 가비아에서 네임 서버 등록하기

◼ 가비아의 도메인 관리로 이동한다.

◼ 네임 서버의 설정 버튼을 클릭한다.

 

◼ AWS Route 53의 호스팅 영역에 등록되어 있는 NS 레코드의 4개의 값을 위 호스트명에 작성한다. 

◼ 소유자 인증을 진행하고 적용을 클릭한다.

SSL(TSL) 인증서 발급

ACM 서비로 이동한다.

 

✨ 인증서 생성하기

◼ 인증서 요청을 클릭한다.

 

◼ 다음을 클릭한다.

 

◼ 완전히 정규화된 도메인 이름 부분에 가비아에서 구매한 도메인을 작성하고 요청 버튼을 클릭한다.

◼ 이때, 도메인 이름은 *.도메인 이름으로 작성해야 한다.

 

◼ Route 53에서 레코드 생성 버튼을 클릭하면 Route 53의 호스팅 영역에 CNAME 레코드가 생성된다.

 

◼ 이후 일정 시간이 지나면 인증의 상태가 발급됨으로 변경된다.

 

 

위 모든 과정을 거치면 브라우저에 도메인 입력 시 등록한 ip로 요청이 가는 것을 확인할 수 있다.

+ 이후 Load Balancer를 연결하는 작업을 진행해야 한다.

(https 적용을 가비아 + Nginx + Certbot을 사용해서 진행할 예정으로 load balancer 연결 작업은 제외한다.)


가비아 + Nginx + Certbot/SSL

✔ 사전 지식

💬 Nginx 선택 이유

◼ Nginx는 경량 웹 서버로, WAS 서버의 부하를 줄여 줄 수 있는 로드 밸런서(Reverse Proxy) 역할로 활용된다.

◼ Event-Driven 구조로 동작하기 떄문에, 한 개 또는 고정된 프로세스만 생성하여 사용할 수 있다.

◼ 즉, nginx로 새로운 요청이 들어오더라도 새로운 프로세스나 쓰레드를 생성 및 사용하지 않기 때문에 비용 측면에서 이점이 존재하한다.

 

✨ Nginx 구조

◼ Nginx는 하나의 Master Process와 다수의 Worker Process로 구성되어 실행된다.

◼ Master Process는 설정 파일을 읽고 유효성 검사 및 Worker Process를 관리한다.

◼ 모든 요청은 Worker에서 처리한다. Worker Process의 개수는 설정 파일에서 정의하며, 정의된 프로세스의 개수와 사용 가능한 CPU 코어 숫자에 맞게 자동으로 조정된다.

 

💬 Reverse Proxy 사용 이유

◼ Reverse Proxy의 웹 서버를 사용하여 DB와 연결된 WAS의 보안을 강화할 수 있다.

◼ Reverse Proxy를 Cluster로 구성해 놓으면 가용성을 높일 수 있고, 사용자가 증가하는 상황에 맞게 Web Server나 WAS를 유연하게 늘릴 수 있다.

 

✔ 가비아에서 DNS 설정하기

◼ 가비아의 도메인 관리로 이동한다.

◼ 구매한 도메인을 클릭하고 DNS 설정 버튼을 클릭한다.

 

◼ 위와 같이 호스트, 값/위치 (AWS EC2의 Public IP)를 등록하고 저장 버튼을 클릭한다.  

◼ 호스트에 www와 @를 입력하는 이유는 도메인에 www를 붙였을 때와 붙이지 않았을 때 모두 적용되도록 하기 위함이다.

 

◼ 해당 작업을 진행하면 도메인으로 접속이 가능해진다.

 

✔ EC2에 nginx 설치하기

◼ sudo apt update

◼ sudo apt install nginx

◼ sudo ufw app list 명령어를 입력하면 다음과 같이 선택할 수 있다.

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
  
Nginx Full : 80, 443 포트
Nginx HTTP : 80
Nginx HTTPS : 443

◼ sudo ufw allow 'Nginx Full' -> 80, 443 포트 모두 허용해 주었다.

◼ sudo ufw allow 'OpenSSH' -> ssh도 허용해야 다음에 ssh 접속이 가능하다.

◼ sudo ufw status

◼ sudo ufw enable -> ufw 켜기

 

위 방법으로 nginx를 설치하면 다음과 같은 명령어로 nginx를 시작/종료할 수 있다.

sudo systemctl enable nginx // nginx 등록

sudo systemctl start nginx // nginx 시작

sudo systemctl stop nginx // nginx 종료

sudo systemctl restart nginx // nginx 재시작

sudo systemctl status nginx // nginx 상태

 

✔ nginx 설정 적용하기

◼ /etc/nginx/sites-enabled 폴더에 존재하는 dafault 파일 안에 server에 관한 설정을 할 수 있다.

◼ 로그 파일은 /var/log/nginx 폴더 아래 access log와 error log 파일이 존재한다.

 

sudo vi /etc/nginx/sites-enabled/dafault

◼ 해당 명령어를 통해 파일을 열고 수정한다.

 

◼ server_name 부분에 가비아에서 구매한 도메인을 도메인, www.도메인 형식으로 입력한다.

 

✔ certbot 설치

💥 2023 amazon-linux에서는 cerbot을 설치하려면 복잡하기 때문에, ubuntu os를 사용하는 것이 좋다.

 

◼ sudo apt install certbot python3-certbot-nginx

◼ certbot --version

 

SSL(TLS) 발급

◼ sudo certbot --nginx

 

◼ 위 명령어를 입력하면 다음과 같은 구문이 나오게 되고 처음에는 이메일 입력 ACME 서버 등록, 뉴스 및 기타 정보를 받을 지 여부, nginx의 server_name 부분에 작성한 domain이 나오게 되고 엔터를 클릭하면 SSL(TLS)를 발급 받을 수 있다.

 

◼ SSL(TLS)가 정상적으로 발급되면 위 사진과 같이 인증서와 Key 생성 위치와 만료 기간을 확인할 수 있다.

 

💥 위와 같은 방식으로 SSL(TLS)를 발급받고 도메인을 브라우저에 검색하면 https로 접속되는 것을 확인할 수 있다.

 

✔ 프록시 설정

## /etc/nginx/nginx.config
http {
    upstream app {
        least_conn;
        server ip:port;
        server ip:port;
             ...
    }
    
             ...
}

◼ /etc/nginx/nginx.config 파일에 위 설정을 추가한다.

Reverse Proxy를 설정하기 위해 upstream을 추가한다. 

least_conn 옵션으로 upstream 블록에 적힌 server 중 connection이 적은 서버로 요청을 분산한다. 

nginx 공식 문서에서 옵션을 확인해서 사용하면 된다.

 

## /etc/nginx/sites-enabled/default
location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 11M;
}

◼ /etc/nginx/sites-enabled/default 파일에 위 설정을 추가한다.

◼ 등록한 도메인에 대한 https 요청을 upstream으로 등록한 app 내의 server로 전송 시킨다. 

 

✔ SSL(TLS) 갱신

◼ Certbot으로 발급 받은 SSL(TLS)는 만료 기간이 3개월로 설정되어 있어 3개월마다 갱신해주어야 한다.

◼ 3개월마다 매번 서버에 접속해서 인증서를 갱신하는 것은 번거롭기 때문에 다음과 같이 자동화 할 수 있다.

 

◼ sudo vi /etc/crontab 설정 파일을 연다

◼ 위 코드를 해당 파일에 작성한다.

◼ 매일 10시, 1시에 root 권한으로 certbot renew --no-self-upgrade 명령어를 실행한다.

◼ certbot renew는 모든 인증서를 점검하고 만료 날짜가 다가오고 있는 인증서를 갱신한다.

◼ --no-self-upgrade는 사용자 개입 없이 업그레이드를 금지하는 옵션으로, 해당 옵션이 없으면 사용자의 y/n 입력을 받기 위해 대기해서 정상적으로 자동 업그레이드가 되지 않는다.

sudo systemctl restart cron 명령어로 위 설정을 적용한다.

 

결론

모든 설정을 정상적으로 했다면 도메인의 요청이 우리가 실행한 서버로 정상적으로 redirect 되는 것을 확인할 수 있다.