使用Dockerfile+Github Actions部署至Nginx时端口占用问题排查
问题:Docker部署时端口80被占用,无法与Nginx共存
我正尝试通过Nginx,使用Dockerfile和Github Actions进行应用部署,却遇到如下错误:
Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use.
停止服务器上的Nginx后即可部署,但我需要Nginx保持运行状态,请问我哪里操作有误?
我的Dockerfile内容
FROM node:20-alpine WORKDIR /app COPY package*.json yarn.lock ./ RUN yarn COPY . . EXPOSE 8081 CMD [ "yarn", "start" ]
我的Github Actions文件内容
name: Deploy to DigitalOcean on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4.0.0 - name: Set up Docker uses: docker/setup-buildx-action@v2.10.0 - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push image to Docker Hub uses: docker/build-push-action@v4.2.1 with: context: . push: true tags: ${{ secrets.DOCKERHUB_USERNAME }}/example:${{ github.sha }} build-args: | NODE_VERSION=20 - name: Deploy to DigitalOcean Droplet uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.DROPLET_IP }} username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} port: 22 script: | echo "Pulling Docker image..." docker pull ${{ secrets.DOCKERHUB_USERNAME }}/example:${{ github.sha }} echo "Stopping and removing existing container (if it exists)..." if docker ps -a | grep -q "example-container"; then docker stop example-container docker rm example-container fi echo "Starting a new container..." docker run -d --name example-container -p 80:8081 ${{ secrets.DOCKERHUB_USERNAME }}/example:${{ github.sha }}
我的Nginx配置文件(/etc/nginx/sites-available/example.com)内容
server { root /var/www/example.com/html; index index.html index.htm index.nginx-debian.html; server_name example.com www.example.com; location / { try_files $uri $uri/ =404; proxy_pass http://localhost:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = www.example.com) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = example.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name example.com www.example.com; return 404; # managed by Certbot }
问题原因及解决方案
问题原因
你在Docker启动命令里把容器的8081端口映射到了主机的80端口(-p 80:8081),但主机上的Nginx已经在监听80端口处理HTTP请求(第二个server块明确配置了listen 80),两者端口冲突导致Docker启动失败。
解决方案
方案1:修改Docker端口映射,避开80端口
把Docker的端口映射改成主机的其他空闲端口,比如8080,再调整Nginx的反向代理指向这个新端口:
- 更新Github Actions里的Docker启动命令:
docker run -d --name example-container -p 8080:8081 ${{ secrets.DOCKERHUB_USERNAME }}/example:${{ github.sha }} - 修改Nginx配置中的
proxy_pass:proxy_pass http://localhost:8080; - 重启Nginx生效:
sudo systemctl restart nginx
方案2:Docker容器与Nginx同网络,用容器名直接通信(推荐)
这种方式不需要暴露主机端口,安全性更高:
- 创建一个Docker网络:
docker network create nginx-network - 修改Docker启动命令,加入网络并去掉主机端口映射:
docker run -d --name example-container --network nginx-network ${{ secrets.DOCKERHUB_USERNAME }}/example:${{ github.sha }} - 修改Nginx配置中的
proxy_pass,直接用容器名访问:proxy_pass http://example-container:8081; - 重启Nginx和容器:
sudo systemctl restart nginx docker restart example-container
额外注意事项
你当前Nginx配置里try_files $uri $uri/ =404;在proxy_pass之前,会优先从本地/var/www/example.com/html读取静态文件。如果你的应用静态文件都在Docker容器里,需要删除root和try_files相关配置,或者调整顺序让代理优先。
内容的提问来源于stack exchange,提问作者kar
相关产品推荐
相关产品推荐

