
개요
서버(NAS)와 인터넷을 사용한 통신으로 주고받는 정보는 외부에 노출이 되기 때문에 개인정보와 같이 민감한 정보를 다루는 경우라면 SSL/TLS 인증서를 발급받아 암호화하여 송수신하는 것이 권장됩니다.
사전작업
인증서 발급
앞선 글 TLS 인증서 발급의 내용을 참조합니다.
Nginx 설치 및 HTTP 연결 설정
앞선 글 웹 서버 설치 및 설정 - Nginx (1/2)의 내용을 참조합니다.
DH Param 키 생성
추가로 HTTPS의 암호화 성능을 높이기 위해 사용하는 난수 DH Param키를 생성합니다.
※ 아래 명령어는 오라클 클라우드 Free Tier 등급에서 제공하는 가상 머신을 이용하면 완료까지 3시간 이상 소요됩니다.
※ 컴퓨터 앞에 앉아서 키의 생성을 하염없이 지켜볼 것이 아니라면, 다음 글 SSH세션-종료시-실행중인-프로그램-종료-방지-Screen을 참고하여 screen을 설치하고 사용법을 익힌 후, 아래 명령을 실행할 것을 추천합니다.
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
https용 서버 블록 설정
앞선 글 웹 서버 설치 및 설정 - Nginx (1/2)에서 생성하였던 example.com의 Nginx 서버 블록 파일을 텍스트 편집기로 열어 편집합니다.
sudo vim ~/docker/nginx-ssl/etc/nginx/conf.d/example.com.conf
서버 블록 파일의 내용은 아래와 같이 수정합니다.
※ example.com 은 자신이 신청한 도메인명으로 교체합니다.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
root /usr/share/nginx/example.com/html;
index index.html index.htm;
server_name example.com www.example.com;
include conf.d/ssl-params.conf;
location / {
try_files $uri $uri/ =404;
}
}
TLS 보안 설정을 별도 파일로 작성하여 example 서버 블록에 포함시켰습니다. 해당 파일을 작성합니다.
vim ~/docker/nginx-ssl/etc/nginx/conf.d/ssl-params.conf
# from https://gist.github.com/ziazek/ae2cb56fe63f8727dbaa55cddbc9780e
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
# use Google DNS
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS header: BE CAREFUL!
# Uncommenting this setting means that your site needs to support HTTPS in the future (including subdomains),
# otherwise users who have previously been to your site won't be able to access.
add_header Strict-Transport-Security max-age=31536000;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exmaple.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
※ 위 내용에 대한 상세한 설명은 Nginx 공식문서를 참조합니다.
YAML 수정
변경사항의 적용을 위하여 포테이너 관리자 페이지(http://example.com:9000)에 접속하여, [Stacks] → [nginxssl] 으로 이동합니다. 기존 내용을 아래와 같이 수정한 후, [Deploy the stack] 버튼을 누릅니다.
version: "2"
services:
nginx:
image: nginx:latest
restart: always
ports:
- 80:80
- 443:443
volumes:
- /home/ubuntu/docker/nginx-ssl/public:/var/www
- /home/ubuntu/docker/nginx-ssl/conf.d:/etc/nginx/conf.d
- /etc/letsencrypt:/etc/letsencrypt
- /etc/ssl/certs:/etc/ssl/certs
portainer 접속 주소 수정
배포를 마친 후, portainer에 접속하기 위하여 웹브라우저에 example.com:9000을 입력하면 다음과 같은 오류가 표시됩니다.
※ 크롬 기준입니다.
사이트에 보안 연결할 수 없음
example.com에서 잘못된 응답을 전송했습니다.
Windows 네트워크 진단 프로그램을 실행해 보세요.
ERR_SSL_PROTOCOL_ERROR
오류의 원인은 다음 두 가지입니다.
- PC용 크롬 브라우저의 경우 한번 https로 접속한 이후, http로 접속되지 않습니다.
- ssl-param.conf에 설정하였던 add_header 옵션의 의미가 https로 접속한 후 http 접속을 허용하지 않기 때문입니다.
즉, 주소창에 아무리 http://example.com:9000으로 입력하여도 크롬에서 강제로 https://example.com:9000으로 변환하기 때문에 오류가 발생합니다.
이를 해결하는 대안 몇 가지는 다음과 같습니다.
- 크롬의 시크릿 모드로 해당 페이지에 접속합니다.
- 스마트 폰에서 접속합니다.
- 도메인 대신
공인 IP:9000를 입력하여 접속합니다.
근본적으로는 9000 포트 역시 SSL 을 적용하면 되겠으나 해당 포트는 Nginx를 거치지 않고 포테이너가 직접 외부와 연결하여 사용하고 있으므로 편집이 불가합니다.
따라서 다음과 같이 Nginx 웹 서버에 리버스 프락시를 구성합니다. 아래의 내용을 기존에 운영 중인 서버 블록에 추가합니다.
location /portainer/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_pass http://example.com:9000/;
}
location /portainer/api/websocket/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_pass http://example.com:9000/api/websocket/;
}
최종 서버 블록은 다음과 같습니다.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
root /usr/share/nginx/example.com/html;
index index.html index.htm;
server_name example.com www.example.com;
include conf.d/ssl-params.conf;
location / {
try_files $uri $uri/ =404;
}
location /portainer/ {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_pass http://example.com:9000/;
}
location /portainer/api/websocket/ {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_pass http://example.com:9000/api/websocket/;
}
}
변경사항의 적용을 위하여 일단은 크롬의 시크릿 모드로 포테이너 관리자 페이지(http://example.com:9000)에 접속하여, [Containers]에서 [nginxssl_nginx_1]을 체크, [Restart]로 nginx 서비스를 재시작합니다.
이제 https://example.com/portainer로 접속하면 기존과 같이 포테이너의 관리자 페이지를 확인할 수 있습니다.
※ 자물쇠 표시를 통해 SSL 이 적용되었음을 확인할 수 있습니다.
※ 추가한 내용은 http://example.com:9000으로 proxy 하였으나, 사실 Container를 서로 연결하여 172.18.0.3같은 내부 IP를 통해 연결하고, 9000 포트는 외부 접속을 불허하는 것이 더욱 보안 측면에서는 좋을 것입니다.
정리
앞선 글에 이어 Nginx를 설정하였습니다. 그 결과 자작 NAS에서 HTTPS를 이용하여 데이터 통신을 수행할 수 있게 되었습니다. 이후의 과정은 자신의 필요에 따라 선택하여 적용할 수 있습니다.
참고
'기타' 카테고리의 다른 글
| 도커 설치 후, 실행시 오류 (0) | 2020.09.23 |
|---|---|
| [자작 NAS] 7. 미디어 서버 - Plex (0) | 2020.09.22 |
| [자작 NAS] 4. Docker 및 Portainer 설치하기 (0) | 2020.09.12 |
| [자작 NAS] 1. 우분투 서버 마련하기 (0) | 2020.09.12 |
| [자작 NAS] 6. 토렌트 클라이언트 - Transmission (0) | 2020.09.07 |