들어가며
인터넷의 다양한 웹사이트를 살펴보면 도메인을 입력하면 웹사이트에 연결된다. 이러한 당연한 기능을 막상 구현하려고 하면 생각보다 다양한 부분에서 의문이 생기게 된다. 예를 들어 node 프로젝트를 클라우드 서버(AWS EC2, GCP VM 등)에서 3000번 포트로 실행시키면 IP와 PORT를 통해서 접근해야 한다 ( http://127.0.0.1:3000와 같이 ) 이렇게 기본적인 서버 실행만 시킨다면 AWS 및 GCP 등 클라우드 서비스나 온프레미즈를 통해 웹 프레임워크를 실행시키면 깔끔한 도메인을 갖지 못하는 것을 알 수 있다. ( 뒤에 포트를 붙이거나, http로 연결된다거나 등 )
이러한 것들을 해결해 줄 수 있는 것이 Nginx과 같은 웹 서버이다. nginx(엔진엑스)는 웹 서버로 HTTP와 리버스 프록시 등의 기능을 가지고 있다. Java 계열의 프레임워크는 주로 Apache의 Tomcat이라는 웹 서버를 사용하고, PHP는 PHP-FPM(FastCGI Process Manager)를 통해서 웹 서버를 구현한다. 그 외에 프레임워크에서의 https 연결이나 리버스 프록시를 도와주는 것이 바로 이 nginx라는 웹서버이다.
이번 포스팅에서는 Nginx 세팅을 통해서 https 연결하는 방법과 포트 포워딩하는 방법에 대해서 다룬다.
본론
클라이언트
먼저 클라이언트에 대해서 알아보면 클라이언트는 다음과 같은 웹 브라우저를 의미한다. 웹 클라이언트가 웹 서버에게 요청을 보내고 응답을 받는 구조로 웹사이트는 사용자에게 전달된다.
WAS ( Web Application Server )
WAS는 Web Server + Application Server를 합친 것이다. 가장 대표적으로는 자바 계열 프레임워크인 Spring이 있다. Spring은 Apache Tomcat이라고 하는 WS(Web Server)를 사용한다. 그리고 톰캣의 뒷단에는 Spring Container라고 하는 Application Server가 있고 복잡한 로직들은 Application Server에서 실행된다.
위 그림은 Spring 서버에 요청을 보내면 어떤 식으로 요청이 서버에 전달되는지 간단하게 나타낸 구조도다. 여기서 중요한 포인트는 왼쪽의 Tomcat의 Web Server는 HTML, CSS, JS와 같은 정적인 리소스들을 제공하고, 오른쪽의 Spring Container라는 Application Server는 Controller, Service, Repository로 나누어져 복잡한 비즈니스 로직을 처리하는 작업을 한다.
이렇게 Web Server와 Application Server가 합쳐져 있는 구조를 WAS라고 부른다. 우리가 일반적으로 백엔드 개발을 접하게 되면 오른쪽 부분의 Application Server를 개발하게 될 것이다. Spring과 같은 프레임워크를 쓴다면 기본적으로 Apache Tomcat을 쓰도록 설정되어 있기 때문에 애플리케이션에서 tomcat.xml 파일의 수정을 통해서 웹 서버를 설정한다.
하지만 이러한 웹 서버를 내장하고 있지 않은 몇몇 개의 프레임워크에서는 nginx의 설정을 통해서 HTTP 요청을 매끄럽게 받아낼 수 있다
Application Server
웹 서버보다 친숙한 Application Server에 대해서 알아보자. 애플리케이션 서버는 데이터베이스에 액세스하여 정보를 조회/생성/삭제하거나, 비즈니스 로직을 처리하는 등 웹 서버보다 복잡한 기능을 처리한다. 데이터베이스 외에도 메시지 큐, 레디스 등의 서드파티 시스템을 덧붙일 수 있다. 우리가 일반적으로 생각하는 백엔드 개발이다. 이러한 복잡한 로직을 처리하는 어플리케이션 서버를 Web Client(크롬, 파이어폭스)를 통해서 접근할 수 있게 하기 위해서는 Web Server의 도움이 필요하다.
우리가 일반적으로 백엔드 프레임워크로 개발하는 것은 이러한 애플리케이션 서버이다. Python의 Flask 및 Django, Node의 Nestjs 및 Express 등이다. 이러한 프레임워크 중 웹 서버 설정을 내장하고 있지 않거나, 웹 서버를 내장하더라도 다양한 이유로 추가적인 프록시를 사용할 일이 있다면 nginx를 사용하게 된다.
Web Server
웹 서버는 웹 브라우저와 같은 클라이언트의 HTTP 요청에 따라 HTML, CSS , JS 및 기타 리소스 파일을 정적으로 제공하는 컴퓨터 프로그램을 의미한다.
어플리케이션 서버와 웹 서버가 함께 동작하는 원리는 다음과 같다.
- 브라우저는 URL을 사용하여 DNS를 통해 서버의 IP 주소를 찾음
- 브라우저는 서버에 대해서 HTTP 요청을 보냄
- 웹 서버는 요청을 어플리케이션 서버로 전송
- 어플리케이션 서버는 비즈니스 로직을 처리하고 결과를 웹 서버에 반환
- 웹 서버는 브라우저에 응답을 반환
- 브라우저가 정보를 표시
이러한 과정을 거친다. 우리가 이번에 다룰 것은 3번 내용인 웹 서버인 nginx를 통해서 어플리케이션 서버로 전송하는 방법에 대해서 다룰 것이다. Let's Encrypt를 통해서 https 적용 및 포트포워딩을 적용할 예정이다.
이러한 nginx의 역할은 이번 섹션의 첫 번째에 쓰여있는 HTML, CSS를 제공하는 것은 아니고, 리버스 프록시 서버로 쓰는 것이다. Application Server에 보내지는 HTTP 요청을 낚아 프록시 서버로서 https 및 포트 포워딩의 기능을 제공하는 웹 서버로 쓰는 것이다.
HTTPS?
HTTPS는 웹 브라우저와 웹 사이트 간에 데이터를 전송하는 데 사용되는 프로토콜인 HTTP에 보안을 적용한 것이다. HTTPS는 암호화 프로토콜을 사용하는데, 다음과 같이 SSL/TLS 레이어를 거쳐서 암호화된다. HTTP 요청은 쉽게 엿볼 수 있는 구조를 가지고 있기 때문에 다음과 같은 레이어를 통해서 안전한 HTTP 프로토콜을 보장한다. 이러한 레이어를 추가해야지만 https://로 시작하는 도메인을 가질 수 있다.
nginx를 통해 Https를 적용하는 과정
이번 포스팅에서는 Nginx 및 Certbot을 사용할 예정이다. Certbot은 Let's Encrypt라는 무료로 TLS 인증서를 발급해 주는 비영리기관의 인증서를 사용하는 툴이다. 만료 기한이 90일로 정해져 있기 때문에 주기적으로 재발급해야 한다. 우분투를 기준으로 설명한다.
nginx 설치
# apt setting
sudo apt update
sudo apt upgrade
# install nginx
sudo apt install nginx
# run nginx
sudo service start nginx
위 명령어를 통해 nginx를 실행시킬 수 있다. 다음으로 Certbot를 설치하자.
Certbot 설치
# apt-get setting
sudo apt-get update
sudo apt-get upgrade
# install Certbot
sudo apt-get install python3-certbot-nginx
# certificate
sudo certbot certonly --nginx -d EXAMPLE.COM
sudo ls /etc/letsencrypt/live/EXAMPLE.COM
apt-get 패키지 매니저를 통해서 certbot를 다운로드하고 인증서를 발급받는다. 인증서의 경로는 /etc/letsencrypt/live/EXAMPLE.COM/ 이 된다. 해당 디렉터리에 .pem 확장자로 된 파일이 네 개 있는 것을 확인할 수 있다.
Nginx 설정
이제 본격적으로 Nginx를 설정한다.
vi /etc/nginx/nginx.conf
아래처럼 설정 파일을 include 할 수 있게 없다면 추가해 준다.
...
http {
...
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
...
그 후 리눅스의 심볼릭 링크를 사용해 준 후 설정 파일을 본격적으로 생성해 준다. 아래의 conf 파일 수정 시 본인의 도메인과 포트에 맞는 설정으로 바꿔 입력해 준다.
# 심볼릭 링크
sudo ln -s /etc/nginx/sites-available/test.conf /etc/nginx/sites-enabled
# 설정 파일 생성
sudo vi /etc/nginx/sites-available/test.conf
# 80번 포트로 요청이 들어오는 경우 (http)
server {
listen 80;
server_name EXAMPLE.COM; # 도메인 수정
return 301 https://EXAMPLE.COM$request_uri; # 도메인 수정
}
# 443번 포트로 요청이 들어오는 경우 (https)
server {
listen 443 ssl http2;
server_name EXAMPLE.COM; # 도메인 수정
# ssl 인증서 적용하기
ssl_certificate /etc/letsencrypt/live/EXAMPLE.COM/fullchain.pem; # 도메인 수정
ssl_certificate_key /etc/letsencrypt/live/EXAMPLE.COM/privkey.pem; # 도메인 수정
location / {
proxy_pass http://localhost:3000; # 포트 수정 ( 어플리케이션 서버 실행 포트 )
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 기타
server {
if ($host = EXAMPLE.COM) { # 도메인 수정
return 301 https://$host$request_uri;
}
listen 80;
server_name EXAMPLE.COM; # 도메인 수정
return 404;
}
이렇게 설정이 끝났다면 nginx를 재시작해준다.
# nignx 설정 파일 문법 확인
sudo nginx -t
# nginx 재시작
sudo service nginx restart
# nginx 서버 상태 확인
systemctl status nginx.service
정상적으로 nginx가 실행되고 있다면 초록색으로 active 상태를 확인할 수 있고, 아니라면 빨간색으로 표시된다. nginx 설정 파일을 읽어보면 알 수 있겠지만 nginx의 다양한 설정을 통해서 많은 기능을 사용할 수 있다.
마치며
nginx에서 환경 변수를 사용하는 경우
nginx를 설정하며 환경 변수를 설정할 수 있는지 알아봤는데, nginx에서는 환경 변수를 지원하지 않는다! 하지만 docker에서나 linux 등 외부에서 환경변수를 설정해서 받아올 수 있는 방법들이 존재하는데 참고로 달아 두겠다.
- linuxhint : https://linuxhint.com/nginx-use-environment-variables/
- stackoverflow : https://stackoverflow.com/questions/21866477/nginx-use-environment-variables
그리고 인증서는 참고로 90일 주기로 갱신시켜줘야 하기 때문에 certbot를 사용한 인증서 관련된 명령어를 남기면 다음과 같다.
# 인증서 확인
$ sudo certbot certificates
# 인증서 자동 갱신
$ sudo certbot --dry-run
# 인증서 삭제
$ sudo certbot delete --cert-name EXAMPLE.COM
해당 과정을 통해서 주기적으로 https 연결을 위해 인증서를 재발급해야 한다.
참고
- coastby : SSL 적용하기
- AWS : 웹 서버와 애플리케이션 서버의 차이점은 무엇인가요?
- 고운소리의 블로그 : Spring - 요청처리 내부구조
'CS > network' 카테고리의 다른 글
ssh에 대해서 (0) | 2024.07.07 |
---|---|
RESTful API 원칙에 대해서 (1) | 2024.04.16 |
microsoft remote desktop을 통한 window 원격 접속 (1) | 2023.09.01 |