执行nginx -c加载同端口配置报98:Address already in use错误
我在Docker容器中运行了一台Nginx服务器,使用如下命令启动容器:
docker run --name my-custom-nginx-container -v ~/project/nginx/conf/custom.conf:/etc/nginx/custom.conf --network host -t -d nginx
我的custom.conf配置内容如下:
events { worker_connections 1024; } http { server { listen 80; location / { proxy_pass http://127.0.0.1:8081; } } }
现在每当我尝试通过容器shell或直接使用docker exec执行如下命令修改配置时:
nginx -c /etc/nginx/custom.conf
我始终会收到如下报错:
2022/05/19 19:53:16 [emerg] 23#23: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 2022/05/19 19:53:16 [notice] 23#23: try again to bind() after 500ms 2022/05/19 19:53:16 [emerg] 23#23: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 2022/05/19 19:53:16 [notice] 23#23: try again to bind() after 500ms 2022/05/19 19:53:16 [emerg] 23#23: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 2022/05/19 19:53:16 [notice] 23#23: try again to bind() after 500ms 2022/05/19 19:53:16 [emerg] 23#23: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 2022/05/19 19:53:16 [notice] 23#23: try again to bind() after 500ms 2022/05/19 19:53:16 [emerg] 23#23: bind() to 0.0.0.0:80 failed (98: Address already in use) nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 2022/05/19 19:53:16 [notice] 23#23: try again to bind() after 500ms 2022/05/19 19:53:16 [emerg] 23#23: still could not bind() nginx: [emerg] still could not bind()
我已确认没有其他进程占用该端口,执行sudo lsof -i :80返回结果如下:
nginx 13098 root 7u IPv4 171510 0t0 TCP *:80 (LISTEN) nginx 13126 systemd-resolve 7u IPv4 171510 0t0 TCP *:80 (LISTEN)
该问题的成因是什么?是否是Docker特有的问题?(我在Ubuntu 22.04上运行Docker,同操作在macOS本地安装的Nginx上可正常执行)
问题更新
我注意到仅当新旧配置监听相同端口时才会出现该报错,本地安装的Nginx也会复现该问题,因此并非Docker特有问题。核心疑问为:
是否可以通过
nginx -c命令加载与原有配置监听相同端口的新配置?
答案
不能直接在已有Nginx进程运行时,通过nginx -c加载监听相同端口的新配置,核心原因如下:
nginx -c <配置路径>的本质是启动一个全新的Nginx主进程,让新进程加载指定路径的配置,而非给正在运行的Nginx进程下发重载配置的指令。新进程启动时会按照配置尝试绑定对应端口,此时原有Nginx进程已经占用了该端口,自然会抛出Address already in use错误,和容器、操作系统环境无关。- 之前执行
lsof看到80端口已经被Nginx进程占用,就是这个报错的直接来源。
正确的配置加载操作按场景选择即可:
- 如果只是修改当前Nginx正在使用的配置内容,不需要切换配置文件路径:修改配置后先执行
nginx -t校验配置语法是否正确,确认无误后执行nginx -s reload,给运行中的Nginx主进程发送重载信号即可。Nginx会平滑启动新的worker进程加载新配置,再逐步关停旧worker进程,全程不会出现端口冲突,也不会中断正在处理的请求。 - 如果需要切换Nginx加载的配置文件路径(比如从默认的
/etc/nginx/nginx.conf切换到自定义的/etc/nginx/custom.conf),有两种可选方案:- 先执行
nginx -s stop关停当前运行的Nginx进程,再执行nginx -c /etc/nginx/custom.conf用新配置启动Nginx,该方式会有短暂的服务中断。 - 通过Nginx平滑升级流程启动新主进程加载新配置,实现无中断切换,该流程操作相对复杂,仅适合生产环境不允许停服的场景,普通测试、开发环境直接停启即可。
- 先执行
补充Docker场景的注意点:官方Nginx镜像启动时会默认加载内置配置启动Nginx进程,容器启动后直接执行nginx -c本质是重复启动Nginx进程,必然触发端口冲突。如果要让容器启动时就加载自定义配置,应该在启动容器时将自定义配置挂载到镜像默认的配置路径,或者修改容器启动命令指定启动时加载的配置文件,不要等容器启动后再手动执行nginx -c。
内容的提问来源于stack exchange,提问作者johny.bravo
相关产品推荐
相关产品推荐

