---
# System prepended metadata

title: 關於 staticfloat/nginx-certbot 的機制說明

---

# 關於 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