
version: "3"
services:
webserver:
image: nginx:latest
container_name: proxy
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./myweb:/usr/share/nginx/html
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./certbot-etc:/etc/letsencrypt
nginx:
image: nginx:latest
container_name: myweb
restart: always
volumes:
- ./myweb:/usr/share/nginx/html
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot-etc:/etc/letsencrypt
- ./myweb:/usr/share/nginx/html
command: certonly --webroot --webroot-path=/usr/share/nginx/html --email kom347@naver.com --agree-tos --no-eff-email --keep-until-expiring -d inkyung.site -d www.inkyung.site
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
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" "$request_uri" "$uri"'
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
upstream docker-web {
server nginx:80;
}
server {
location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
try_files $uri =404;
}
location / {
allow all;
root /usr/share/nginx/html;
try_files $uri =404;
}
}
}
도커 컴포즈를 백그라운드로 실행 한다.
docker-compose up -d
certbot 컨테이너의 로그를 확인하여 인증서가 성공적으로 발급되었는지 확인한다.
docker logs certbot
위 문구가 나왔다면 성공적으로 인증서가 발급되었다는 것이다.
하지만 인증서 확인을 위해 cd live 명령어를 입력해도 권한 오류가 발생한다.
따라서 인증서를 확인해보고 싶다면 설정된 루트 패스워드를 통해 접근을 해야하지만, 루트 패스워드를 설정하지 않은 경우에는 따로 sudo passwd 명령어를 통해 EC2 루트 사용자 패스워드를 설정해준다.
su -
패스워드 설정 후 위 명령어를 통해 루트 사용자로 접속해준다.
따라서 루트 사용자로 접속 후 위에 명시된 인증서가 발급된 경로로 들어가 인증서들을 확인할 수 있게된다.
su - ubuntu
인증서 확인 후 위 명령어를 통해 다시 자신의 아이디로 돌아올 수 있다.
mv nginx.conf nginx.conf.init
mv nginx.conf.https nginx.conf
HTTPS를 지원하기 위해 기존 nginx.conf 파일을 nginx.conf.https 파일로 대체한다.
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
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" "$request_uri" "$uri"'
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
upstream docker-web {
server nginx:80;
}
server {
listen 80;
server_name inkyung.site www.inkyung.site;
location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name inkyung.site www.inkyung.site;
ssl_certificate /etc/letsencrypt/live/inkyung.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/inkyung.site/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; # 보안 강화를 위한 옵션 추가
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 보안 강화를 위한 옵션 추가
location / {
proxy_pass http://docker-web; # docker-web 컨테이너로 포워딩
proxy_redirect off; # 서버 응답 헤더의 주소 변경 (불필요)
proxy_set_header Host $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-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
listen 80, location / {return 301 https://$host$request_uri;}
80 포트로 들어오는 HTTP 요청을 모두 HTTPS(443)으로 변환시킨다.
301: 영구적인 리디렉션. 사이트 주소를 변경하거나 새로운 페이지로 영구적으로 이동하는 경우에 사용. (HTTP 요청을 HTTPS로 리디렉션할 때 많이 사용된다.)
302: 임시적인 리디렉션. 주로 리다이렉션을 사용하여 요청을 다른 서버로 전달하거나, 일시적으로 특정 페이지를 다른 곳으로 이동시킬 때 사용.
$host 및 $request_uri는 Nginx에서 사용되는 변수이다.
- $host
해당 변수는 현재 요청된 호스트의 이름을 나타낸다. 즉, HTTP 요청의 호스트 헤더에 있는 값을 가져온다. 해당 변수는 사용자가 요청한 호스트의 도메인 이름을 나타내며, "www.example.com"과 같은 형식을 갖는다.
- $request_uri
해당 변수는 현재 요청된 URI(Uniform Resource Identifier)를 나타낸다. URI는 요청된 리소스의 위치를 식별하는 데 사용되며, 쿼리 매개변수 및 기타 요청 정보를 포함하며, "/page1.html?param=value"와 같은 형식을 갖습니다.
따라서 $host, $request_uri를 함께 사용하면 현재 요청된 호스트와 URI를 조합하여 완전한 요청된 URL을 생성할 수 있게되고, 리디렉션이나 요청을 다른 위치로 전달할 때 사용된다.
listen 443 ssl;
SSL(암호화 통신)을 사용하여 443 포트에서 들어오는 요청을 수신한다는 의미이다.
#include /etc/letsencrypt/options-ssl-nginx.conf;
보안 강화를 위한 추가 옵션이다.
options-ssl-nginx.conf 내용 링크 : https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
보안 강화를 위한 추가 옵션이다.
ssl-dhparams.pem 내용 링크: https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem
HTTPS를 지원하도록 nginx.conf 파일을 수정한 후 Docker Compose를 재실행한다.
cf. 재실행 전 아래 명령어들을 통해 이전에 생성했던 컨테이너, 이미지, 볼륨 등을 삭제한 후 재실행한다.
#모든 컨테이너 삭제
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker rmi -f $(docker images -q)
#쓰지 않는 볼륨 삭제
docker volume prune
#쓰지 않는 이미지, 볼륨, 네트워크 삭제
docker system prune -a --volumes
도커 컴포즈를 백그라운드로 실행 한다.
docker-compose up -d
certbot 컨테이너의 로그를 확인하여 인증서를 확인한다.
docker logs certbot
--keep-until-expiring 옵션으로 인해 발급 받은 인증서가 아직 만료가 되지 않아 갱신을 하지 않음을 의미하는 문구가 위와 같이 표시가 된다.
inkyung.site에 들어가 https로 정상 작동하는지 확인한다.
myweb 컨테이너의 index.html이란 테스트 파일이 화면에 보여지므로 정상 작동하는 것을 확인할 수 있다.