根本原因是Docker容器以PID 1进程的生命周期为准,Nginx默认daemon on会fork后退出,导致PID 1(如bash)终止而容器退出;daemon off使其前台运行并占据PID 1,保持容器持续运行。

在 Docker 中运行 Nginx 时,必须显式指定 daemon off,否则容器启动后会立即退出。根本原因在于:Docker 的生命周期完全由 PID 1 进程决定——该进程终止,容器即停止。
容器不是虚拟机,它只管一个前台主进程
Docker 容器的设计哲学是“one container, one process”。它不提供 init 系统或进程管理器,也不后台托管子进程。当容器启动,Docker 把你指定的命令作为 PID 1 运行;只要这个进程退出,无论其他服务是否还在工作,容器都会被强制终止。
Nginx 默认以守护进程(daemon on)模式启动:它 fork 出 worker 子进程后,主进程立刻 detach 并退出。此时如果直接执行 nginx,PID 1 是 shell 或 entrypoint 脚本,它启动 Nginx 后就完成了自己的任务,随即退出 → 容器瞬间关闭。
daemon off 让 Nginx 自己变成 PID 1
nginx -g "daemon off;" 的作用是禁用守护进程模式,让 Nginx 主进程不 fork、不 detach,而是持续运行在前台,直接占据 PID 1 的位置。
- 它不再产生后台 master + worker 的分离结构,而是以单进程阻塞方式监听端口、处理请求
- 该进程不会主动退出,除非收到 SIGTERM 或发生严重错误
- Docker 检测到 PID 1 仍在运行,就认为容器健康,保持运行状态
两种常见误配场景及后果
即使使用官方 nginx 镜像,自定义 CMD 或 entrypoint 时也极易踩坑:
-
Shell 形式 CMD(如
CMD nginx -g "daemon off;"):实际启动的是/bin/sh -c "nginx -g ...",PID 1 是 sh 进程。虽然 sh 会等待 nginx 返回,但 nginx 前台运行后不返回,sh 就一直挂起——这看似能撑住容器,但信号无法正确传递(如docker stop发送的 SIGTERM 会被 sh 截获,nginx 收不到),导致优雅终止失败 -
未加 daemon off 的自定义启动脚本(如
CMD ["sh", "start.sh"]):脚本内若只写nginx,Nginx 后台化,脚本执行完即退出 → 容器秒退;若脚本末尾没加exec nginx -g "daemon off;",也会因残留 shell 进程而干扰信号转发
正确写法与关键细节
推荐始终使用 exec 形式的 JSON 数组语法,并确保 Nginx 是真正的 PID 1:
-
CMD ["nginx", "-g", "daemon off;"]—— 最简可靠,Nginx 直接为 PID 1 -
ENTRYPOINT ["nginx"]+CMD ["-g", "daemon off;"]—— 组合灵活,适合复用镜像 - 若需前置操作(如渲染配置),脚本结尾务必用
exec nginx -g "daemon off;",用exec替换当前 shell 进程,避免多一层 wrapper
注意:daemon off 是全局指令(-g 参数指定),不能写在 nginx.conf 里——配置文件中的 daemon off; 不生效,必须通过命令行传入。


















