Rhythm Up - 역대글
▶ Nginx HTTPS
기존 배포 방식에서는 HTTP 프로토콜을 사용해 데이터를 전송하고 있었다. 그러나 HTTP는 데이터가 암호화되지 않은 상태에로 전송되기 때문에, 민감한 정보가 제3자에 의해 가로채이거나 악용될 위험이 있다. 이러한 보안 문제를 해결하기 위해 HTTPS로 전환이 필요하다.
HTTPS는 SSL/TLS 인증서를 기반으로 동작하며, 인증서를 통해 서버와 클라이언트 간의 신뢰를 형성한다. HTTPS를 사용하면 데이터가 암호화된 상태로 전송되기 때문에, 제3자가 데이터를 가로채더라도 이를 읽거나 해독할 수 없다. 이를 통해 사용자 정보와 서버 간 통신을 안전하게 보호할 수 있다.
보안 이점 외에도 HTTPS는 검색 엔진 최적화(SEO)에서도 긍정적인 영향을 미친다. 구글을 포함한 주요 검색 엔진은 HTTP 기반 웹사이트를 신뢰성이 낮다고 평가하며, 순위를 HTTPS 기반 웹사이트보다 낮게 지정하는 경향이 있다. 따라서 HTTPS로 전환하지 않으면 검색 결과에서 상위 노출이 어려울 수 있다.
또한, HTTPS는 웹사이트의 기능과 확장성에도 중요한 역할을 한다. 예를 들어, PWA 기능은 HTTPS를 요구하며, API를 활용할 때도 HTTP 환경에서는 CORS 제한으로 특정 기능이 정상적으로 작동하지 않을 수 있다.
이러한 이유로, 기존 HTTP 환경을 HTTPS로 전환하는 작업을 진행하려고 한다.
HTTPS 인증서
HTTPS 전환을 위해 Let's Encrypt를 활용할 계획이다. Let's Encrypt는 무료로 TLS/SSL 인증서를 제공하는 인증 기관(CA)으로, 안전하고 효율적으로 HTTPS 환경을 구성할 수 있는 도구이다.
설정 작업은 다음 3단계로 구성된다 :
- HTTPS 인증서 발급
- HTTPS 배포
- HTTPS 인증서 갱신
이 과정에서 중복되는 설정을 방지하고 재사용성을 높이기 위해 공통 설정 파일을 작성하여 활용한다.
공통 설정
아래는 Nginx 컨테이너를 설정하는 docker-compose.common.yml의 공통 설정이다.
// docker-compose.common.yml
version: "3.8"
services:
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
networks:
- shared_network
networks:
shared_network:
external: true
- restart :
- unldess-stopped : 서버를 수동으로 중단한 경우를 제외하고 자동으로 다시 시작되도록 설정한다. 이로써 예기치 않게 종료되더라도 재시작이 보장된다.
- ports :
- 80:80 : HTTP 통신을 위해 80번 포트를 열어준다.
- 443:443 : HTTPS 통신을 위해 443번 포트를 열어준다.
- 두 포트를 모두 활성화하여 추후 전부 HTTPS로 전환해 트래픽을 처리할 수 있도록 설정한다.
- volumes :
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf :
Nginx 설정 파일을 도커 컨테이너 내부로 복사하여 HTTPS 인증 및 배포에 필요한 Nginx 설정을 반영한다. - ./certbot/conf:/etc/letsencrypt, ./certbot/www:/var/www/certbot
Certbot에 의해 자동 생성되는 파일 및 인증서를 저장할 경로를 정의한다. 별도의 디렉토리를 생성할 필요는 없으며, 설정된 경로에 인증서와 관련 파일이 저장된다.
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf :
HTTPS 인증
docker compose 설정
HTTPS 인증서를 발급하기 위해 Certbot을 활용하여 인증 작업을 설정한다. 이를 위해 docker-compose.certbot.yml 파일을 작성하고 필요한 설정을 구성한다.
// docker-compose.certbot.yml
version: "3.8"
services:
nginx:
volumes:
- ./nginx/nginx.certbot.conf:/etc/nginx/nginx.conf
certbot-renew:
image: certbot/certbot
container_name: certbot-renew
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --force-renewal --email sjw7324@gmail.com -d mafia-game.seojaewan.com --agree-tos
- nginx 서비스
- volums :
- ./nginx/nginx.certbot.conf:/etc/nginx/nginx.conf :
공통 설정에서 사용한 Nginx 설정 파일을 Certbot 인증용 설정 파일로 교체한다. 이 설정을 통해 Certbot이 인증서 발급을 위해 필요한 HTTP 요청을 처리하도록 설정한다.
- ./nginx/nginx.certbot.conf:/etc/nginx/nginx.conf :
- volums :
- certbot-renew 서비스
- image : certbot/certbot :
- Certbot의 Docker 이미지를 사용하여 HTTPS 인증서를 발급하고 관리한다.
- Certbot은 Let's Encrypt 인증서를 발급하는 데 널리 사용되는 무료 오플 소스 도구이다.
- volumes :
- ./certbot/conf:/certbot:/etc/letsencrypt :
Certbot이 발급한 인증서를 저장할 경로이다. 이 경로는 Nginx와 공유하여 인증서를 사용할 수 있도록 설정한다. - ./certbot/www:/var/www/certbot :
인증서를 발급받기 위한 웹 루트 디렉토리를 지정한다. Certbot은 이 디렉토리를 사용하여 인증 도중 생성되는 파일을 저장한다.
- ./certbot/conf:/certbot:/etc/letsencrypt :
- command :
- certonly --webroot -w /var/www/certbot --force-renewal --email {email} -d {domain} --agree-tos :
- certonly : 인증서만 발급하고 나머지 설정을 기존 환경을 유지한다.
- --webroot -w /var/www/certbot : 인증서를 발급받기 위한 웹 루트 디렉토리를 지정한다.
- --force-renewal : 인증서를 강제 갱신한다.
- --email {이메일} : 인증서 관련 알림을 받을 이메일 주소를 설정한다.
- -d {도메인} : 인증서를 발급받을 도메인을 지정한다.
- --agree-tos : Let's Encrypt의 서비스 약관에 동의한다.
- certonly --webroot -w /var/www/certbot --force-renewal --email {email} -d {domain} --agree-tos :
- image : certbot/certbot :
Certbot 명령어 흐름
- Certbot은 지정된 도메인에 대해 인증서를 요청한다.
- 요청 과정에서 웹 루트(./certbot/www)에 임시 파일을 생성하여 도메인 소유권을 검증한다.
- 검증이 완료되면 Let's Encrypt 인증서가 ./certbot/conf 경로에 저장된다.
- Nginx는 발급된 인증서를 참조하여 HTTPS 환경을 구성한다.
nginx 설정
// nginx/nginx.certbot.conf
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name mafia-game.seojaewan.com www.mafia-game.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
listen 80;
server_name rhythm-up.seojaewan.com www.rhythm-up.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
}
- events 블록
- worker_connections 1024;
- 한 번에 처리할 수 있는 최대 연결 수를 1024개로 설정한다.
- worker_connections 1024;
- http 블록
- HTTPS 인증을 받을 서벌르 설정한다. 현재는 2개의 서버를 넣었지만 필요에 따라 1개 또는 여러개,
- location ~ /.well-known/acme-challenge/ { root /var/www/certbot; }
- Certbot이 Let's Encrypt 인증서를 발급할 때 사용하는 경로를 열어준다.
- HTTPS 인증만 받으면 되는 단계이므로 다른 경로는 접근하지 못하게 설정한다.
Certbot 인증
- location ~ /.well-known/acme-challenge/
- Let's Encrypt가 도메인 소유권을 확인하기 위해 사용하는 표준 경로이다.
- root /var/www/certbot; 설정을 통해 인증 파일이 저장될 디렉토리를 지정한다.
- Certbot이 요청을 처리할 수 있도록 반드시 포함해야 한다.
- HTTPS 인증서 발급 과정
- Certbot은 server_name에 명시된 도메인으로 요청을 보낸다.
- Nginx는 / .well-known/acme-challenge/ 경로를 처리하고, 해당 디렉토리에 저장된 인증 파일을 Certbot에 전달한다.
- 도메인 소유권이 검증되면 Let's Encrypt가 인증서를 발급한다.
HTTPS 배포
HTTPS 배포를 위해 docker-compose.deploy.yml 파일을 구성한다. 이 설정은 인증서를 발급받은 이후 Nginx가 HTTPS 트래픽을 처리할 수 있도록 Nginx 설정 파일을 HTTPS에 맞게 변경하는데 초점이 맞춰져있다.
docker compose
// docker-compose.deploy.yml
version: "3.8"
services:
nginx:
volumes:
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf
- volumes :
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf
- nginx.deploy.conf 파일은 HTTPS 배포를 위한 Nginx 설정 파일이다.
- Common Compose에도 Nginx 설정 파일이 참조되지만, 배포 시점에 변경될 가능성을 고려하여 배포 전용 설정 파일에 명시적으로 지정했다.
- ./nginx/nginx.deploy.conf:/etc/nginx/nginx.conf
nginx
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name mafia-game.seojaewan.com www.mafia-game.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mafia-game.seojaewan.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mafia-game.seojaewan.com/privkey.pem;
server_name mafia-game.seojaewan.com www.mafia-game.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 마피아 게임 서버
location / {
proxy_pass http://mafia-client:3000;
proxy_http_version 1.1;
}
# API Proxy 서버
location /api {
proxy_pass http://mafia-server:4000/;
proxy_set_header Host $host;
# 클라이언트의 Host 헤더 값을 Nginx가 프록시를 통해 백엔드 서버로 전달한다.
proxy_set_header X-Real-IP $remote_addr;
# 클라이언트의 IP를 확인할 필요가 있을 때 사용
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 다수의 프록시가 관여했을 때 원본 IP를 정확히 파악해야 하는 경우 사용
# CORS 설정 (특정 도메인만 허용)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# OPTIONS 요청에 대한 처리
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
}
# WebSocket Proxy 서버
location /socket.io {
proxy_pass http://mafia-server:4000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
# CORS 설정 (특정 도메인만 허용)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# OPTIONS 요청에 대한 처리
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
}
}
server {
listen 80;
server_name rhythm-up.seojaewan.com www.rhythm-up.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/rhythm-up.seojaewan.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rhythm-up.seojaewan.com/privkey.pem;
server_name rhythm-up.seojaewan.com www.rhythm-up.seojaewan.com;
location ~ /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 리듬업 서버
location / {
proxy_pass http://rhythm-up:3001;
proxy_http_version 1.1;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
}
}
}
- HTTP 서버 블록
- return 301 https://$host$request_uri;
- 모든 HTTP 요청을 HTTPS로 리다이렉션한다.
- 사용자가 HTTP로 접속하더라도 자동으로 HTTPS로 전환되어 보안이 강화된다.
- return 301 https://$host$request_uri;
- HTTPS 서버 블록
- ssl_certificate, ssl_certificate_key
- Let's Encrypt에서 발급받은 인증서와 개인 키를 참조한다.
- /etc/letsencrypt/live/~ 경로는 Certbot에 의해 자동 생성된 인증서 파일의 위치다.
- ssl_certificate, ssl_certificate_key
HTTPS 갱신
HTTPS 인증서 갱신을 자동화 하기 위해서는 Linux의 Crontab과 함께 사용해야 한다.
// docker-compose.certbot-update.yml
version: "3.8"
services:
nginx:
volumes:
- ./nginx/nginx.certbot.conf:/etc/nginx/nginx.conf
certbot-mafia:
image: certbot/certbot
container_name: certbot-mafia
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --force-renewal --email sjw7324@gmail.com -d mafia-game.seojaewan.com --agree-tos
certbot-rhythm:
image: certbot/certbot
container_name: certbot-rhythm
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot -w /var/www/certbot --force-renewal --email sjw7324@gmail.com -d rhythm-up.seojaewan.com --agree-tos
HTTPS 인증과 크게 다른 부분이 없기 때문에 설정에 대한 코드는 따로 작성하지 않겠다.
Linux의 Crontab 기능과 함께 사용하면서 작업한 HTTPS 인증서를 전부 갱신해주는 부분이다. 추후 새로운 서비스를 배포한다면 해당 서비스 역시 추가해서 갱신되는 부분만 업데이트가 된다고 생각하면 된다.
총총
최근에는 가급적이면 코드가 많은 글을 작성하고 싶지 않았지만, 생각해야할 거리가 많아서 작성하게 되었다.
여전히 Nginx 설정과 Docker 설정에 부족함이 있다고 생각하지만 프로젝트를 진행하면서 문제를 발견하고 찾는 것도 재미라고 생각한다.
(지금 할 수 있는 것을 하자! )
'도커' 카테고리의 다른 글
Docker 배포 최적화 (2) | 2024.12.25 |
---|---|
[Docker] Node 환경 만들기 (2) | 2022.03.13 |
[Docker] 도커? (2) | 2022.03.11 |