docker compose restart 不会应用端口变更,因其仅重启旧容器而不重建,端口映射等配置在创建时已固化;必须使用 docker compose up -d 重建容器才能生效。

docker compose restart 不会应用端口变更
改了 docker-compose.yml 里的 ports 字段后执行 docker compose restart,端口映射完全不会更新——容器还是用旧的网络配置在跑,新端口根本没暴露,请求直接超时或被拒绝。
这是因为 restart 只是向已有容器发 SIGTERM 再启动它,不重建、不重读配置、不重新创建网络栈。端口映射属于容器创建时的静态定义,运行中不可变。
- 常见错误现象:改完
- "8443:443"后 curl 8443 没响应,docker ps里仍显示0.0.0.0:443->443/tcp - 验证方式:
docker inspect 容器名 | jq '.[0].HostConfig.PortBindings',输出和你刚改的ports不一致就说明没生效 - 别指望
docker compose up -d --no-deps或加--force-recreate单独骗过它——只要不是完整重建,端口就不会动
必须用 docker compose up -d 重建容器
docker compose up -d 是唯一可靠的方式:它会检测 docker-compose.yml 变更,自动 stop 旧容器、删除、再 create 新容器,并把新 ports 绑定进去。数据卷(如 caddy_data)默认保留,证书和配置不会丢。
- 执行前确认:检查
volumes是否已声明为命名卷(如caddy_data:),否则挂载路径可能被清空 - 如果用了绑定挂载(
./caddy_data:/var/lib/caddy),确保宿主机路径存在且权限正确,否则容器启动失败 - HTTP/3 需要额外声明 UDP 端口:
- "443:443/udp"必须和 TCP 行一起存在,缺一不可
端口改错会导致 Caddy ACME 失败
FrankenPHP 依赖 Caddy 自动申请 HTTPS 证书,而 Let's Encrypt 的 HTTP-01 和 TLS-ALPN-01 验证都强依赖端口可达性。如果只开放了 8443 但没开 80 或 443,或者安全组/防火墙没同步更新,ACME 流程会卡在验证环节,日志里反复出现 acme: Error -> could not determine the domain's IP 或 timeout during validation。
立即学习“PHP免费学习笔记(深入)”;
- 生产环境必须放行
80(HTTP)和443(HTTPS/TCP+UDP),哪怕你只想用 8443 ——Caddy 默认仍会尝试 80 端口重定向和 ACME 回调 - 阿里云/腾讯云等厂商的安全组修改后,需手动点击“应用”或等待几秒才生效,别改完就立刻测试
- 本地测试可用
curl -v http://yourdomain.com/.well-known/acme-challenge/test检查 80 端口是否通,这是 ACME 最先探测的路径
重建后证书还在吗?关键看 caddy_data 是否持久化
证书本身不随容器重建丢失,但前提是 caddy_data 目录被正确挂载。FrankenPHP 容器内证书默认存在 /var/lib/caddy,若没做任何挂载,每次 up -d 都会生成全新空白目录,Caddy 只能重新走 ACME 流程——这不仅慢,还可能触发 Let's Encrypt 的速率限制(每域名每周最多 5 次失败验证)。
- 正确做法:在
docker-compose.yml中声明命名卷并挂载:services: php: volumes: - caddy_data:/var/lib/caddy volumes: caddy_data: - 验证是否生效:
docker exec -it 容器名 ls /var/lib/caddy/certificates/,应能看到域名子目录和certificate.pem - 别手贱进容器去
rm -rf /var/lib/caddy——Caddy 不会自动恢复旧证书,只会申请新的,浏览器可能报“证书不被信任”(staging 环境证书)
容器重建本身不危险,危险的是以为改了配置就万事大吉。最常被忽略的,是安全组端口没同步、caddy_data 挂载路径写错、以及把 restart 当成万能刷新键。



















