티스토리 뷰

Infra

DuckDns + LetsEncrypt로 Nginx HTTPS설정

빛의기도 2024. 8. 21. 15:56

 
 

프로젝트 초기에는 도메인 및 인증서가 없는 상황이 대부분이다.
하지만 backing system들 중, SSL 인증서가 필요한 환경도 있을 수 있다.(가령 docker registry 등…)
이때, public 도메인과 공인 인증서를 무료로 발급 받는 방법을 설명 한다.

 


환경

구축 환경은 다음과 같다.

OS : ubuntu
docker + nginx
docker + letsencrypt
duckdns domain + crontab 으로 자동 갱신

 
이런 환경과 다르다 하더라도 docker를 설치 하는 방법과 crontab 등록 방법이 약간 OS별 차이만 있을 뿐이므로, 크게 차이가 없을것이라 생각 한다.
 
 
우선, OS는 준비 되어 있다고 가정하고 진행 한다.
OS 설치까지 담기에는 너무 쓸 내용이 많아진다.......


A. Docker 설치

docker 에 대해서는 이미 알고 있을거라 생각 하고 Pass....

더보기

하려고 했지만,

모르는게 당연한거라...... 약간의 부연 설명을 하겠음..

Docker가 뭐지? 어떻게 쓰는겨? (tistory.com)  < -- 여기를 참고 해도 좋을 것 같다.

 

docker는(정확히는 containerd는...) cgroups 라는 프로세스들의 자원을 제한하고 격리시키는 커널 기능을 사용한 가상환경을 구현한 구현체이다. 말이 어렵다면, 간단히 vmware나 virtualbox 같은 가상환경이라고 생각 하면 된다.

 

하지만 vmware나 virtualbox 와는 다른 점은, 가상머신을 생성하는게 아니고 실행할 process를 container 단위로 실행 시킨다는게 다르다. 가상머신은 하드웨어를 가상화해서 구현하고, 그 위에 OS부터 차근차근 다 설치 해야 한다. 하지만 container는 실행할 Process만 Image 단위로 만들어서 Container단위로 실행 하게 되므로, 가볍고 빠르다.

 

Container는 Contaienr Runtime이라는... 일종의 Java의 JVM 과 같은 런타임 위에서 기동 되게 된다. 이 Contaienr Runtime이 containerd 이고, docker는 CLI이다.

 

 

docker 컨테이너란 무엇인가요?
https://www.docker.com/blog/lxc-vs-docker/

 

Docker Engine 이 바로 Container Runtime이고, 그 위에 실행되는 APP 2개가 Container이다...


 

이 문서에서는 Ubuntu에서 진행 할 예정이다.

 

하지만..... Windows 에서 설치 하고자 한다면... 

권장하진 않지만..... WSL V2를 설치 하고 Docker Desktop 을 설치하면 된다.

Docker는 Linux Kernel 기능을 사용한거라 Windows에서는 실행이 되지 않는다.

WSL이나 Hyper-V 등... 가상 환경에서 설치 해야 한다.

 

https://docs.docker.com/desktop/install/windows-install/#system-requirements

Install Docker Desktop on Windows

Get started with Docker for Windows. This guide covers system requirements, where to download, and instructions on how to install and update.

docs.docker.com

 

https://docs.docker.com/desktop/install/windows-install/#install-docker-desktop-on-windows

Install Docker Desktop on Windows

Get started with Docker for Windows. This guide covers system requirements, where to download, and instructions on how to install and update.

docs.docker.com

 

 

물론 개인사용자에게만 무료다..

docker core 가격 정책.(개인사용자에게는 무료이다!)
https://www.docker.com/pricing/

원래는 전체 무료였는데... 몇년 전에 Docker Desktop이 유료 전환 되었다..

 

  

더 자세한 내용은 Docker 공식 사이트를 참고 하길..

RedHat 사이트도 비교적 잘 정리된 문서들이 많음..

 

https://docs.docker.com/get-started/
https://docs.redhat.com/ko/documentation/red_hat_enterprise_linux/6/html/resource_management_guide/ch01

 

 
docker가 설치 되어 있지 않다면, docker를 먼저 설치 해 보자.
Docker-Desktop 이 아니고 Docker Engine 만 설치 하는거다..!!!
 
 
https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

Install Docker Engine on Ubuntu

Jumpstart your client-side server applications with Docker Engine on Ubuntu. This guide details prerequisites and multiple methods to install Docker Engine on Ubuntu.

docs.docker.com

 

docker가 설치 되어 있지 않은 상황
docker ps 명령이 실행되지 않음.
# Get the Docker signing key for packages
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
# Add the Docker official repos
echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
     $(lsb_release -cs) stable" |     sudo tee /etc/apt/sources.list.d/docker.list
# Install Docker
# The aufs package, part of the "recommended" packages, won't install on Buster just yet, because of missing pre-compiled kernel modules.
# We can work around that issue by using "--no-install-recommends"
sudo apt update
sudo apt install -y --no-install-recommends     docker-ce     cgroupfs-mount
sudo systemctl enable docker
sudo systemctl start docker

 
docker ps 명령이 실행 되는지 확인 한다.
 
 
 
 

B. Domain 생성

 

1. Duckdns에 도메인 생성.

Duckdns 사이트를 접근해서 duckdns.org 도메인을 생성 한다.

URL : https://duckdns.org
gmail 계정으로 로그인 가능.

 

더보기
duckdns 사이트 화면
duckdns 가입을 위한 google 계정으로 로그인

로그인 하고, 승인 절차를 거치면 아래와 같이 로그인이 됨.(상단 우측에 Mail 계정이 보임)

 

화면에 reCaptcha 버튼을 클릭

duckdns 가입 후 최초 1회 reCapcha 버튼을 클릭안내.
domain 목록을 볼 수 있는 화면(현재는 비어 있음)

sub domain에 원하는 domain을 적고, add domain을 클릭 하면, 만약 중복되지 않은 도메인이라면 아래와 같이 등록 되고,

"current ip" 에 현재 접근한 pc의 공인 ip를 확인할 수 있음.

신규 도메인 등록 화면

 

이렇게 등록 되면 바로 사용 가능하다.

window 키 > cmd 를 실행 해서 ping 을 실행 해 보면, 정상적으로 응답이 오는 것을 확인 할 수 있다.

도메인 등록 후 ping 테스트 화면

 

 

 

이제 duckdns 화면에서 token을 확인 한다.

duckdns 계정의 token 확인 하는 화면

도메인 생성이 끝나면 아래 정보를 기억 한다.

  • 계정(gmail)
  • token
  • domain
  • ip

 

2. IP 자동 갱신을 위한 crontab 등록

보통 현재 진행하는 환경이 유동 IP일 것이다.
어느순간 IP가 변경이 되게 되는데, 그러면 domain에 할당 된 ip를 매번 변경 해 주어야 한다.
 
duckdns 사이트의 install 메뉴를 보면 update 하는 명령이 소개 되어 있다.

해당 update 구분을 주기적으로 실행 하도록 crontab에 등록 할 예정이다.
등록을 위해 duck.sh 라는 script를 작성하고, 해당 script를 5초에 한번 실행하도록 crontab에 등록 할 예정이다.
 
아래와 같은 Script를 미리 만들었다. 
여기서 다음과 같이 수정하고 실행 하면 된다.

  • lst_dns, token을 수정
  • root 권한으로 해당 script를 실행
mkdir -p /data/install/duckdns
cat << EOF > /data/install/duckdns/duck.sh
# --------------------------------------------------------
# multiple domain define.
# ex : domain01.duckdns.org / domain02.duckdns.org
# lst_dns="domain01;domain02"
# --------------------------------------------------------

lst_dns="dev-001"  
token="12a34b5c-d678-491e-fg9h-0ij123kl4mno"

export IFS=";"  
for dns in \$lst_dns; do  
  echo "curl \"https://www.duckdns.org/update?domains=\$dns&token=\$token&ip=\"" > "/data/install/duckdns/logs/\$dns.cmd"  
  echo url="https://www.duckdns.org/update?domains=\$dns&token=\$token&ip=" | curl -k -o "/data/install/duckdns/logs/\$dns.log" -K -  
  sleep 5  
done
EOF

chmod +x /data/install/duckdns/duck.sh

cat  << EOF >> /var/spool/cron/crontabs/root
*/5 * * * * /data/install/duckdns/duck.sh >/dev/null 2>\&1
EOF

 
그러면 /data/install/duckdns의 경로에 duck.sh 파일이 생성 되고, crontab에 등록된다.
만약 도메인이 여러개라면, lst_dns에 세미콜론(;) 으로 구분하여 도메인을 나열해 주면 된다.
(ex : lst_dns="domain01;domain02")
 


C. Nginx 설치

비교적 가벼운 NginX를 설치 한다.
Nginx 는 Docker로 설치 한다.
 

1. 이미지 다운로드

docker pull nginx

 
 
원본 config를 획득 한다.

# /etc/nginx/conf.d -> /etc/nginx/conf.d.tmp 로 config를 복사할거다.

# nginx container 를 임시로 실행 함.(이때 복사를 위해 volume 을 설정 한다.)
docker run --name nginx -d --rm \
 -v /apps/nginx/conf.d:/etc/nginx/conf.d.tmp
 nginx:1.23.1

# config 복사
docker exec -it nginx sh -c "cp /etc/nginx/conf.d/* /etc/nginx/conf.d.tmp/"
sudo docker cp nginx:/etc/nginx/nginx.conf /apps/nginx/nginx.conf

# container 제거
docker stop nginx

 
 
획득한 config 파일들을 확인 한다.

ls /apps/nginx/*
nginx의 설정 경로 확인

 
 

2. 실행

 docker run --name nginx -d -p 80:80 -p 443:443 --restart=always \
 -v /apps/nginx/nginx.conf:/etc/share/nginx/nginx.conf \
 -v /apps/nginx/html:/etc/share/nginx/html \
 -v /apps/nginx/common.d:/etc/nginx/common.d \
 -v /apps/nginx/conf.d:/etc/nginx/conf.d \
 -v /apps/nginx/ssl.d:/etc/nginx/ssl.d nginx:1.23.1

 

  • nginx.conf : nginx 의 기본 설정 파일
  • html : 정적 페이지를 구성할때 사용할 경로
  • common.d : 추후 사이트 공통으로 구성할 설정이 있을 경우 사용할 경로
  • conf.d : 사이트 별 설정을 정의할 경로
  • ssl.d : SSL 설정을 구성할 경로

 
 
다음과 같은 명령으로 실행중인 container를 확인할 수 있다.
 

  • docker ps 
  • : docker container의 실행 상태를 확인 할 수 있음.
  • docker logs -f {container-id}
  • : docker container의 log를 확인. container-id는 docker ps로 확인할 수 있음.

 

3. 실행 확인 및 접속 테스트 

docker ps
port forward 설정 확인

 
port forwarding이 80, 443 으로 되어 있으므로 브라우져로 접속 해 본다.
브라우져에서 http://{서버 IP} 로 접속 해 확인할 수 있다.
 

browser로 http 접속 화면

 
http 로 접속해서 안전하지 않다는 경고를 볼 수 있다.
 

http로 접속 했을때 안전하지 않음 이라는 경고 출력

 
 
이때, 앞에서 설정한 duckdns 도메인으로도 접속 확인을 해 본다.
만약 도메인으로 접속할 수 없다면 공유기에서 forward 설정을 해 줘야 한다.
 
 

4. 공유기 Forward 설정

 
이 설정은 공유기마다 다르다...
각 공유기 메뉴얼을 참고 한다.

더보기

참고로 IPTime을 기준으로 설명 하자면.....

 

보통은 192.168.0.1 이.. 공유기 접속 ip 일거다...

ip를 확인 해 보면, 기본 게이트웨이(Default Gateway) IP가 공유기 IP이다.

기본 게이트웨이 확인

 

브라우져로 접속 하여 로그인 하고,

공유기 관리화면 접속

관리도구를 들어간다.

iptime의 경우 관리도구 접속

일반적으로 포트포워드 설정은 라우터 관리 메뉴 하위에 있다...(공유기 마다 다름..)

iptime의 경우 포트포워드 설정

 

 

그러면 이제 도메인으로 접속 할 수 있다.

 
대략.. 이런 식이다...;;

port forward 설정 시 적용 할 망 구성도

 
정상적으로 설정이 되었다면 도메인으로 접속이 가능 할 것이다.
 
만약, 공유기 내부에서 domain으로 접근이 안된다면, 휴대폰 LTE로 연결 후 폰에서 브라우져로
http://dev-001.duckdns.org와 같이 duckdns에 등록한 도메인으로 접근을 해 본다.
 
LTE로 접근이 잘 된다면, 큰 문제는 없을 것으로 생각 된다.
다만 직접 접근이 안된다면 hosts 파일에 해당 도메인과 192 로 시작하는 사설 ip를 등록해서 우선 진행 하도록 한다.
 
 


 

D. Lets Encrypt 설치

Lets Encrypt는 비영리 기관 ISRG 에서 발급해 주는 TLS 인증서 이다. 전세계 2억개가 넘는 사이트에서 사용하고 있다고 한다.
 

letsencrypt 사이트

 
 

1. 설치

 
아래 Script에 적절한 값을 설정하여 실행 한다.

  • EMAIL : duckdns 로그인 ID(gmail 계정)
  • URL : duckdns 에 등록한 subdomain을 포함한 전체 주소.(dev-001.duckdns.org)
  • DUCKDNSTOKEN : duckdns 의 token. (duckdns 사이트에 로그인 해 보면 보인다...)
sudo docker run \
--cap-add=NET_ADMIN \
--name=letsencrypt \
-v /data/letsencrypt/config:/config \
-e PGID=$(id -g $USER) \
-e PUID=$UID \
-e EMAIL=<요기에 duckdns login id> \
-e URL=<요기에 duckdns domain, ex:domain01.duckdns.org> \
-e SUBDOMAINS=wildcard \
-e ONLY_SUBDOMAINS=true \
-e VALIDATION=duckdns \
-e DUCKDNSTOKEN=<요기에 duckdns token, duckdns 로그인 후 도메인 등록 페이지에서 확인 할 수 있다.> \
-p 60080:80 \
-p 60443:443 \
-e TZ=Asia/Seoul \
--restart=unless-stopped \
linuxserver/letsencrypt:version-1.11.0

 
이 container도 80, 443으로 통신 한다. 그래서 nginx container와 충돌이 발생해서 기동이 안된다.
letsencrypt container는 60080->80, 60443->443 으로 forward 설정을 해줘서 문제가 발생하지 않도록 한다.

letsencrypt 가 실행된 상황에서 망 구성도

현재 대략 이런식으로  띄워 지게 되는데,
인증서 발급을 위해서는 LetsEncrypt Container에 외부에서 접근 가능해야 한다.
 
이제, 공유기에서도 80->60080, 443->60443 으로 들어오도록 설정을 바꿔 주고 실행 하도록 한다.

letsencrypt container로 portforward 구성을 한 망 구성도

 

letsencrypt container 실행 화면(log)
실행 화면
duckdns로 인증서 발급 확인 화면

인증서 발급이 완료 되었다.
 
 

생성된 인증서 확인(domain 폴더)
생성된 인증서 확인(keys/letsencrypt)

각 도메인 별 경로가 별도로 생성되니, 참고 하시고...
 
이 인증서를 Nginx에 설정 해 주면 된다.
 
다시 공유기 forward 설정을 원복 하고....(60080, 60443 제거)
Nginx 에 인증서 설정을 한다.
 


 

E. Nginx에 인증서 설정

 

1. SSL 설정 

(1) 백업

cp /apps/nginx/nginx.conf /apps/nginx/nginx.conf.backup
cat << EOF > /apps/nginx/nginx.conf
user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    server_names_hash_bucket_size 128;
    server_names_hash_max_size 8192;
    
    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" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
    
    sendfile        on;
    keepalive_timeout  65;
    charset           utf-8;
    include /etc/nginx/conf.d/*.conf;
}
EOF

 

(2) ssl.location.opt 설정 파일 생성

이 파일은 letsencrypt 가 생성된 디렉토리 중에서 내용을 찾아볼 수 있다.
관심 있으신 분은 /apps/letsencrypt 경로 아래에 nginx 경로를 찾아 보도록.....

cat << EOF > /apps/nginx/ssl.d/ssl.location.opt
                 proxy_redirect off;
                 proxy_http_version 1.1;
                 proxy_pass_header Server;
                 proxy_set_header X-Scheme \$scheme;
                 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-Proto "https";
EOF

 
 

(3) 서버(사이트) 설정 추가

duckdns 에 생성된 도메인 명으로 conf 파일을 만든다.
그리고 server_name 을 적당히 수정 한다.

cat << EOF > /apps/nginx/conf.d/dev-001.duckdns.org.conf
server {
        listen 80;
        server_name *.dev-001.duckdns.org;
        return 301 https://\$host\$request_uri;
 }
server {
         listen 443 ssl;
         server_name sub1.dev-001.duckdns.org sub2.dev-001.duckdns.org;
         include ssl.d/dev-001.duckdns.org.ssl;
         location / {
                 include ssl.d/ssl.location.opt;
                 
                 root   /usr/share/nginx/html;
                 index  index.html index.htm;
        }
 }
server {
         listen 443 ssl;
         server_name *.dev-001.duckdns.org;
         deny all;
 }
EOF

 
사이트의 ssl 설정도 파일명을 적당히 수정 해 준다.

cat << EOF > /apps/nginx/ssl.d/dev-001.duckdns.org.ssl
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
ssl_session_tickets off;

# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
### Linuxserver.io Defaults
# Certificates
ssl_certificate /apps/letsencrypt/config/keys/letsencrypt/fullchain.pem;
ssl_certificate_key /apps/letsencrypt/config/keys/letsencrypt/privkey.pem;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /apps/letsencrypt/config/keys/letsencrypt/fullchain.pem;
# Diffie-Hellman Parameters
ssl_dhparam /apps/letsencrypt/config/nginx/dhparams.pem;
# Resolver
resolver 127.0.0.11 valid=30s; # Docker DNS Server
# Enable TLS 1.3 early data
ssl_early_data on;
EOF

 

2. Nginx 재기동

이때, Letsencrypt 구성 경로도 mount 추가 해 준다.
 
* 정지

docker stop nginx
docker rm nginx

 
* 기동

docker run --name nginx -d -p 80:80 -p 443:443 --restart=always \
-v /apps/nginx/nginx.conf:/etc/share/nginx/nginx.conf \
-v /apps/nginx/html:/etc/share/nginx/html \
-v /apps/nginx/common.d:/etc/nginx/common.d \
-v /apps/nginx/conf.d:/etc/nginx/conf.d \
-v /apps/nginx/ssl.d:/etc/nginx/ssl.d \
-v /apps/letsencrypt:/apps/letsencrypt \
 nginx:1.23.1

 
 
이제 접속 해 보면, 인증서가 정상적으로 설정 되어 로드 되는것을 확인할 수 있다.
해당 인증서는 3개월짜리 Asta(*) 인증서 이므로, Sub domain을 마음대로 추가하여 구성 해도 된다!!!
3개월 뒤에는 인증서를 갱신을 해 줘야 한다.
물론, 이것도 자동으로 구성하는 방법이 있지만, 다른 페이지에서 다루도록 하겠다.

nginx 에 인증서 적용 후 https로 정상 통신 되는 화면

 
 

'Infra' 카테고리의 다른 글

docker-compose 에 대한 소개 및 사용법  (0) 2024.08.28
[IaC] vagrant로 virtualbox의 VM 관리하기  (2) 2024.08.23
컨테이너 런타임시스템 Docker!!  (0) 2024.08.22
DevOps란?  (0) 2024.08.20
클라우드 서비스의 이해  (0) 2024.08.20