우기의 알 블로그 저자 한승욱이라고 합니다.
스스로 알을 깨고 나오는 새처럼
언젠가 알을 깨고 온전한 나 자신이 되었을 때, 그때를 기다리며 제 속에서 솟아 나오는 것을 글로써 표현하고자 합니다.
'개발 기술블로그'를 위주로 저 한승욱의 다양한 관심사, 생각, 철학 등을 포스팅합니다.
유효성 검사용, 실제 인증서를 위하여 호스트와 볼륨 맵핑이 된 상태이고, 같은 호스트 볼륨을 공유하는 nginx가 해당 파일을 제공받을 수 있다고 생각하면 된다.
두 컨테이너는 각각 commnd, entrypoint 부분이 존재하는데, 이는 인증서가 만료되었을 때 자동으로 갱신하기 위함이다.
certbot에서 12시간 마다 인증서가 갱신되는지 확인하고, nginx에서는 만약 갱신이 되었다면 이를 6시간마다 다시 적용하고 리로드하기 위함이다.
express-app 컨테이너는 내가 nginx에서 proxy pass 하고자 하는 서비스이며, 여기서는 간단한 express를 다룬다.
(Springboot, Django, FastAPI 등 자신이 만든 서비스가 해당이 될 수 있을 것이다.)
해당 부분과 Dockerfile 부분에 대한 설명은 생략한다.
다음은 init-letsencrypt.sh 스크립트이다.
기존에 원저자가 만들어놓은 것은 명령어가 docker-compose 로 되어 있어서 이 부분만 전체적으로 docker compose 로만 수정해주었다.
굉장히 긴 스크립트이지만 간단하게는 아까 이야기 한검증 받기 위한 용도라고 생각하면 된다.
domains=(spy-stock.com) # 여기에 자신의 도메인 입력하기
rsa_key_size=4096
data_path="./data/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
1) Dockerfile은 src/app.js의 간단한 express 서버에 대한 이미지다.
2)README.md 생략
3) data/nginx/app.conf 는 샘플로 제공하는 nginx 설정 파일이다.
4) docker-compose.yml은 1)번의 이미지, nginx, certbot 총 3개의 이미지에 대한 컨테이너 설정이다.
5) package.json, yarn.lock 생략
6) src/app.js는 간단한 express 서버이다.
2) shell-script 실행
init-letsencrypt.sh을 실행해준다.
이전에 당연히 github README 또는 위의 코드 설명을 보고, nginx conf와 init-letsencrypt 스크립트에 자신의 도메인을 추가해 준 상태여야 한다.
./init-letsencrypt.sh
이때까지는 꼭 data/nginx/app.conf의 주석 해제를 하면 안된다.
또한 인증서 발급을 요청하는데 횟수 제한이 있기 때문에, 테스트를 할 때에는 해당 파일의 staging=0(기본값은 1)으로 설정하여 진행하는 것을 추천한다.
만약 테스트가 성공한다면 다시 기본값인 1로 바꾸어서 스크립트를 다시 한번 실행해야 한다.
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/spy-stock.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/spy-stock.com/privkey.pem
This certificate expires on 2022-12-15.
These files will be updated when the certificate renews.
이와 같은 문구가 노출되면 성공적으로 인증서 발급이 된 것이다.
data 디렉토리안에 cerbot이라는 폴더가 생겼을 것이고 그 안에 이것저것 잡다한 파일들이 생겼을 것이다.
3) app.conf 주석 해제
data/app.conf 의 주석을 모두 해제해준다.
server {
listen 80;
server_name spy-stock.com; # 여기에 자신의 도메인 입력하기
server_tokens off;
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# 백엔드 upstream 설정
upstream myweb-api {
server express-app:80; # 여기에 자신의 컨테이너:포트, 인증서 적용에 성공하면 주석 해제
}
server {
listen 443 ssl;
server_name spy-stock.com; # 여기에 자신의 도메인 입력하기
server_tokens off;
ssl_certificate /etc/letsencrypt/live/spy-stock.com/fullchain.pem; # 여기에 자신의 도메인 입력하기
ssl_certificate_key /etc/letsencrypt/live/spy-stock.com/privkey.pem; # 여기에 자신의 도메인 입력하기
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://myweb-api; # 여기에 자신이 proxy_pass할 upstream 입력하기
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;
}
}
4) 컨테이너 실행
docker compose up
docker compose up --build
5) 확인
해당 도메인으로 접속
결론
성공적으로 ssl 인증서가 발급되었고, 해당 도메인으로 접속 시 reverse-proxy 되어 내 서비스 컨테이너에 정상적으로 동작하는 것을 확인할 수 있다.
docker compose + nginx, letsencrypt를 활용한 SSL 적용
본인은 간단한 사이드 프로젝트, 연습용 배포를 할 때 docker compose와 nginx를 통한 reverse-proxy 기반의 배포를 자주 활용한다.
보통 하나의 인스턴스에 nginx를 띄우고 내가 띄우고자 하는 서비스(예. express 서버)로 proxy_pass해주는 방식을 활용한다.
위와 같이 nginx-proxy라는 이미지를 활용해 따로 nginx 설정 없이 편하게하는 방법도 있지만,
이번에는 직접 nginx config 파일을 작성하고, letsencrypt 사설 인증서도 shell-script를 통해 받아오는 과정을 진행한다.
위 두 자료를 활용해서 진행했고, 이를 조금 더 개선해서 본인만의 예제 자료를 만들었다.
https://github.com/SeungWookHan/docker-nginx-certbot-example
가정
이에 대해서는 따로 한번 포스팅 할 예정이다.
위 레포지토리의 README을 꼼꼼히 읽는 것 만으로도 진행이 가능하지만 부가 설명을 붙여본다.
data/nginx/app.conf 를 보자
여기서 자신의 도메인에 맞춰서 # 여기에 자신의 도메인 입력하기 부분을 채워 넣어주면 된다.
초기에 주석을 달아 설정한 이유는, 초기 인증서 발급 때 에러를 유발하기 때문이다.
인증서를 발급받을 때는 http, 즉 80번 포트에 대한 설정만으로도 충분하다.
본인은 spy-stock.com 이라는 도메인을 활용하기에 이와 같이 설정해두었다.
주석 달아져 있는 부분에도 미리 채워 놔준다.
예를 들어 자신의 도메인이, a.com 이라면 위에서 해당 도메인이 들어가는 부분은,
이와 같이 될 것이다.
위 설정은 기본적으로 자신의 도메인으로 모든 http 요청에 대해 https로 디라이렉션하는 nginx 설정이다.
letsencrypt는 도메인에서 .well-known 으로 요청하여, 해당 도메인에 대한 유효성을 검사하고, 특정 응답을 받게되면 이에 대해 인증서를 부여하는 방식이다.
예를 들면, 이와 같다고 생각하면 된다.
“야 너 정말 그 도메인 소유자 맞아?”
“그러면 내가 어떠한 파일을 줄테니까 그거를 한번 띄워봐”
“그러면 내가 거기로 요청해본 뒤에 해당 파일이 정말 오면 인증해줄게”
이를 위해
해당 라인이 존재한다고 생각하면 된다.
또한 주석 부분에서는, 위에서 검증 통과 후 발급받은 인증서를 적용하기 위해
인증서, 개인키, 추가 설정을 넣어준다고 생각하면 된다.
추가적으로 나는 docker-compose.yml에 정의한 express-app 이라는 서비스로 proxy pass 해주고자 upstream으로 myweb-api라는 것을 정의해주었다.
이러한 myweb-api를 아래 라인의 proxy_pass에 적용하였다.
upstream의 이름을 바꾼다면 아래 proxy_pass에도 바꿔주면 된다.
역시 upstream 안의 컨테이너:포트도 자신의 입맛에 맞게 설정해준다.
그 다음은 docker-compose.yml 파일을 보자
nginx 컨테이너는 http, https에 대해 모두 포트를 맵핑해준다.
volumes 부분만 이해하면 되는데,
첫번째 라인은 위에서 설정한 nginx config 파일을 컨테이너 안에서도 활용할 수 있게 해주는 것이다.
두번째, 세번째 라인은 위에서 “그러면 내가 어떠한 파일을 줄테니까 그거를 한번 띄워봐” 를 시전하기 위해 certbot에서 주는 파일을 nginx 컨테이너 안으로도 제공해주기 위함이다.
여기서 한개는 유효성 검사용, 실제 인증서용이라고 생각하면 된다.
cerbot 컨테이너도 역시 volumes 부분만 이해하면 된다.
유효성 검사용, 실제 인증서를 위하여 호스트와 볼륨 맵핑이 된 상태이고, 같은 호스트 볼륨을 공유하는 nginx가 해당 파일을 제공받을 수 있다고 생각하면 된다.
두 컨테이너는 각각 commnd, entrypoint 부분이 존재하는데, 이는 인증서가 만료되었을 때 자동으로 갱신하기 위함이다.
certbot에서 12시간 마다 인증서가 갱신되는지 확인하고, nginx에서는 만약 갱신이 되었다면 이를 6시간마다 다시 적용하고 리로드하기 위함이다.
express-app 컨테이너는 내가 nginx에서 proxy pass 하고자 하는 서비스이며, 여기서는 간단한 express를 다룬다.
(Springboot, Django, FastAPI 등 자신이 만든 서비스가 해당이 될 수 있을 것이다.)
해당 부분과 Dockerfile 부분에 대한 설명은 생략한다.
다음은 init-letsencrypt.sh 스크립트이다.
기존에 원저자가 만들어놓은 것은 명령어가 docker-compose 로 되어 있어서 이 부분만 전체적으로 docker compose 로만 수정해주었다.
굉장히 긴 스크립트이지만 간단하게는 아까 이야기 한 검증 받기 위한 용도라고 생각하면 된다.
이 부분만 살펴보면 되는데,
이 정도이다.
진행
1) 레포지토리 클론
먼저 서버 컴퓨터에서 자신이 원하는 디렉토리에 해당 예제 레포지토리를 받아준다.
레포지토리의 구조는 위와 같다.
1) Dockerfile은 src/app.js의 간단한 express 서버에 대한 이미지다.
2)README.md 생략
3) data/nginx/app.conf 는 샘플로 제공하는 nginx 설정 파일이다.
4) docker-compose.yml은 1)번의 이미지, nginx, certbot 총 3개의 이미지에 대한 컨테이너 설정이다.
5) package.json, yarn.lock 생략
6) src/app.js는 간단한 express 서버이다.
2) shell-script 실행
init-letsencrypt.sh을 실행해준다.
이전에 당연히 github README 또는 위의 코드 설명을 보고, nginx conf와 init-letsencrypt 스크립트에 자신의 도메인을 추가해 준 상태여야 한다.
이때까지는 꼭 data/nginx/app.conf의 주석 해제를 하면 안된다.
또한 인증서 발급을 요청하는데 횟수 제한이 있기 때문에, 테스트를 할 때에는 해당 파일의 staging=0(기본값은 1)으로 설정하여 진행하는 것을 추천한다.
만약 테스트가 성공한다면 다시 기본값인 1로 바꾸어서 스크립트를 다시 한번 실행해야 한다.
이와 같은 문구가 노출되면 성공적으로 인증서 발급이 된 것이다.
data 디렉토리안에 cerbot이라는 폴더가 생겼을 것이고 그 안에 이것저것 잡다한 파일들이 생겼을 것이다.
3) app.conf 주석 해제
data/app.conf 의 주석을 모두 해제해준다.
4) 컨테이너 실행
docker compose up
5) 확인
해당 도메인으로 접속
결론
성공적으로 ssl 인증서가 발급되었고, 해당 도메인으로 접속 시 reverse-proxy 되어 내 서비스 컨테이너에 정상적으로 동작하는 것을 확인할 수 있다.
'기술개발 > Nginx' 카테고리의 다른 글