部署Node.js应用至DigitalOcean Droplet遇端口占用问题求助
我在DigitalOcean的Droplet上部署了一个简单的Node.js应用,原本运行正常。现在想给应用添加SSL证书,同时在同一Droplet上部署多个应用到不同域名,因此使用了Nginx。我已在Droplet上安装好Nginx,完成域名和SSL配置,主域名www.example.com可正常运行静态HTML文件。
但通过Github Actions部署应用时出现如下错误:
Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use.
我已按照DigitalOcean官方文档配置Nginx,请问现在该如何将Node.js应用部署到Nginx?需要修改服务器配置,还是更新Dockerfile或Actions文件?
附Dockerfile:
FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN yarn COPY . . EXPOSE 8080 CMD [ "yarn", "start" ]
附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 }}/my-app:${{ 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 }}/my-app:${{ github.sha }} echo "Stopping and removing existing container (if it exists)..." if docker ps -a | grep -q "my-app-container"; then docker stop my-app-container docker rm my-app-container fi echo "Starting a new container..." docker run -d --name my-app-container -p 80:8080 ${{ secrets.DOCKERHUB_USERNAME }}/my-app:${{ github.sha }}
1. 修复端口冲突问题
错误根源是Nginx已经占用了80端口,而你的Docker命令试图将容器8080端口映射到主机80端口,导致端口冲突。需要修改Actions中的Docker运行命令,把容器端口映射到主机的非80/443端口(比如3000),同时限制容器仅在本地回环地址监听,避免直接暴露到公网:
修改Actions中docker run行内容:
docker run -d --name my-app-container -p 127.0.0.1:3000:8080 ${{ secrets.DOCKERHUB_USERNAME }}/my-app:${{ github.sha }}
2. 配置Nginx反向代理
在Nginx配置目录(通常为/etc/nginx/sites-available/)新建对应应用域名的配置文件,比如my-app.example.com,内容如下:
server { listen 80; server_name my-app.example.com; # 重定向HTTP请求到HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl; server_name my-app.example.com; # 填写你的SSL证书路径(例如Let's Encrypt颁发的证书) ssl_certificate /etc/letsencrypt/live/my-app.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/my-app.example.com/privkey.pem; # 反向代理到Docker容器映射的本地端口 location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
执行以下命令启用配置并重启Nginx:
# 启用配置文件 sudo ln -s /etc/nginx/sites-available/my-app.example.com /etc/nginx/sites-enabled/ # 验证配置语法 sudo nginx -t # 重启Nginx生效 sudo systemctl restart nginx
3. Dockerfile无需修改
你的Dockerfile配置正常,Node应用监听8080端口的设置不需要改动——我们只是通过端口映射和Nginx反向代理实现对外服务,不影响容器内部的端口监听逻辑。
内容的提问来源于stack exchange,提问作者kar

