olrlobt

[INFRA] Nginx를 사용하여 HTTPS 요청 처리하기 본문

Infra

[INFRA] Nginx를 사용하여 HTTPS 요청 처리하기

olrlobt 2024. 2. 20. 10:30

2024.02.19 - [Infra] - [INFRA] EC2 서버 기본 설정과, SWAP메모리 할당하기

 

[INFRA] EC2 서버 기본 설정과, SWAP메모리 할당하기

이번 프로젝트에서 인프라를 담당하면서 위와 같은 구조로 시스템 아키텍처를 구성해 보았다. 위와 같이 인프라를 구성하면서, 진행했던 과정을 기록하고 문제가 됐던 부분을 다시 정리해 보려

olrlobt.tistory.com

 

해당 포스팅은 윗글과 이어서 진행하는 글이다. 기본적인 서버 세팅은 위 포스팅을 참고하길 바란다.

 


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 요청을 할 수 있다.

 

 

 

 

 

Comments