클라이언트로와 서버 요청 응답을 http로 통신하고 있는 상황에서
모든 요청 응답에 암호화를 적용하기 위해 API 서버에 https를 적용하려 한다.
http와 https의 차이가 궁금하다면 아래 포스팅을 참고하자.
2022.09.22 - [◼ CS 기초 지식/[네트워크]] - HTTP와 HTTPS의 개념 및 차이점에 대해 알아보자.
서버에 https를 적용하기 위한 방법들
여러 서칭 결과 서버에 https를 적용하는 방법은 아래와 같은 방법이 있었다.
AWS(유료) -> Route53 + ACM + ALB(Application Load Balancer)
1. ACM으로 특정 도메인에 대한 SSL 인증서 발급
2. Route53에서 DNS 레코드 생성 후 도메인 소유권 확인 및 인증서 발급 대기
3. ALB를 적용해 ACM에서 발급받은 SSL 인증서로 HTTPS 리스너 설정 및 요청을 받을 타겟 그룹 설정
4. Route53에서 도메인 이름으로 요청 시 모든 요청을 ALB로 가도록 호스팅 영역 설정
Nginx(무료)
- Certbot을 사용해 SSL 인증서를 무료로 발급하고 갱신 가능
- 리버스 프록시 적용 가능
위 비교를 보면 Nginx로 설정하는 것이 훨씬 간단하게 https 적용이 가능해보였고,
무엇보다 무료라는 점, 그리고 현재는 로드 밸런싱을 고려하지 않고 있다는 점에서 Nginx로 https를 적용하게 되었다.
Nginx에 대해 궁금하다면 아래 포스팅을 참고하자.
2023.06.24 - [◼ 오픈소스] - Nginx란 무엇이고 왜 사용하는가? (Apache와 차이점)
Certbot ?
Certbot 공식 홈페이지에서는 아래와 같이 설명하고 있다.
"Certbot은 수동으로 관리되는 웹사이트에서 Let's Encrypt 인증서를 자동으로 사용하여 HTTPS를 사용하도록 하는 무료 오픈 소스 소프트웨어 도구입니다."
즉, 무료로 SSL 인증서를 발급받고 https를 적용할 수 있다.
또한 SSL 인증서를 자동으로 갱신하도록 설정할 수도 있고, Nginx 내에 https 설정을 자동으로 적용해준다.
Nginx로 https 적용하기
우리는 Certbot으로 SSL 인증서를 받고 https를 적용할 것이다.
설명하기에 앞서 우리의 서비스에서 Nginx를 적용해 클라이언트 요청이 서버까지 가는 흐름을 보면 다음과 같다.
이제 위 흐름에 맞춰 Nginx에 https 적용을 하고 리버스 프록시까지 적용을 해볼 것이다.
1. Nginx 설치
EC2에 접근해 아래 명령어로 EC2 내에 Nginx를 설치해주자.
참고로 현재 우리 EC2는 ubuntu 24.04 LTS AMI를 사용하고 있다.
// nginx 설치
sudo apt install nginx
// nginx 실행
sudo service nginx start
2. Certbot 다운로드
Certbot 공식문서에서 웹 서버와 운영체제 별로 설치 명령어를 제공해준다.
https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal
아래 명령어들은 다음과 같은 기준으로 나온 명령어들이다.
// snap 이용하여 certbot을 설치하기 때문에 snap 설치 및 최신화를 위한 core 설치
sudo apt install snapd
sudo snap install core
// certbot 설치
sudo snap install --classic certbot
// certbot 명령을 로컬에서 실행할 수 있도록 ln -s 명령으로 snap의 certbot 파일을 로컬의 cerbot과 심볼링링크(동기화)
ln -s /snap/bin/certbot /usr/bin/certbot
3. Certbot으로 Nginx 설정 적용하기
인증서를 받으면 Certbot이 인증서를 제공하도록 Nginx 구성을 자동으로 편집하도록 아래 명령어를 입력한다.
sudo certbot --nginx
위 명령어를 입력하면 여러 질문들이 등장한다.
전부 y를 입력하고 넘어가도 문제는 없지만, domain을 입력하라는 질문에선 SSL 인증서를 발급받을 DNS를 입력해야한다.
아래 문구가 나오면 정상적으로 입력한 DNS에 SSL 인증서 발급민 Nginx 구성이 자동으로 편집된 것이다.
위 문구를 통해서 아래와 같은 정보들을 얻을 수 있다.
~ on 2024-11-18 # 11월 18일 까지 인증서가 유효하다. (나중에 자동갱신 가능)
https://teamody.ddns.net # https가 설정된 DNS
/etc/letsencrypt/live//teamody.ddns.net/fullchain.pem # 공개키 경로
/etc/letsencrypt/live/teamody.ddns.net/privkey.pem # 비밀키 경로
그리고 중요한 건 아래 문구이다.
"Successfully deployed certificate for teamody.ddns.net to /etc/nginx/sites-enabled/default"
입력한 DNS로 SSL 인증서 배포를 완료했고 /etc/nginx/sties-enabled/ 경로에 있는 default 파일에 관련 설정을 추가했다는 것이다.
4. Certbot 자동 갱신 적용
Let’s Encrypt 인증서는 90일 후에 만료된다.
우리는 이를 일정시간마다 갱신 여부를 확인하고 갱신되도록 crontab 파일에 작업을 추가할 것이다.
sudo crontab -e
파일 맨 하단에 아래 명령을 추가하고 저장하자.
아래 명령어는 매일 아침 12시마다 인증서가 30이내에 만료되는지 확인하고 만료되면 갱신한다.
0 12 * * * /usr/bin/certbot renew --quiet
5. /etc/nginx/sites-enabled/default 파일 수정
이제 해당 경로로 들어가 우리가 필요한 설정만 건드려볼 예정이다.
변경한 부분을 쉽게 파악할 수 있도록 주석을 달아놨다.
수정 사항 O : 443을 listen하는 설정
서버가 실행되는 8080 포트로 포워딩하기위해
proxy_pass로 리버스 프록시를 적용했다.
localhost의 주소로 적은 이유는 ec2내에 실행되고 있기 때문이다.
수정 사항 O : 80을 listen하는 설정
80 요청을 받으면 443으로 리다이렉션 시켜주는 설정인데 기존에는 응답코드가 301로 되있다.
하지만 301의 경우 리다이렉션을 적용할 때 처음 요청한 HTTP 메서드에서 GET 요청으로 변경되는 문제가 있었고, 본문 내용이 삭제되는 문제가 있었다.
(POST 요청을 해도 GET 요청으로 바뀜..)
그래서 308로 응답코드를 수정했고 308은 리다이렉션을 적용할 때 처음 요청한 HTTP 메서드로 요청을 보내고 본문 내용도 유지한다.
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
# 수정 사항 X
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
# 수정 사항 O : 443을 listen하는 설정
server {
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name teamody.ddns.net; # managed by Certbot
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
proxy_pass http://127.0.0.1:8080; # 8080 포트로 리버스 프록시 추가
#try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/teamody.ddns.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/teamody.ddns.net/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
}
# 수정 사항 O : 80을 listen하는 설정
server {
# 301 -> 308로 바꿈 (301일 경우 POST 요청도 GET 요청으로 바뀌는 문제가 있음.)
if ($host = teamody.ddns.net) {
return 308 https://$host$request_uri;
} # managed by Certbot
listen 80 ;
listen [::]:80 ;
server_name teamody.ddns.net;
return 404; # managed by Certbot
}
6. Nginx 설정 테스트 및 재시작
아래 명령어를 입력해 nginx 설정 파일에 문제가 없는제 확인한다.
sudo nginx -t
아래 문구가 나왔다면 설정 파일에는 문제가 없다.
이제 다음 명령어로 nginx를 재시작하자
sudo service nginx restart
nginx가 실행되지 않는다면 ?
아래 명령어들로 에러 문제를 확인하고 해결할 수 있다.
// nginx 상태 확인
sudo service nginx status;
// 에러 로그 확인
sudo tail -n 10 /var/log/nginx/error.log
이대로 잘 따라왔다면 성공적으로 https가 적용된 것을 볼 수 있다.
Certbot 인증서 재발급 받기
공짜로 발급 받았던 도메인이 만료일이 한참 남았음에도 갑자기 만료가되어 서버 접속이 안되는 문제가 발생했었다.
공짜를 너무 좋아했던 것일까; 가비아에서 도메인을 구입해 이 도메인으로 새로 인증서 발급을 하려한다.
기존 인증서 제거
// 인증서 목록 확인
sudo certbot certificates
// 기존 인증서 삭제 (example.com : 삭제하려는 실제 도메인 이름)
sudo certbot delete --cert-name example.com
// 관련 설정 제거
sudo rm -rf /etc/letsencrypt/live/example.com
sudo rm -rf /etc/letsencrypt/archive/example.com
sudo rm -f /etc/letsencrypt/renewal/example.com.conf
Cerbot으로 작성된 /etc/nginx/sites-enabled/default 파일의 설정 제거
# managed by Certbot 으로 추가된 server {} 블록들을 제거해주자.
(sudo certbot --nginx 다시 재발급 받으면 해당 블록들을 추가해주기 때문에 충돌 방지로 지워줘야 한다.)
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
# fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}
"Certbot으로 Nginx 설정 적용하기" 목차로 이동해 순서대로 적용
위 목차로 다시 이동해서 순서대로 적용해주면 된다.
'◼ DevOps' 카테고리의 다른 글
[프록시 점프] Bastion Host를 거쳐 private 서버로 한 번에 접근하기 (1) | 2024.09.24 |
---|---|
[Docker] 도커 옵션 쉽게 알아보고 제대로 활용하기 (2) | 2024.08.31 |
[Spring] ELK + Kafka를 활용해 실시간 로그 수집하기 (0) | 2023.10.06 |
[무중단 배포] Nginx를 사용해 EC2에 무중단 배포 적용하기 (0) | 2023.09.28 |
[Spring] kafka와 SSE(Server Send Event)를 사용한 실시간 알림 전송 방법 (4) | 2023.09.20 |