개요
Nginx는 정적 파일(HTML, CSS, JavaScript, 이미지 등)을 서빙하는데 효과적인 오픈소스이다.
Nginx는 또한 리버스 프록시 서버로 사용할 수 있다. DNS로 들어온 클라이언트의 요청을 다른 서버로 전달하고 다시 클라이언트에게 전달하는 역할을 한다.
또 SSL/TLS 프로토콜을 지원하여 HTTP/HTTPS 들어오는 접근을 인증서로 안전하게 처리할 수 있다.
이번 4-2 캡스톤 디자인 프로젝트에선 Nginx 웹 서버를 사용하여 React 앱을 호스팅할 것이며 동시에 Certbot을 사용하여 인증서를 발급받고 Https 프로토콜 연결을 제공할 것이다.
Certbot이란
Certbot을 사용하면 명령어 한 줄로 SSL 인증서를 발급받을 수 있는데. Let's Encrypt를 사용해서 그 과정을 구현한다.
Let's Encrypt는 ACME(Automatic Certificate Management Environment) 프로토콜을 사용하여 인증서를 발급하는데, Certbot은 이 프로토콜을 구현한 클라이언트이다.
Let's Encrypt 인증서는 90일 동안 유효한데, Certbot은 인증서 갱신을 자동화하여 만료 전에 인증서를 갱신할 수 있다. 이로 인해 서버 관리자는 인증서 만료를 걱정하지 않고 웹사이트를 운영할 수 있다.
구현
Nginx와 Certbot을 Docker-compose를 이용하여 동시에 배포한다.
HTTP와 HTTPS를 지원하기 위해 80번 PORT와 443 PORT를 오픈하며 volumes를 마운트해 파일들을 certbot 컨테이너가 만드는 인증서를 nginx 내부와 연동시킨다.
예를 들어, "./data/nginx:/etc/nginx/conf.d"로 볼륨이 설정되면, "./data/nginx" 폴더 안에 파일들이 nginx 컨테이너 내부의 "/etc/nginx/conf.d"로 복사된다.
먼저 다음과 같이 nginx 설정에 사용되는 conf 파일을 작성한다.
server {
listen 80;
server_name jeus.site www.jeus.site;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 http://$host$request_uri; # 301 Redirect to HTTP
}
}
# SSL 설정은 주석 처리 또는 삭제
# server {
# listen 443 ssl;
# server_name jeus.site www.jeus.site;
#
# ssl_certificate /etc/letsencrypt/live/jeus.site/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/jeus.site/privkey.pem;
#
# location / {
# proxy_pass http://jeus.site:8000;
# 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;
# }
# }
그 후 docker-compose.yaml를 작성한 후 docker compose up -d 명령어를 실행한다
Https에 해당하는 443 port를 주석처리해준 이유는 아직 certbot이 인증서를 생성하지 못했기 때문이다. 인증서 없이 443 설정을 하려고 하면 컨테이너가 비정상 종료된다.
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
depends_on:
- certbot
certbot:
image: certbot/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
그 후 curl을 통해 확인한다.
301으로 rebound가 오는 것을 확인 가능하다. 잘 가지는 것을 확인 가능하다.
그리고 다음 명령어를 실행해 인증서를 생성한다.
docker-compose run --rm certbot certonly --webroot --webroot-path=/var/www/certbot -d jeus.site -d www.jeus.site
인증서가 생성된 것을 확인한 뒤 docker compose down를 하고 다시 docker compose up -d를 하여 background로 certbot과 nginx를 실행한다.
실행하기 전에 인증서를 생성했으므로 443 port 설정의 주석을 해제한다.
server {
listen 80;
server_name jeus.site www.jeus.site;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name jeus.site www.jeus.site;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/jeus.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jeus.site/privkey.pem;
location / {
proxy_pass http://jeus.site:8000;
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_pass에 react app의 port를 지정해서 서빙해야 하지만 현재 아직 react 개발이 끝나지 않았기에 nginx 서버를 간단하게 8000번으로 띄워 테스트를 진행해보았다.
2개의 nginx server가 띄워져있음을 확인 가능하다. 하나는 react 대용이고 하나는 우리가 지금까지 구현한 웹 서버이다.
최종 결과이다. curl로도 웹 브라우저 접속으로도 정상 작동하는 것을 확인 가능하다. 또한 인증서도 정상 연결되었다.