如何正确配置Docker+Nginx运行Node+Mongo?本地部署问题求助
Let's walk through each of your issues and fix them one by one. I've worked through similar Docker/Nginx/Node setups many times, so here's what's going wrong and how to resolve it:
1. Node Container Can't Connect to MongoDB
Root Causes
- Your Node app is trying to connect to
127.0.0.1:27017—inside a Docker container,127.0.0.1refers to the container itself, not the Mongo container or your host machine. depends_ononly ensures the Mongo container starts before your Node container, but it doesn't wait for the Mongo service to actually be ready to accept connections.- You tried container names/IPs, but likely didn't update your connection string correctly in
.env.
Fixes
- Update your
.envMongo connection string:
Use the Docker Compose service name (mongodb) as the host—Compose automatically creates a network where service names resolve to container IPs:MONGO_URI=mongodb://mongodb:27017/wetaxitask - Add health checks to Mongo to ensure Node only starts once Mongo is ready:
Update yourdocker-compose.ymlMongo service:mongodb: container_name: wetaxitask_mongodb image: mongo:latest restart: always ports: - 27017:27017 volumes: - ./data:/data/db environment: - MONGO_INITDB_DATABASE=wetaxitask healthcheck: test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"] interval: 5s timeout: 5s retries: 5 - Make Node wait for Mongo's health check:
Update your Node service indocker-compose.yml:wetaxitask: container_name: wetaxitask_api_dev image: wetaxitask restart: always build: . depends_on: mongodb: condition: service_healthy redis: condition: service_started env_file: .env ports: - 8080:80 links: - redis - mongodb - Add reconnection logic to your Node code:
If using Mongoose, enable auto-reconnect:mongoose.connect(process.env.MONGO_URI, { autoReconnect: true, reconnectTries: Number.MAX_VALUE, reconnectInterval: 1000 });
2. Python-Related Errors
Root Cause
Your Dockerfile mixes build and production environments poorly:
- You install Python in the builder stage, but then copy the entire project to the Nginx-based production container. If your
npm starttriggers any build steps (like compiling native modules), the production container may have an incomplete Python environment. - Running both Node and Nginx in the same container violates Docker's "one process per container" best practice, leading to process management issues.
Fix
Rewrite your Dockerfile to separate build and production, and use a process manager to run both services:
# Builder Stage - handles dependencies and TypeScript compilation FROM node:12.18-alpine AS base-builder RUN apk update && apk add --no-cache python3 make g++ libc6-compat WORKDIR /usr/src/app COPY tsconfig.json package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # Adjust to your actual build script (e.g., tsc) # Production Stage - runs Node + Nginx via supervisord FROM nginx:1.19.0-alpine RUN apk add --no-cache nodejs npm supervisor WORKDIR /usr/src/app # Copy only necessary files from builder COPY --from=base-builder /usr/src/app/dist ./dist COPY --from=base-builder /usr/src/app/node_modules ./node_modules COPY --from=base-builder /usr/src/app/package*.json ./ COPY --from=base-builder /usr/src/app/.env ./ # Replace default Nginx config RUN rm /etc/nginx/conf.d/default.conf COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf # Add supervisord config to manage both processes COPY supervisord.conf /etc/supervisord.conf EXPOSE 80 3000 CMD ["supervisord", "-c", "/etc/supervisord.conf"]
Create a supervisord.conf file in your project root:
[supervisord] nodaemon=true [program:node] command=npm start directory=/usr/src/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:nginx] command=nginx -g "daemon off;" stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
3. Nginx Returns Welcome Page for All Endpoints
Root Cause
Your Nginx config only proxies requests to /welcome to your Node service—all other requests fall back to Nginx's default static files directory (/usr/share/nginx/html), which serves the welcome page.
Fix
Adjust your Nginx config based on your project type:
If you have a frontend SPA + API:
server { listen 80; root /usr/src/app/dist/client; # Path to your built frontend files index index.html index.htm; # Proxy API requests to Node location /api/ { proxy_pass http://127.0.0.1:3000/api/; 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; } # Handle SPA routing (redirects all non-static requests to index.html) location / { try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
If this is a pure API service:
server { listen 80; # Proxy all requests to Node 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; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Bonus: Better Architecture (Separate Containers)
For long-term maintainability, split Node and Nginx into separate containers. Update your docker-compose.yml:
version: '3.8' services: wetaxitask_api: container_name: wetaxitask_api_dev build: ./api # Move Node project to an /api subdirectory with its own Dockerfile restart: always depends_on: mongodb: condition: service_healthy redis: condition: service_started env_file: .env networks: - app-network mongodb: container_name: wetaxitask_mongodb image: mongo:latest restart: always ports: - 27017:27017 volumes: - ./data:/data/db environment: - MONGO_INITDB_DATABASE=wetaxitask healthcheck: test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"] interval: 5s timeout: 5s retries: 5 networks: - app-network redis: container_name: wetaxitask_redis image: redis:latest ports: - 6379:6379 networks: - app-network nginx: container_name: wetaxitask_nginx image: nginx:1.19.0-alpine restart: always ports: - 8080:80 volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf - ./client/dist:/usr/share/nginx/html # Frontend static files depends_on: - wetaxitask_api networks: - app-network networks: app-network: driver: bridge
Then update Nginx's proxy pass to use the Node service name:
proxy_pass http://wetaxitask_api:3000/api/;
内容的提问来源于stack exchange,提问作者Jakub

