Docker 容器通常不直接處理 SSL——前面的反向代理負責終結 TLS 並將解密後的流量轉發給容器。本指南涵蓋三種最常見的方案。
方案一:Nginx 反向代理 + 手動證書
最適合小型部署的簡單方案。從 GetHTTPS 獲取證書並掛載到 Nginx 容器中。
docker-compose.yml
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs/fullchain.pem:/etc/ssl/fullchain.pem:ro
- ./certs/privkey.pem:/etc/ssl/privkey.pem:ro
depends_on:
- app
app:
image: your-app:latest
expose:
- "3000"
nginx.conf
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://app:3000;
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 $scheme;
}
}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
續簽方式: 用來自 GetHTTPS 的新檔案替換 ./certs/ 中的檔案,然後執行 docker compose exec nginx nginx -s reload。
方案二:Traefik 自動獲取 Let’s Encrypt
Traefik 是為容器構建的反向代理,可以自動獲取和續簽 Let’s Encrypt 證書。
docker-compose.yml
services:
traefik:
image: traefik:v3.0
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.email=you@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/acme/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-acme:/acme
app:
image: your-app:latest
labels:
- "traefik.http.routers.app.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=3000"
volumes:
traefik-acme:
Traefik 處理一切:證書籤發、續簽和 HTTPS 終結。無需手動管理證書。
方案三:Caddy(零配置 HTTPS)
Caddy 自動獲取和續簽 Let’s Encrypt 證書,完全零配置。
docker-compose.yml
services:
caddy:
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
depends_on:
- app
app:
image: your-app:latest
expose:
- "3000"
volumes:
caddy-data:
Caddyfile
yourdomain.com {
reverse_proxy app:3000
}
這就是全部配置。Caddy 會獲取 Let’s Encrypt 證書並自動續簽。
如何選擇?
| Nginx + 手動證書 | Traefik | Caddy | |
|---|---|---|---|
| 配置難度 | 中等(配置 + 證書檔案) | 中等(標籤配置) | 極簡 |
| 自動續簽 | ❌(手動) | ✅ | ✅ |
| 靈活性 | 高 | 高 | 中等 |
| 學習曲線 | 低(熟悉) | 中等 | 低 |
| 最適合 | 小型部署,完全控制 | 動態容器,微服務 | 簡單站點,最少配置 |
Docker 中的證書續簽
方案一(Nginx + 手動):
# Replace cert files in your local ./certs/ directory
cp new-fullchain.pem ./certs/fullchain.pem
cp new-privkey.pem ./certs/privkey.pem
# Reload Nginx inside the container (no restart needed)
docker compose exec nginx nginx -s reload
方案二(Traefik)和方案三(Caddy):
自動處理——它們在內部管理續簽。證書儲存在 Docker 卷(traefik-acme 或 caddy-data)中,在容器重啟後仍然保留。
Docker Swarm:使用 secrets
對於 Docker Swarm 部署,使用 Docker secrets 代替繫結掛載證書檔案:
# Create secrets from your cert files
docker secret create ssl_cert fullchain.pem
docker secret create ssl_key privkey.pem
# In docker-compose.yml (deploy mode)
services:
nginx:
image: nginx:alpine
secrets:
- ssl_cert
- ssl_key
configs:
- source: nginx_conf
target: /etc/nginx/conf.d/default.conf
secrets:
ssl_cert:
external: true
ssl_key:
external: true
Secrets 在容器內掛載到 /run/secrets/ssl_cert 和 /run/secrets/ssl_key——靜態和傳輸中都加密。
常見錯誤
將證書打包進 Docker 映象
# ❌ NEVER do this
COPY fullchain.pem /etc/ssl/fullchain.pem
COPY privkey.pem /etc/ssl/privkey.pem
證書每 90 天過期一次。打包進映象意味著每 60 天就要重新構建和重新部署。始終以卷或 secrets 方式掛載證書。
忘記暴露埠 80
埠 80 用於:
- HTTP → HTTPS 重新導向
- Let’s Encrypt HTTP-01 驗證(Traefik/Caddy 自動續簽需要)
ports:
- "80:80" # Don't forget this
- "443:443"
未持久化 ACME 資料
Traefik 和 Caddy 將 Let’s Encrypt 證書和賬戶金鑰儲存在卷中。沒有持久化,它們會在每次容器重啟時重新請求證書——並觸發速率限制:
volumes:
traefik-acme: # MUST be a named volume, not anonymous
caddy-data:
常見問題
應用容器可以直接處理 SSL 嗎?
可以,但不推薦。反向代理模式(在邊緣終結 TLS,內部轉發明文 HTTP)是標準做法,因為:應用不需要知道證書的事情,續簽不需要重啟應用,而且你可以集中管理 TLS 配置。
如何為多個容器配置 SSL?
使用 Traefik 或 Caddy 時,為每個服務新增標籤/配置——它們會自動獲取各自的證書。使用 Nginx 時,在配置中新增多個 server 塊。
應該用 GetHTTPS 還是 Traefik 內建的 ACME?
生產環境推薦使用 Traefik/Caddy 內建的 ACME——它自動處理續簽。當你需要為 Nginx 反向代理方案(方案一)獲取證書,或容器沒有直接網際網路訪問無法完成 ACME 驗證時,使用 GetHTTPS。
如何在 Docker 中安全地掛載證書?
以只讀模式掛載(:ro),在 Swarm 模式下對私鑰使用 Docker secrets,確保只有反向代理容器能訪問證書檔案。永遠不要將證書打包進 Docker 映象——它們會過期,你需要重新構建。
可以在 Kubernetes 中使用 GetHTTPS 證書嗎?
可以。從 GetHTTPS 證書檔案建立 Kubernetes TLS secret:
kubectl create secret tls my-tls-cert --cert=fullchain.pem --key=privkey.pem
然後在 Ingress 資源中引用它。要在 Kubernetes 中實現自動續簽,可以考慮使用 cert-manager 配合 Let’s Encrypt ClusterIssuer。