AWS EC2 도메인 및 HTTPS 적용
서론
필자는 소프트웨어 공학 수업에서 팀장 및 백엔드 개발, 배포 과정을 담당하였다. 멋쟁이사자처럼 12기 대학 아기사자 활동을 하며 배포까지는 경험을 해보았지만, 주도적인 경험이 아니었으며 도메인 및 https 적용은 진행하지 않았기에 해당 프로젝트를 통하여 도메인 및 https를 적용한 배포를 경험해보고자 한다.
AWS EC2를 통하여 배포를 진행하며, 프론트엔드와 백엔드는 하나의 계정이 아닌 별도의 계정으로 배포를 진행한다. 해당 포스팅에서는 도메인 및 https 적용에 관한 전반적인 내용과 별개 계정으로 진행한 배포로 인하여 https 인증서 발급 시 발생되는 트러블 슈팅에 관한 내용을 담고자 한다.
사용 환경
- 별개의 AWS 계정을 통한 배포
- 가비아를 통한 도메인 사전 구매 - DOMAIN.co.kr (가칭)
- Route53을 통한 호스팅 영역 및 도메인 설정
- Nginx와 letsencrypt(certbot)을 통한 https 적용
본 포스팅에서 도메인 구매 및 프로젝트 배포에 관한 과정은 생략한다.
프론트엔드(리액트)는 Nginx, 백엔드(스프링)은 nohup을 통한 빌드 파일을 실행하고 있다.
각 인스턴스에서 http(80)와 https(443) 포트에 대한 인바운드 규칙을 설정해주어야 한다.
Route53
Amazon Route53은 가용성과 확장성을 보장하는 도메인 이름 시스템(DNS)이다.
Route53은 자체적으로 도메인 구매 서비스를 제공하며, 외부 기관에서 구매한 도메인도 등록 가능하다. 이외에도 로드밸런싱이나 EC2, ELB, S3 등과 같은 AWS 인프라와 통합된 환경을 구축할 있는 서비스를 제공한다.
필자는 가비아를 통하여 DOMAIN.co.kr 도메인을 구매하였다. 최상위 도메인(TLD, Top-Level Domain)으로 .xyz
와 같은 도메인 사용 시 https 인증이 정상적으로 진행되지 않을 수도 있으므로 이 점을 유의해야 한다.
하위 도메인으로 프론트엔드 서버는 www.DOMAIN.co.kr, 백엔드 서버는 api.DOMAIN.co.kr을 사용한다. 각 하위 도메인에 관한 설정은 Route53 상에서 호스팅 영역을 생성하여 진행한다.
프론트엔드
프론트엔드 계정에서 Route53 DOMAIN.co.kr로 호스팅 영역을 생성한다.
호스팅 영역 생성 시 NS(Name Server) 레코드와 SOA(Start of Authority) 레코드가 생성된다.
NS 레코드에 기입된 4개의 네임서버는 아마존에서 관리하는 현재 도메인의 네임서버를 지칭한다. 따라서, 가비아에서 구매한 도메인의 네임서버를 아마존 네임서버로 변경해주어야 한다.
가비아의 1~4차 네임서버를 Route53 호스팅 영역의 네임서버로 교체하여 준다. 이 때, Route53 NS 레코드에 구분자로 사용된 .
은 제거한 뒤 기입하여야 한다.
도메인의 네임서버를 교체하고 난 뒤, 프론트엔드 하위 도메인 www.DOMAIN.co.kr을 방금 생성한 호스팅 영역의 A 레코드로 등록해주어야 한다.
A 레코드는 IPv4 주소 및 AWS 상에서 사용 중인 리소스(EC2 등)를 통한 라우팅 유형이다.
www
을 입력한 뒤, 값 부분에는 프론트엔드 인스턴스 IP를 입력하여 준다.
레코드 생성을 완료하고 나면 호스팅 영역 내 방금 입력한 A 레코드가 추가된 것을 확인할 수 있다.
www.DOMAIN.co.kr로 접속하면 배포한 리액트 서버에 접속할 수 있게 된다. A 레코드 추가 후 해당 도메인이 적용되기까지는 시간이 소요된다고 한다. 소요 시간은 개인마다 차이가 있으면 필자는 5분만에 진행이 되었다.
백엔드
백엔드는 api.DOMAIN.co.kr 하위 도메인을 사용한다.
Trouble Shooting
앞서 언급하였듯이 해당 프로젝트의 프론트엔드와 백엔드 서비스는 별개의 계정으로 배포를 진행하였기에 호스팅 영역 설정에 있어 고려 사항이 존재한다. 우선, 에러를 발생시킨 상황은 다음과 같다.
PROBLEM. Route53에 동일한 이름의 호스팅 영역 생성
배포에 관한 블로그 자료들을 참고하면 대부분 단일 계정을 통해 배포를 진행한 경우가 많다. 해당 글들을 참고하여 도메인 설정을 진행하다보니, 처음에는 프론트/백엔드 계정 모두 DOMAIN.co.kr로 호스팅 영역을 생성하였다.
따라서, 각 호스팅 영역에 할당된 4개의 레코드를 모두 가비아의 네임서버로 등록하다보니 가바아에는 총 8개(프론트 4 + 백엔드 4)의 네임 서버를 등록하였다. 이는 이후 https 적용 시 도메인을 통한 certbot 인증 시, 도메인을 찾지 못하여 인증서 발급이 불가능한 에러로 이어졌다. 해당 에러에 대해서는 에러 로그도 불명확하기에 해결하는데 많은 시간이 걸렸다.
SOLVING. 백엔드 계정을 하위 도메인을 호스팅 영역으로 생성
해결 방법은 호스팅 영역을 정확하게 구분하여 생성하는 것이다.
프론트엔드 계정에서 호스팅 영역은 DOMAIN.co.kr, 백엔드에서는 api.DOMAIN.co.kr 로 나누어 생성한다.
호스팅 영역 생성 시 작성하는 도메인 이름은 하나의 컨테이너 이름이라고 볼 수 있다. 즉, 각 호스팅 영역의 구분자로 사용되기에, 두 계정에서 동일한 도메인으로 호스팅 영역 생성 시 각 컨테이너를 구분할 수 없게 되어 에러가 발생하였던 것이다.
위와 같은 이유로 인하여 백엔드 호스팅 영역은 api.DOMAIN.co.kr로 생성한다.
호스팅 영역 생성 후 백엔드 인스턴스를 A 레코드로 등록한다.
설정이 완료되고 나면 아래와 같이 도메인을 통하여 백엔드 서버에 접속 가능하다.
해당 결과에서
:8080
포트를 안 붙여도 접속이 가능한 이유는 80 → 8080 포트포워딩을 진행하였기 때문이다.따라서, 포트포워딩을 따로 진행해주지 않았다면 api.DOMAIN.co.kr:8080으로 접속하여야 한다.
현재는 포스팅 작성을 위하여, EC2 인바운드 규칙을 모든 IP에서 허용하도록 임시로 바꾼 상태이다.
실제 환경에서는 보다 안전한 사용을 위하여 프론트엔드, 개발자의 로컬 환경의 IP만 허용하도록 인바운드 규칙을 수정하여야 한다.
백엔드 서버에 연결이 되는 것을 확인하면, 프론트엔드 호스팅 영역에 백엔드 NS 레코드를 추가해주어야 한다. 상위 도메인 호스팅 영역에 하위 도메인 호스팅 영역의 네임서버를 등록해줌으로써 DOMAIN.co.kr 경로를 통한 도메인 검색 시 모든 하위 도메인에 대한 조회가 이루어지도록 한다.
따라서, 프론트엔드 호스팅 영역의 최종적인 형태는 다음과 같다.
가장 상단에 위치한 A 레코드는 www.DOMAIN.co.kr이 아닌 DOMAIN.co.kr로 접속시에도 프론트엔드 서버로 접속이 가능하도록 추가한 레코드이다. 이는 기타 블로그를 참고하다가 진행한 내용이기에 프론트엔드 서버 도메인을 하나만 사용할 것이라면 추가적으로 등록을 해주지 않아도 무방하다.
https 인증서 발급
인증서 발급은 Nginx와 letsencrypt(certbot)을 사용하여 진행한다. 따라서, 인스턴스에 Nginx 및 certbot 설치가 필요하다.
프론트엔드
Nginx
sudo apt install nginx -y
sudo systemctl start nginx
이후, 인스턴스의 Public IP 또는 도메인을 통하여 접속하여 Nginx의 실행 여부를 확인한다. 해당 접속은 리액트가 실행 중인 3000 포트가 아니다.
위와 같이 Nginx가 정상적으로 동작하는 것을 확인하였다면, certbot을 설치 단계로 넘어간다.
Certbot
여러 블로그들을 참고하여 Certbot을 설치하는 방법으로 3가지 정도를 확인하였다.
sudo apt install letsencrypt
sudo apt install certbot
sudo snap install certbot --classic
필자는 가장 마지막 명령어를 통하여 certbot을 설치하였다.
snap 및 certbot 설치에 몇 분 정도 소요된다.
설치가 완료되고 나면, Certbot을 통한 인증서 발급을 진행한다.
sudo certbot --nginx
certbot을 통한 인증서 발급 시 사용자의 이메일도 입력하여야 한다.
필자는 초기 프론트엔드 https를 적용하는데 트러블 슈팅 과정을 겪으며, 다양한 방법을 시도하였기에 해당 과정에서는 이메일을 입력하는 부분이 생략되었다. 이메일 입력 과정은 백엔드 인스턴스 https 적용 과정에서 참고하길 바란다.
인증서 발급이 완료되고 나면 certbot은 알아서 /etc/nginx/sites-available/default.conf 파일을 수정한다. 저장된 인증서 경로 등을 자동으로 파일에 기입하여 준다.
Nginx를 통한 프로젝트 배포 시, default.conf 파일 삭제 후 myapp.conf와 같은 커스텀 파일을 만들어 설정을 진행하는 경우에는 파일 수정이 제대로 진행이 되지 않을 수도 있다.
해당 경우에는 아래의 내용을 그대로 적용시키면 해결되는 문제이며, 인증서 발급 시 Nginx conf 파일을 꼭 확인하여야 한다.
# ============================ #
# 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
}
위 내용 중 #managed by Certbot
주석이 달린 코드들이 Certbot이 알아서 추가한 코드이다.
사이트 경로 및 인증서 연결에 관한 내용이다. https의 인증 방식에 대해서는 해당 포스팅에서 생략한다.
위 코드에서 불필요한 부분(…)은 제거하고 빌드된 리액트 파일을 Nginx로 실행시키도록 파일을 수정한다.
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;
}
root 경로와 도메인 등은 본인 설정에 맞도록 수정하여야 한다.
위 코드의 동작은 다음과 같다.
- https(443) 요청 → 리액트 프로젝트
- http(80) 요청 → https 요청으로 리다이렉트
모든 설정이 완료되었으면 Nginx를 재시작해주어야 한다.
sudo systemctl restart nginx
Nginx가 재시작되고 나면 브라우저로 접속하여 확인해보자.
![]() |
![]() |
위와 같이 정상적으로 https 설정이 완료된 것을 확인할 수 있다.
필자는 해당 과정만 4일 이상 소요되었기 때문에 해당 포스팅을 본 사람들이라면 이와 같은 고생을 겪지 않기를 바란다.
백엔드
백엔드 서버는 스프링 프로젝트가 8080 포트로 실행되고 있음을 가정한다.
Nginx
sudo apt install nginx -y
certbot
sudo snap install certbot --classic
sudo certbot --nginx
Trouble Shooting

PROBLEM. Certbot failed to authenticate some domains
인증에 실패하였다는 문구를 확인하면 401(unauthorized) 에러가 발생한 것을 확인할 수 있다.
앞서 언급하였듯이 필자는 사용 편의성을 위하여 80 → 8080 포트포워딩을 진행하였다. 따라서, 80포트로 인증서 발급에 대한 요청이 Spring Security에 의하여 401 에러를 응답한 것이다.
SOLVING. 포트포워딩 해제
포트포워딩을 해제하여 해당 에러를 해결한다.
sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
참고로 해당 인증 과정에서 이메일 인증(기입)을 진행하는 것을 확인할 수 있다.
에러 해결 후 다시 인증을 진행한다.
정상적으로 인증서 발급이 완료 시, Nginx의 default 파일에 인증서 관련 설정이 자동으로 추가된 것을 알 수 있다.
server {
listen 443 ssl;
server_name api.DOMAIN.co.kr;
location / {
proxy_pass http://localhost: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 에러 리턴
}
백엔드 서버는 데이터와 직결되어 있으므로 http 포트로 요청 시 404 에러를 리턴하도록 설정한다.
Nginx 재시작 후 정상 접속 확인을 진행한다.
백엔드 서버는 위와 같이 http 포트로 요청 시 Nginx에서 404 에러를 응답하는 것을 확인할 수 있다.
결론
예전에 개발 관련 글을 보던 중 Localhost를 벗어나기에 관한 글을 보고 공감을 한 적이 있다. 아무리 로컬에서 개발을 잘 하더라도 배포를 하지 못하면 그 서비스는 사용자에게 도달할 수 없다. 해커톤을 통해 배포를 진행해 본 경험이 있지만, 이번 경험을 통하여 스스로 배포 과정을 겪으며 문제들을 해결해나간 것은 큰 동기부여가 되었다.
이번 프로젝트에 사용한 AWS, 가비아, Certbot 외에도 다양한 배포, 도메인, 인증서 서비스들이 존재한다. 해당 과정의 흐름을 전체적으로 이해하였기에 기타 다른 서비스들을 이용해보며 경험을 확장해나가는 것이 새로운 목표이다.