olrlobt
[INFRA] Nginx를 사용하여 HTTPS 요청 처리하기 본문
2024.02.19 - [Infra] - [INFRA] EC2 서버 기본 설정과, SWAP메모리 할당하기
해당 포스팅은 윗글과 이어서 진행하는 글이다. 기본적인 서버 세팅은 위 포스팅을 참고하길 바란다.
Nginx
Nginx는 가볍고, 고성능의 HTTP 웹 서버, 리버스 프록시, 이메일 프록시(POP3/IMAP), TCP/UDP 프록시 서버로 사용된다. 비동기 이벤트 기반의 구조를 가지고 있어, 매우 높은 동시 연결을 처리할 수 있는 것이 특징이다.
처음에는 웹 서버로 개발되었지만, 현재는 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 기능을 제공하며, 웹의 성능과 보안을 향상하는 데 널리 사용된다.
나는 Nginx가 지원하는 SSL/TLS 프토토콜을 이용하여 도메인을 HTTPS로 구성하여 보안을 강화할 목적으로 사용했다.
SSL/TLS
SSL(Secure Sockets Layer)과 TLS(Transport Layer Security)는 인터넷상에서 데이터를 안전하게 전송하기 위해 설계된 암호화 프로토콜이다. SSL/TLS는 웹 브라우저와 서버 간, 또는 두 서버 간의 통신에서 데이터를 암호화하여 보안을 유지하는 데 사용된다.
SSL은 이 분야의 원조 프로토콜이고, TLS는 후속 버전으로 SSL 3.0에 기반하고 있지만, 보안과 효율성 등 개선 사항과 변경사항이 많아 별도의 이름으로 구분된다. 하지만, 기술적으로 연속성이 있고 많은 사람이 SSL이라는 용어에 익숙하기 때문에 SSL이라 통칭하기도 하며 SSL/TLS처럼 붙여서 부르기도 한다.
Nginx 설치
$ sudo apt update
$ sudo apt upgrade
먼저, apt를 이용하여 nginx를 설치하기 위해, apt 패키지를 업데이트해 준다.
$ sudo apt install nginx -y
그리고 앞서 진행하던 EC2 ubuntu 서버에 nginx를 설치한다.
잘 설치가 진행되었다면, 아래 명령어를 통해 상태를 확인할 수 있다.
$ sudo systemctl status nginx
SSL/TLS 설정
Nginx의 SSL/TLS 설정에는 인증서가 필요한데, Let's Encrypt를 사용하여 무료로 쉽게 발급받을 수 있다. Let's Encrypt는 자동화된 무료 개방형 인증 기관으로 비용이나 복잡한 절차 없이 누구나 SSL/TLS 인증서를 발급받을 수 있게 하는 서비스이다. 무료인 대신 만료기한이 90일로 주기적으로 재발급을 해야 하고, 실제 서비스를 운영한다면 보안등급이 더 높은 유료 인증서를 사용해야 한다.
Certbot은 Let's Encrypt의 파트너 소프트웨어로, SSL/TLS 인증서의 발급부터 설치, 갱신에 이르기까지 전 과정을 자동화한다. Certbot을 이용하면 사용자는 간단한 몇 가지 명령어로 HTTPS 설정을 쉽게 할 수 있으며, 90일 주기로 인증서를 재갱신하는 것도 자동으로 해 준다.
Let's Encrypt 설치
$ sudo apt-get install letsencrypt
Certbot 설치
$ sudo apt-get install certbot python3-certbot-nginx
Certbot - Nginx 연결
$ sudo certbot --nginx
해당 명령어를 실행하면 아래와 같이 몇 가지 설정을 해 주어야 한다.
# 이메일 입력
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel):
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 약관동의
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 이메일 수신동의
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
Account registered.
위 설정은 본인에 맞게 설정하면 된다.
HTTPS 적용 도메인 설정
여기서 Https를 적용하고 싶은 도메인을 고를 수 있고, 모든 도메인을 선택하려면 그냥 엔터를 누르면 된다.
만약 이미 발급된 인증서가 있다면, 재 발급받을 것인지 물어보는 창이 나온다. 재발급받고 싶다면 2를 눌러 재발급을 신청한다.
HTTP-HTTPS 리다이렉트 설정
모든 HTTP 트래픽을 HTTPS로 리다이렉트 하려면 2를, 2 기존 HTTP 설정을 유지하고 싶다면 1을 입력한다.
이런 메시지가 나오면 성공적으로 설정이 완료되었다.
Nginx 환경설정
SSL/TLS 인증서 발급을 마쳤다면, Nginx의 설정에서 SSL/TLS 인증서를 사용하도록 변경해 주어야 한다.
Nginx가 읽어 들이는 핵심 설정파일은 /etc/nginx/nginx.conf 파일이다.
이 파일은 아래와 같은 구성을 하고 있다.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
nginx.conf 파일의 주요 구성은 다음과 같다.
1. Global block
Nginx 서버 전체에 영향을 미치는 설정을 포함한다. 사용자의 수, 로그 파일의 위치, PID 파일의 경로 등을 설정할 수 있다.
2. Events block
연결 처리에 관련된 설정을 포함한다. 여기서는 동시 연결 처리 방식이나 연결 수의 제한 등을 설정할 수 있다.
3. HTTP block
HTTP와 관련된 설정을 포함하며, 여러 개의 서버 블록(Server blocks)을 포함할 수 있다. 이 서버 블록에 우리가 주로 변경해야 하는 설정들이 포함된다.
이 nginx.conf 파일을 보면 Http 블록 가장 아래에 다음과 같은 명령어가 포함되어 있다.
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
즉, /etc/nginx/conf.d/ 경로의. conf 확장자를 갖는 파일을 포함한다는 것이고, /etc/nginx/sites-enabled/ 의 모든 파일을 포함한다는 말이다.
따라서 우리는 nginx.conf 파일에서 직접 설정을 하지 않고,
sites-enabled, sites-available, conf.d 세 가지 폴더에 설정하는 방법을 사용한다.
여기서 sites-available 안의 파일은, sites-enabled 폴더에 심볼릭 링크로 연결되어 nginx 설정이 가능해진다.
sites-enabled
/etc/nginx/sites-enabled/default 파일로, 실제로 Nginx에 의해 읽히며 활성화된 사이트의 설정을 포함한다. 일반적으로 sites-available에 있는 설정 파일의 심볼릭 링크를 생성해 두고, 활성화하거나 비활성화하여 실제 설정 파일을 옮기지 않고도 관리를 쉽게 할 수 있게 해 준다.
여기서 심볼릭 링크는 윈도우에서 바로 가기와 비슷한 개념이며, 원본 파일이나 디렉터리로의 포인터 역할을 한다. 즉, /etc/nginx/sites-enabled/default의 심볼릭 링크가 sites-available/default로 설정되어 있으면, 어느 한 파일이 수정되면 같이 바뀌게 된다.
아래 명령어로 심볼릭 링크가 있는지 확인이 가능하다.
$ ls -l /etc/nginx/sites-enabled/
위와 같은 결과가 뜬다면, default라는 이름으로 해당 경로의 심볼릭 링크가 존재한다는 것을 의미한다.
만약 심볼릭 링크를 생성하거나 제거하려면 아래와 같은 명령어를 입력하면 된다.
# 심볼릭 링크 제거
$ sudo rm /etc/nginx/sites-enabled/default
# 심볼릭 링크 생성
$ sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
sites-enabled 폴더 안의 default 파일의 경우 sites-available 폴더 안의 설정파일을 심볼릭 링크로 연결해 주기만 하면 된다.
sites-available
/etc/nginx/sites-available/ 디렉터리 내부의 파일로, 가능한 모든 웹사이트의 서버 블록 설정 파일을 보관한다. 여기에는 활성화되지 않은 사이트의 설정도 포함할 수 있으며, sites-enabled의 심볼릭 링크로 활성화할 수 있다.
일반적으로 이 폴더 안에 여러 개의 설정 파일을 두고, 상황에 따라 sites-enabled 폴더로 심볼릭 링크를 활성화/비활성화하면서 서버의 설정을 전환한다.
/etc/nginx/sites-available/ 안의 파일은 일반적으로 아래와 같이 구성되며, 해당 예시에는 SSL 설정이 포함되어 있다.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri; # 모든 HTTP 요청을 HTTPS로 리다이렉트
}
server {
listen 443 ssl;
server_name example.com www.example.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # SSL 인증서 경로
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # SSL 키 경로
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
root /usr/share/nginx/html; # 해당 디렉터리를 경로로 잡음
index index.html;
}
}
이 Server 블록은 하나의 웹 사이트나 애플리케이션을 나타내며, server_name, listen, location 블록으로 구성된다. 또한 특정 도메인에 대한 요청을 처리하는 방식을 구성한다.
listen은 특정 포트와 IP 주소에 대한 리스닝을 설정할 수 있다.
server_name 에는 처리할 도메인 이름을 지정할 수 있다.
Location block은 특정 요청 URI에 대한 처리 방식을 정의한다. 정적 파일의 제공, 프록시 서버로의 요청 전달, 요청에 대한 특정 처리 등을 설정할 수 있다.
이제 하나하나 살펴보자.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri; # 모든 HTTP 요청을 HTTPS로 리다이렉트
}
해당 server 블록은 80 포트 http로 오는 모든 요청을 https로 리다이렉트 해주는 역할을 한다.
그리고, 다음 server 블록은 443 포트 https로 오는 모든 요청을 처리한다.
server {
listen 443 ssl;
server_name example.com www.example.com;
access_log /var/log/nginx/access.log; # 성공 로그 저장 경로
error_log /var/log/nginx/error.log; # 실패 로그 저장 경로
그리고 아래 부분이 ssl 인증서를 지정해 주는 부분이다.
이 부분 경로에는 fullchain.pem 경로와 privkey.pem 경로를 지정해 준다.
기본적으로 아래와 같은 경로이고, example.com을 본인의 도메인으로 대체해 주면 된다.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # SSL 인증서 경로
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # SSL 키 경로
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_protocols TLSv1.2 TLSv1.3; # 서버에서 지원할 TLS 프로토콜의 버전
ssl_session_cache shared:SSL:10m; # 10MB의 공유 메모리를 SSL 세션 캐시로 사용하겠다는 의미
ssl_session_timeout 10m; # 세션 유효기간 10분 설정
그 후, 아래 부분은 정적 파일을 로딩해 주는 부분이다.
/ 로 들어오는 모든 URI는 해당 로케이션 블록을 통해 정적 파일이 서빙된다.
location / {
root /usr/share/nginx/html; # 해당 디렉터리에
index index.html; # index.html 파일을 서빙한다
}
이 Location 블록의 경우에는 프록시 서버로의 요청을 전달하는 역할도 할 수 있는데,
나의 경우에는 아래와 같이 설정하여 / 루트 경로로 들어오는 모든 URL을 도커에서 실행 중인 3000 포트로 서빙해 주는 식으로 사용하였다.
location / {
proxy_pass https://localhost:3000; # 특정 요청을 전달하는 역할 / 이 경우 도커로
proxy_set_header Host $host; # 원래 요청의 호스트 이름을 대상 서버에 전달
proxy_set_header X-Real-IP $remote_addr; # 클라이언트의 실제 IP 주소를 대상 서버에 전달
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 요청이 전달된 클라이언트의 IP 주소 목록을 대상 서버에 전달
proxy_set_header X-Forwarded-Proto $scheme; # 원래 요청에서 사용된 프로토콜(예: http, https)을 대상 서버에 전달
}
conf.d
/etc/nginx/conf.d/~~. conf 파일로, Nginx는 구동 시 이 디렉터리 내의. conf 확장자를 가진 모든 파일을 자동으로 읽어 들인다. 이 디렉터리에는 개별 설정 등을 심볼릭 링크를 관리할 필요 없이 설정을 추가하거나 제거하기 편리함을 제공한다.
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
예를 들어, 위와 같이 로그 파일을 저장하는 설정을 할 수 있으며, Http 블록 안에 직접적으로 들어가는 코드는 블록으로 구성할 필요가 없다.
Nginx 설정 파일 검증
$ sudo nginx -t
설정을 마쳤으면 위 코드를 입력하여 정상적으로 설정이 되었는지 확인한다.
위와 같이 OK 표시가 떴다면 정상적으로 설정이 된 것이고, 오류가 있다면 아래와 같이 오류가 난 부분을 알려준다.
Nginx 시작
$ sudo systemctl start nginx
Nginx 재시작
$ sudo systemctl reload nginx
설정 파일을 수정한 이후엔, 수정 사항이 적용될 수 있도록 Nginx를 재시작해준다.
이제 도메인으로 접속을 하게 되면, 위 화면과 같이 Nginx의 기본적인 웰컴 페이지가 보인다.
이 Nginx의 설정에서 location 블록을 적절히 수정하여 요청을 받을 때 React의 정적 파일을 서빙해 주어 페이지를 렌더링 하거나, 요청을 다른 서버로 넘겨주어 간단하게 API 요청을 할 수 있다.
'Infra' 카테고리의 다른 글
[INFRA] Jenkins 설치하기 (0) | 2024.03.30 |
---|---|
[INFRA] AWS EC2 프리티어 인스턴스 생성하기 (2) | 2024.03.25 |
[INFRA] Docker에서 Nginx 컨테이너 실행과 https 설정하기 (1) | 2024.03.20 |
[INFRA] Docker와 Dockerfile, Docker-compose 구성하기 (1) | 2024.02.21 |
[INFRA] EC2 서버 기본 설정과, SWAP메모리 할당하기 (1) | 2024.02.19 |