0. 들어가기 앞서
이전 포스팅인 [CertBot] SSL 와일드카드 인증서 받기 [Docker] 주피터 노트북 생성 를 보고 오면 도움이 된다.
내 부끄러운 코드를 실행하는 주피터 노트북은 기본적으로 HTTP로 작동되는 상태다. 이말은 즉 내 주피터 노트북 서버 까지 가는 네트워크 장비 중 한개라도 보안 사고가 발생하면 부끄러운 내 코드가 만 천하에 공개될수 있다. 그렇기 때문에 HTTPS 를 적용할 예정이다.
HTTPS 는 nginx 와 apache 웹 서버와 같은 웹 엔진으로 리버스 프록시를 사용하여 적용한다.
1. 공식문서
이번 포스팅은 도커의 엔진엑스 이미지를 가지고 리버스 프록시를 설정 할 예정이다.
블로그를 따라하는것도 좋지만 공식문서를 보자.
눈물을 머금고 60개월 풀할부로 산 K8 의 메모리시트 사용법은 옆집 준식이보다 기아 메뉴얼이 더 잘 알려주기 때문이다.
하지만 공식 문서의 알짜배기만 필요한 사람들을 위해 공식문서를 보며 소개하겠다.
2. 준비물
준비물은 SSL 인증서가 필요하다. SSL 인증서가 없는 경우[CertBot] SSL 와일드카드 인증서 받기 로 SSL 인증서를 받아오자.
또한 주피터 노트북의 컨테이너 혹은 주피터 노트북도 실행중인 상태여야 한다. 여기서는 3333 번 포트로 주피터 노트북이 실행중임을 가정한다.
3. 설정 확인
먼저 주피터 노트북의 실행 포트를 봐야한다. 블로그 주인장은 도커로 주피터 노트북을 실행중이다.
docker ps -a

이렇게 됬다면 nginx 를 설정해야 한다. 기본적으로 http 로 들어오는건 https 로 바꿔주고, https 로 들어온 패킷은 주피터 노트북으로 바인딩 시켜줘야 한다. 그 역할을 리버스 프록시 설정으로 해주는 것이다.

공식문서를 보면 클라이언트는 NGINX 에 요청하면 클라이언트가 바로 프록시 서버에 가는게 아닌 NGINX 가 프록시 서버에 접속 한후 그 응답을 클라이언트에 전달해주는 역할을 한다고 한다. 지원하는 프로토콜은 FastCGI, uwsgi, memcached 가 있다고 한다.
또한 http 프록시 서버에 요청을 전달하려면 proxy_pass 를 지정해주면 된다고 한다.
location /some/path/ {
proxy_pass http://www.example.com/link/;
}
이렇게 말이다.
하지만 이렇게 하면 문제가 있다. nginx 가 프록시 서버에 접속하는꼴이 되므로 실제로 누가 요청했는지 헤더값을 설정 해 줘야 한다.

엔진엑스 공식 문서에서도 Request 헤더를 추가 해줘야 한다고 한다.
location /some/path/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
이런식으로 말이다.
하지만 주피터 노트북은 websocket 도 사용한다. 그렇기 때문에 웹소켓도 설정 해야한다.
공식문서에 매우 친절히 나와있다.

세가지 헤더만 추가 하면 된다고 한다.
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
4. 설정 적용
위의 3장의 설정을 잘 보면 https 로 들어오는걸 주피터 노트북에 연결만 해주면 끝이다. nginx 가 http 로 주피터 노트북에 접속해야 함으로 proxy_pass 를 사용 해야 하며, 헤더값을 지정하여 주피터 노트북이 엔진엑스가 아닌 클라이언트의 실제 호스트와 실제 ip의 값을 지정해줘야 한다.
이렇게 말이다
vim /etc/nginx/conf.d/default.conf
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/letsencrypt/live/[mydomain.com]/fullchain.pem; # SSL 인증서 파일
ssl_certificate_key /etc/letsencrypt/live/[mydomain.com]/privkey.pem; # SSL 키 파일
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://[주피터노트북IP]:[주피터노트북포트];
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
}
}
server {
listen 80;
server_name localhost;
return 301 https://$host$request_uri;
}
이렇게 말이다.
주피터노트북IP와 포트, mydomain환경에 맞게 바꿔줘야 한다. 아래는 블로그 주인장의 conf다.
블로그 주인장은 3333포트를 사용중이기 때문에 저렇게 설정해줬다.

5. 확인해보기
이제 다 되었다면 도커로 nginx 를 실행해보면 끝이다.
아래 명령어를 실행해서 한번 확인해보자.
docker run --name nginx -p 80:80 -p 443:443 -d -v /etc/nginx/conf.d:/etc/nginx/conf.d -v /etc/letsencrypt:/etc/encrypt nginx

HTTPS 가 야무지게 적용된다.
6. Docker-Compose 설정
지금 3333번 포트는 외부에 열려있다. 직접 WAS(주피터 노트북)을 외부에 노출하는것은 별로 좋지 않은 행위다. 그래서 실제 배포 할때는 nginx 만 외부에 열고 나머지는 다 차단한다.
또한 주피터 노트북이 실행이 안된 상태에서 nginx 를 켜봤자 말짱 도로묵이기 때문이다.
그러면 어떻게 하면 WAS 를 외부에 노출하지 않으면서 주피터 노트북이 실행 되야만 nginx 를 실행시킬수 있을까?
우리는 도커를 사용중이다. 도커는 해당 솔루션을 docker-compose 를 통해 제공한다.
먼저 아무데나 Docker-compose.yml 파일을 아래와 같이 만들자.
jupyter-3.9 의 3333:8888 을 없애고 컨테이너를 jupyter-network 라는 어댑터로 묶었다. 이렇게 하면 컨테이너명이 아이피가 된다.
cd
vim docker-compose.yml
version: '3'
services:
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- /etc/nginx/conf.d:/etc/nginx/conf.d
- /etc/letsencrypt:/etc/letsencrypt
restart: always
depends_on:
- jupyter-3.9
networks:
- jupyter-network
jupyter-3.9:
image: jupyter/minimal-notebook:python-3.9.7
container_name: jupyter-3.9
environment:
- DOCKER_STACKS_JUPYTER_CMD=notebook
volumes:
- /home/ubuntu/jupyter:/home/jovyan
restart: always
networks:
- jupyter-network
networks:
jupyter-network:


이렇게 만들었으면 모든 컨테이너를 종료 후 삭제시킨다.
docker stop nginx
docker stop jupyter-3.9
docker rm nginx
docker rm jupyter-3.9
docker ps -a

또한 nginx.conf도 아래와 같이 수정해줘야 한다.
vim /etc/nginx/conf.d/default.conf
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/letsencrypt/live/[mydomain.com]/fullchain.pem; # SSL 인증서 파일
ssl_certificate_key /etc/letsencrypt/live/[mydomain.com]/privkey.pem; # SSL 키 파일
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://jupyter-3.9:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_read_timeout 86400;
}
}
server {
listen 80;
server_name localhost;
return 301 https://$host$request_uri;
}
꼭 proxy_pass http://jupyter-3.9:8888 은 바꾸면 안된다!

그 후 docker-compose.yml 파일이 있는곳에 가서 실행하면 된다.
docker-compose up

접속 확인을 해보자.

또 이제 8888 로 들어가면 접속이 안됨을 볼 수 있다.
'도커' 카테고리의 다른 글
| [DOCKER] 도커로 Django 배포하기 (0) | 2023.11.07 |
|---|---|
| [Docker] 주피터 노트북 생성 (1) | 2023.10.20 |
| 도커설치 - 우분투 (0) | 2023.10.20 |