基于Docker、Nginx、Let's Encrypt SSL及Supervisor部署Laravel的最佳方案
针对你的场景(Azure ACI部署Laravel单容器镜像,避免因证书申请重构镜像),以下是三种可行方案,按推荐度排序:
方案一:Certbot侧车容器(最适合ACI场景)
利用ACI支持多容器部署的特性,保留原有Laravel+Nginx镜像作为主容器,新增一个Certbot侧车容器专门负责证书的申请、更新,证书文件存储在ACI共享卷中,主容器通过挂载卷读取证书。
具体步骤:
修改Nginx配置
更新你的nginx.conf,添加SSL监听和ACME挑战路径配置,证书路径指向共享卷(比如/etc/letsencrypt):server { listen 80; server_name your-domain.com; # ACME挑战路径,用于Let's Encrypt验证 location /.well-known/acme-challenge/ { root /var/www/html; try_files $uri =404; } # 重定向HTTP到HTTPS location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # Laravel核心路由配置 location / { try_files $uri $uri/ /index.php?$query_string; } # PHP-FPM转发配置 location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }ACI多容器部署配置
在ACI的部署yaml中定义两个容器,共享同一个Azure文件共享卷:apiVersion: 2021-07-01 location: eastus name: laravel-aci-deployment properties: containers: - name: laravel-app properties: image: your-acr-name.azurecr.io/laravel-image:latest ports: - port: 80 - port: 443 volumeMounts: - name: cert-volume mountPath: /etc/letsencrypt - name: cert-volume mountPath: /var/www/html/.well-known resources: requests: cpu: 1.0 memoryInGB: 1.5 - name: certbot properties: image: certbot/certbot:latest command: ["certonly", "--webroot", "-w", "/var/www/html", "-d", "your-domain.com", "--email", "your-email@example.com", "--agree-tos", "--non-interactive", "--keep-until-expiring"] volumeMounts: - name: cert-volume mountPath: /etc/letsencrypt - name: cert-volume mountPath: /var/www/html resources: requests: cpu: 0.5 memoryInGB: 0.5 volumes: - name: cert-volume azureFile: shareName: cert-share storageAccountName: your-storage-account storageAccountKey: your-storage-key ipAddress: type: Public dnsNameLabel: your-dns-label ports: - port: 80 - port: 443 osType: Linux- 首次部署后,Certbot会自动申请证书并存储到共享卷
- 后续可将Certbot容器的命令改为自动更新:
["renew", "--webroot", "-w", "/var/www/html", "--non-interactive"],通过ACI重启策略或外部定时任务触发更新
调整Supervisor配置
确保主容器的Supervisor仅管理PHP-FPM,Nginx通过启动脚本启动(需等证书存在后再加载SSL配置)。
方案二:Azure Key Vault + 自动化证书同步
如果不想引入侧车容器,可将Let's Encrypt证书托管在Azure Key Vault,通过ACI的密钥挂载功能将证书挂载到容器中,再用自动化工具定期更新证书。
具体步骤:
申请并导入证书到Key Vault
- 在本地或临时容器中用Certbot申请证书:
certbot certonly --standalone -d your-domain.com - 将证书文件(fullchain.pem、privkey.pem)合并为PFX格式,导入Azure Key Vault
- 在本地或临时容器中用Certbot申请证书:
ACI挂载Key Vault证书
在ACI部署配置中添加Key Vault卷挂载,将证书挂载到容器的/etc/letsencrypt路径:volumes: - name: cert-volume secret: secretName: your-cert-secret sourceVault: id: /subscriptions/your-sub-id/resourceGroups/your-rg/providers/Microsoft.KeyVault/vaults/your-vault自动化证书更新
- 使用Azure Function编写定时任务,每月调用Certbot更新证书,转换为PFX格式后上传到Key Vault
- ACI会自动刷新挂载的证书(需重启容器或利用Key Vault的自动同步机制)
方案三:容器启动脚本动态获取证书(不推荐)
不修改镜像,但在容器启动时执行Certbot证书检查和申请逻辑,需挂载持久卷保存证书避免重复申请(注意Let's Encrypt的速率限制)。
具体步骤:
修改启动脚本
创建start.sh替换原CMD命令,脚本内容:#!/bin/sh # 检查证书是否存在 if [ ! -f /etc/letsencrypt/live/your-domain.com/fullchain.pem ]; then # 安装Certbot并申请证书 apt-get update && apt-get install -y certbot certbot certonly --webroot -w /var/www/html -d your-domain.com --email your-email@example.com --agree-tos --non-interactive fi # 启动Nginx和Supervisor service nginx start /usr/bin/supervisord -c /etc/supervisor/supervisord.conf挂载持久卷
在ACI部署中挂载Azure文件共享卷到/etc/letsencrypt,确保证书在容器重启后保留。添加定时更新任务
在Supervisor配置中添加cron任务,每月执行certbot renew命令更新证书。
内容的提问来源于stack exchange,提问作者iamsubingyawali

