ec2+route53+nginx+certbot 을 통한 https 적용기 및 트러블 슈팅

기영·2024년 11월 12일
1
post-thumbnail

본 포스팅은 aws ec2를 이용한 리액트, 스프링 프로젝트 배포 및 도메인/https 적용 과정과 과정 중 겪은 트러블 슈팅에 관한 내용입니다.

틀린 내용이 있다면 댓글로 알려주시면 감사하겠습니다.

사용 환경

  • ❗️ 별개의 aws 계정으로 ec2 배포
  • 가비아에서 도메인 구매 DOMAIN.co.kr (DOMAIN은 가칭)
  • Route53을 통한 호스팅 영역 및 도메인 설정
  • nginx와 letsencrypt(certbot)을 통한 https 적용

📌 참고
본 포스팅에서 도메인 구매, 프로젝트 배포 등의 과정은 생략한다.

또한, 프로젝트는 이미 배포되어 있는 상태를 가정한다.

리액트는 빌드된 파일을 nginx를 통해 실행하고, 스프링은 nohup을 통한 백그라운드 실행 및 8080 포트에서 동작하고 있음을 전제로 한다.

각 인스턴스에서 http(80), https(443) 포트에 대한 인바운드 규칙을 설정해주어야 한다.

aws 설정 - Route53

앞서 언급하였듯이 필자는 별개의 aws 계정을 사용하여 각 프로젝트를 배포하였다.
이에 따라서 Route53 호스팅 영역 설정 시 고려해야되는 사항이 있다.

필자는 해당 부분때문에 약 4일 정도를 고생하다가 해결하였다.
비슷한 상황이신 분들이 나와 같은 고생을 겪지 않았으면 하는 마음에 해당 포스팅을 작성한다.

우선, 가비아에서 등록한 도메인(Domain.co.kr)을 통하여 Route53에서 호스팅 영역을 생성해야 한다.

필자는 하위 도메인으로 프론트엔드는 www.DOMAIN.co.kr / 백엔드는 api.DOMAIN.co.kr을 사용하려 한다.

프론트엔드 호스팅 영역 및 레코드 생성

우선 Route53에서 '호스팅 영역' 카테고리를 선택하면 다음과 같은 화면이 나온다.
호스팅 영역 생성 버튼을 클릭하여 호스팅 영역을 생성하자.

프론트엔드 계정의 호스팅 영역은 가장 상위 도메인인 DOMAIN.co.kr로 설정한다.
호스팅 영역 생성 버튼을 누르면 다음과 같은 화면이 나온다.

위 호스팅 영역에 나오는 NS 레코드를 가비아의 네임서버에 적용하여 주어야한다.

NS 레코드에 나오는 4개의 레코드를 가비아의 1~4차 네임서버에 적용해주고 적용까지 시켜주어야 DOMAIN.co.kr 도메인 접속 시 aws의 네임서버들에서 내 인스턴스의 레코드를 찾을 수 있게 되는 것이다.

자, 이제 내 프론트엔스 인스턴스를 www.DOMAIN.co.kr으로 A 레코드로 등록해주어야 한다.

레코드 생성 버튼을 누른 뒤 A 레코드를 선택한 뒤, 하위 레코드를 www로 적어주고 프론트엔드 서버의 public ip를 입력해주자.

위와 같이 입력한 뒤 '레코드 생성' 버튼을 클릭해서 A 레코드를 추가하자.

위와 같이 레코드가 등록되면 프론트엔드의 도메인 적용이 정상적으로 완료된 것이다.
www.DOMAIN.co.kr로 직접 접속해 확인해보자.

❗ 필수 참고
필자는 이후 https 적용 시 기타 여러 블로그들을 참고하다보니 www.DOMAIN.co.kr 이외에도 DOMAIN.co.kr A 레코드도 생성해 프론트엔드 서버 public ip를 적용시켜주었다.
따라서, 프론트엔드 Route53에는 총 4개의 레코드가 생성되어 있다.


백엔드 호스팅 영역 생성 및 레코드 생성

백엔드는 DOMAIN.co.kr의 하위 도메인인 api.DOMAIN.ac.kr로 구성한다.

📌 Trouble Shooting - 별개 aws 계정으로 프론트/백 배포 시 호스팅 영역 설정 관련 문제
해당 에러는 필자가 4일동안 해결하지 못하다가 겨우 해결해 낸 에러다.
나와 비슷한 상황인 다른 분들은 해당 에러로 골머리 겪지 않기를 바란다.

우선, 에러를 겪어던 상황을 자세히 설명하면

▶ 별개의 aws 계정으로 프론트/백 배포 후 Route53의 동일한 이름의 호스팅 영역 생성
도메인 및 https 적용 블로그들을 보면 대부분 단일 계정으로 배포를 진행한 포스팅이었다.
필자는 해당 글들을 참고하다보니, 호스팅 영역을 프론트/백 동일하게 DOMAIN.co.kr로 생성하였다.
이후, 각 호스팅 영역에 할당되는 4개의 레코드를 모두 가비아에 적용시켜서 가비아에는 총 8개의 네임서버(프론트 NS 4개 + 백 NS 4개)가 등록되어 있었다.
이는 이후에 도메인을 찾지 못해 certbot을 통한 인증서 발급이 되지 않는 문제로 이어졌다.

▶ 해결
해결 방법은 호스팅 영역을 정확하게 구분하여 생성하는 것이다.
필자는 호스팅 영역으로 프론트엔드 DOMAIN.co.kr / 백엔드 api.DOMAIN.co.kr으로 나누어 생성하였다.

호스팅 영역 생성 시 작성하는 도메인 이름은 하나의 컨테이너 이름이다.
따라서, 두 계정에서 동일한 도메인(DOMAIN.co.kr)으로 호스팅 영역 생성 시 컨테이너를 구분할 수 없게 되어 도메인을 찾지 못하는 에러가 발생하는 것이었다.

위와 같은 이유때문에 호스팅 영역은 api.DOMAIN.co.kr로 생성한다.

위와 같이 호스팅 영역을 생성하고 나면, 백엔드 인스턴스를 A 레코드로 등록한다.

위와 같이 설정을 완료하게 되면 api.DOMAIN.co.kr로 접속해서 연결이 잘 되는 지 확인해보자.

참고로 필자는 80 → 8080으로 포트포워딩을 해주었기때문에 api.DOMAIN.co.kr로 접속하면 Spring Security로 인하여 401 에러가 응답되었다. 해당 메시지는 필자가 직접 설정한 커스텀 에러 응답 구조이므로 필자와 다르게 나와도 괜찮다.

포트포워딩을 따로 해주지 않은 상황이면 api.DOMAIN.co.kr:8080으로 접속해서 스프링에서 설정한 응답을 확인하면 된다.

위와 같이 백엔드 연결이 잘 되는 것을 확인하면, 프론트엔드 호스팅 존에 백엔드 NS 레코드를 추가해줘야 한다.
그래야지만, 이후 인증서 발급 시 도메인을 통해 백엔드 서버를 찾아 인증할 수 있게 된다.

따라서, 최종적으로 프론트엔드 호스팅 존은 다음과 같은 형태가 된다.


인증서 발급 및 nginx 적용

프론트엔드 인스턴스

git, nodejs, npm 등 설치는 생략한다.

1. nginx 설치

$ sudo apt install nginx -y
# nginx 완전 삭제 명령어
$ apt-get remove --purge nginx nginx-full nginx-common 

2. nginx 동작 확인

$ sudo systemctl start nginx

$ sudo systemctl status nginx

이후, 인스턴스의 public ip또는 도메인을 통하여 접속해보기

다음과 같이 Welcome to Nginx 화면이 뜨면 Nginx가 제대로 동작하고 있는 것이다.

3. certbot 설치

여러가지 블로그들을 참고하여보니 certbot 설치는 3가지 방법 정도가 있다.

$ sudo apt install letsencrypt

$ sudo apt install certbot

$ sudo snap install certbot --classic  # 필자가 선택한 방법

필자는 3번 방법을 통하여 certbot을 설치한다.
snap 및 certbot 설치에 몇 분 정도 소요된다.

4. certbot을 통한 인증서 발급

$ sudo certbot --nginx

기타 블로그를 참고하니 인증서 발급에도 여러 방법이 있는 것 같다.
필자는 위와 같은 명령어를 통하여 인증서를 발급받았다.

원래는 certbot 인증서 발급 시 이메일도 입력을 해야한다.
필자는 초기에 프론트엔드 https 적용부터 시도하였고, 4일 내내 여러 시도를 해봤기 때문에 이메일을 입력하는 부분을 이미 진행하여 위 사진에는 이메일 입력 칸이 뜨지 않은 것 같다.

📌 '백엔드 인스턴스 - certbot 설치' 절을 확인해보면 이메일 인증도 진행하였으니 확인하길 바란다.

5. 발급된 인증서를 통한 nginx 설정

4번 과정에서 확인할 수 있듯이 sudo certbot --nginx 명령어를 통해 인증서를 발급받으면 알아서 /etc/nginx/sites-available/default 파일을 수정한다.

nginx로 프로젝트 배포 시 default 파일 삭제 후 myapp.conf 등의 커스텀 설정 파일을 만들어 적용시키는 경우가 있는데, 해당 경우에는 아래에 나오는 설정 파일 내용을 그대로 적용시키면 문제없이 동작하리라 예상이 된다.

certbot이 수정한 default 설정 파일 내용을 확인해보자.

# ============================ #
# Default server configuration #
# ============================ #

server {
	...
}

...

server {
	...
    server_name www.DOMAIN.co.kr; # managed by Certbot


	location / {
		...
		try_files $uri $uri/ =404;
	}

	...

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
❗️	ssl_certificate /etc/letsencrypt/live/www.DOMAIN.kr/fullchain.pem; # managed by Certbot
❗️	ssl_certificate_key /etc/letsencrypt/live/www.DOMAIN.co.kr/privkey.pem; # managed by Certbot
❗️	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
❗️	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = www.DOMAIN.co.kr) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


	listen 80 ;
	listen [::]:80 ;
    server_name www.DOMAIN.co.kr;
    return 404; # managed by Certbot
}

불필요 내용이나 주석 등은 다 ...으로 처리하였다.

위의 내용에서 우리가 중요하게 봐야할 부분은 ❗️로 표시된 부분 뿐이다. 해당 부분이 https 통신을 가능하게 해주는 것이다.

해당 코드를 복사해놓고 우선 나머지 부분은 다 삭제해도 무방하다.

이후 내용을 아래와 같이 변경하자.

당연히 해당 작업을 하기전에 리액트 프로젝트가 설치되어 있어야하고, 빌드되어 있어야한다.
즉, /home/ubuntu/프로젝트이름/build 경로 내에 필드된 파일들이 위치해있어야한다.

server {
	listen 443 ssl;
   	server_name www.DOMAIN.co.kr; # managed by Certbot

	location / {
		root /home/ubuntu/PROJECT_NAME/build;
		index index.html index.html;
		try_files $uri $uri/ /index.html;
	}

    ssl_certificate /etc/letsencrypt/live/www.DOMAIN.kr/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/www.DOMAIN.co.kr/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
	listen 80;
    server_name www.DOMAIN.co.kr;
    return 301 https://www.DOMAIN.co.kr$request_uri;
}

위 코드에서 DOMAINPROJECT_NAME 부분은 당연히 자신의 도메인, 프로젝트(디렉토리) 명으로 되어있어야 한다.

위 코드는 프론트엔드(리액트) nginx 설정 코드로

  • https(443) 요청 → 리액트 프로젝트 띄우기
  • http(80) 요청 → https 요청으로 리다이렉트

위와 같은 역할을 수행한다.

자, 이제 모든 설정이 끝났으면 nginx를 재시작하자.

$ sudo systemctl restart nginx

이후 브라우저로 접속해서 확인해보자.

성공 ❗

드디어, 4일만에 본 https 적용에 성공한 페이지이다.
http로 접속을 하더라도 https로 리다이렉트된다.


백엔드 인스턴스

백엔드는 기존에 nohup를 통해 스프링 프로젝트가 8080포트로 실행되고 있음을 가정한다.

1. nginx 설치

$ sudo apt update

$ sudo apt upgrade

$ sudo apt install nginx

2. certbot 설치

$ sudo snap install certbot --classic

3. certbot을 통한 인증서 발급

📌 Trouble Shooting : Certbot failed to authenticate some domains

출력 에러 로그를 확인하면 unauthorized, 401 에러가 발생한 것을 알 수 있다.
certbot은 CA 발급을 위해 80 포트를 사용한다.

필자는 기존에 사용 편의성을 위해 80 → 8080 포트로 포트포워딩을 진행하였다.
따라서, 위 에러는 스프링 시큐리티에 의해 401 에러를 응답한 것이다.

위 에러를 해결하기 위해 포트포워딩 설정을 해제한다.

$ sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

이후, 다시 certbot을 통한 인증서 발급을 진행한다.

$ sudo certbot --nginx

위 출력 로그와 같이 인증서 발급이 진행되었고, nginx의 default 설정 파일에 인증서 관련 설정이 자동으로 배포된 것을 알 수 있다.

4. nginx 설정 변경

server {
	listen 443 ssl;
	server_name api.DOMAIN.co.kr;

	location / {
		proxy_pass http://localhost:8080; // ❗️ 8080포트로 열린 스프링 프로젝트로 연결
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
	}

	ssl_certificate /etc/letsencrypt/live/api.DOMAIN.co.kr/fullchain.pem;	# managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/api.DOMAIN.co.kr/privkey.pem;	# managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf;						# managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 							# managed by Certbot
}

server {
	listen 80;
	server_name api.DOMAIN.co.kr;
	return 404; // ❗️ api 서버는 http(80) 요청 시 404 에러 리턴
}

설정 완료 후 nginx 재시작

$ sudo systemctl restart nginx

5. 결과 확인

성공 ❗

백엔드 서버는 설정한 것과 같이 https로 요청 시 정상적인 응답, http 요청 시 nginx를 통한 404 에러를 응답하는 것을 알 수 있다.

이와 같이 프론트, 백엔드 모두 https를 적용시켰다.


결론

개발 시 코드가 아니라 이러한 시스템 구조에 관한 설정 부분이 개념부터 적용까지 굉장히 낯설고, 자료도 많이 모호하며 어려운 것 같다.

필자도 호스팅 영역 설정 같은 간단한 문제였지만 해당 부분을 몰라 4일 동안 해결을 못하고 있었다. 해결 방법을 정말 시간과 노력을 투자해 여러 자료를 찾아다니고 직접 산전수전 겪어가며 적용해보는 수 밖에 없는 것 같다.

다행히 많은 IT 전공생, 종사자분들이 많은 자료를 공유하고 있다.
나의 포스팅도 https 적용에 문제를 겪고 있는 분들에게 도움이 되었으면 한다.

profile
computer engineering student

0개의 댓글