# 關於 staticfloat/nginx-certbot 的機制說明 ## 前言 之前一直沒有很懂如果這image要配上docker-compose.yml到底需要怎麼配置,網路上眾說紛紜,直到今日我觀察到了一個現象。 ## 重點1 (vaildation response) * 在container內下`ps aux`可以看到一行指令一直有存在 ```bash USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 3848 2964 pts/0 Ss+ 03:04 0:00 /bin/bash /scripts/entrypoint.sh ``` * `cat` 看一下這隻程式會發現他用一個無窮迴圈在跑(一週跑一次) `/scripts/run_certbot.sh`,這隻程式裡面有用到 `/scripts/util.sh` 裡面的function `get_certificate()` 有執行一段程式碼 ```bash certbot certonly --expand --agree-tos --keep -n --text --email $2 --server \ $letsencrypt_url $opt_domains --http-01-port 1337 \ --standalone --preferred-challenges http-01 --debug ``` * 可以看到裡面的port是用1337去產生 http://YOUR_DOMAIN/.well-known/acme-challenge/xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 的 **vaildation response** * 意思就是你需要在你的 nginx default.conf 裡在80port那一個server section裡加上 ```nginx server { listen 80; listen [::]:80; ##For Certbot SSL acme-challenge ##Docker service nginx use staticfloat/nginx-certbot as image ##The script in container /scripts/run_certbot.sh use 1337 for certbot --http-01-port location ~ /.well-known/acme-challenge/ { allow all; proxy_pass http://localhost:1337; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } ..... ``` * 這邊之所以要用loaclhost是因為是在這一顆container內本身,如果是別顆contain去起nginx服務,用staticfloat/nginx-certbot僅作為驗證機,那就要走另外的方式(綁host port或走docker network) ## 重點2 (/etc/nginx/user.conf.d/*.conf 與 /etc/nginx/conf.d/*.conf) * 我在docker-compose.yml裡綁定volumes是這樣綁 ```yaml nginx: container_name: my_nginx image: staticfloat/nginx-certbot restart: unless-stopped tty: true ports: - "80:80" - "443:443" environment: CERTBOT_EMAIL: my.mail@gmail.com volumes: - /var/www/html/project:/var/www/html/project - ./nginx:/etc/nginx/user.conf.d:ro - /etc/letsencrypt:/etc/letsencrypt depends_on: - php ``` * `./nginx`資料夾裡有放一的`default.conf`檔,staticfloat/nginx-certbot似乎會將container內的`/etc/nginx/user.conf.d`這資料夾下`*.conf`的檔案複製到container內的 `/etc/nginx/conf.d/`下 * 但此動作需要 `docker restart` 此container後,才會運作。所以只改docker volumes綁出來的外面的`./nginx/default.conf`然後再進去conatiner下`nginx -s reload`是沒有用的。 ## 架構與結果 ```mermaid flowchart TB user-->host host-->|80 port| nginx host-->|443 port| nginx nginx-->|"server listen 443\n~ /.php\nfastcgi_pass php:9000"|php subgraph container [staticfloat/nginx-certbot] nginx-->|"server listen 80\n~ /.well-known/acme-challenge/\nproxy_pass http://localhost:1337"|http-01 end nginx-->|"server listen 80\n /\nproxy_pass return 301"|host ``` * 整體架構如上圖: - 驗證時步驟: 1. 內部依照腳本產生localhost port 1337的偵聽,並回應**vaildation response** 2. 外部user(certbot)查詢進去 http://YOUR_DOMAIN/.well-known/acme-challenge/xxxxxxxxxxxxxxxxxxxxxxxxxxxxx 3. 裡面被nginx proxy_pass 到container內的1337 port取得**vaildation response** 4. 驗證成功,內部自行更新憑證,內部自行重啟nginx - 一般瀏覽行為80port: 1. 外部use瀏覽進去 http://YOUR_DOMAIN/ 2. 裡面被nginx return 301 到https - 一般瀏覽行為443port: 1. 外部use瀏覽進去 https://YOUR_DOMAIN/ 3. 裡面被nginx fastcgi_pass 到container php:9000