개요
서버(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 |