Nginx로 SSL 인증서 발급 및 https 적용하기 (+ 재발급)

반응형

 

클라이언트로와 서버 요청 응답을 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와 차이점)

 

Nginx란 무엇이고 왜 사용하는가? (Apache와 차이점)

Nginx의 등장 이전최초의 웹 서버는 1995년 UNIX 기반으로 만들어진 NCSA Httpd 였다.하지만 처음은 다 그렇듯이 NCSA Httpd에는 버그가 상당히 많아서 개발자들이 사용할 때 많은 불편함을 겪었다고 한다

hstory0208.tistory.com


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

 

Certbot Instructions

Tagline

certbot.eff.org

 

아래 명령어들은 다음과 같은 기준으로 나온 명령어들이다.

 

// 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 설정 적용하기" 목차로 이동해 순서대로 적용

위 목차로 다시 이동해서 순서대로 적용해주면 된다.