reactjsdockerdocker-composedeploymentfastapi

App crash when prepare to deploy using docker-compose


I have a project with two folder: frontend(react 19 with vite) and backend(fastapi), previously when in development, below are my docker and docker-compose file, and i can connect with database client in vscode

my dockerfile

FROM python:3.13-alpine
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
    PYTHONPATH=/app \
    CARGO_HOME=/root/.cargo \
    RUSTUP_HOME=/root/.rustup \
    PATH="/root/.cargo/bin:$PATH"
WORKDIR /app
# Install system dependencies for psycopg2 and build tools
RUN apk update && apk add --no-cache \
    gcc \
    musl-dev \
    libpq-dev \
    postgresql-dev \
    python3-dev \
    libffi-dev \
    cargo \
    rust \
    openssl-dev \
    make \
    curl
# Copy and install Python dependencies
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the app
COPY . /app
# Expose the port
EXPOSE 8000
# Run the application
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

and this is docker-compose after i move it to the root folder (for deploy to vps), basically i added /backend to the path

version: "3.8"

services:
  app:
    build:
      context: ./backend
      dockerfile: Dockerfile
    dns:
      - 8.8.8.8 # Google's public DNS
    container_name: fastapi-app
    env_file:
      - ./backend/.env
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - CELERY_BROKER_URL=${REDIS_URL}
      - CELERY_RESULT_BACKEND=${REDIS_URL}
    depends_on:
      - db
      - redis
    networks:
      - backend
    volumes:
      - ./backend:/app # Mount the app directory to the container for live updates
    command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload # Enable hot-reloading

  celery_worker:
    build:
      context: ./backend
      dockerfile: Dockerfile
    container_name: celery-worker
    env_file:
      - ./backend/.env
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - CELERY_BROKER_URL=${REDIS_URL}
      - CELERY_RESULT_BACKEND=${REDIS_URL}
      - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - AWS_REGION=${AWS_REGION}
      - AWS_BUCKET_NAME=${AWS_BUCKET_NAME}
    depends_on:
      - app
      - db
      - redis
    volumes:
      - ./backend:/app
    command: celery -A app.worker worker --loglevel=info
    networks:
      - backend
  db:
    image: pgvector/pgvector:pg16
    env_file:
      - ./backend/.env
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - backend

  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
    env_file:
      - ./backend/.env
    environment:
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    command: [
        "redis-server",
        "--appendonly yes",
        "--requirepass",
        "${REDIS_PASSWORD}",
      ] # Enforces Redis password
    volumes:
      - redis_data:/data
    networks:
      - backend

networks:
  backend:

volumes:
  postgres_data:
  redis_data:

docker file in react folder

# Step 1: Build the React app using Vite
FROM node:22-alpine AS build

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY frontend/package*.json ./

# Install dependencies
RUN npm install

# Copy all source code
COPY frontend/ ./

# Build the production version of the app
RUN npm run build

# Step 2: Serve the app using Nginx
FROM nginx:alpine

# Copy the build files from the build stage to Nginx's html directory
COPY --from=build /app/dist /usr/share/nginx/html

# Expose port 80 for Nginx
EXPOSE 80

# Start Nginx in the foreground
CMD ["nginx", "-g", "daemon off;"]

docker-compose for react

version: "3.8"

services:
  frontend:
    build:
      context: .
      dockerfile: frontend/Dockerfile # Referencing the Dockerfile in frontend folder
    env_file:
      - ./frontend/.env
    container_name: react-frontend
    ports:
      - "80:80" # Nginx exposes the app on port 80
    networks:
      - frontend
    depends_on:
      - app # React app depends on the backend

networks:
  frontend:

my ngix.conf

server {
    listen 80;
    
    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;  # This line handles SPA routing!
    }
    
    # API proxy configuration (if needed)
    location /api/ {
        proxy_pass http://app:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

When i am trying to test on local before push to vps, i visit to localhost:5173 and it gave me 'This site can’t be reached', but when i tried localhost:80, it can show the login page, but when i reload, it redirect to localhost/auth/login (previously localhost:5173/auth/login worked, i tried localhost:80/auth/login but no success) and show 404 not found nginx, and also i cannot connect to my postgres local anymore, my database client show Cannot not connect to server on 127.0.0.1:5432

I tried to change the host in .env for postgres from db to localhost but it doesn't work, for frontend part, i also changed the port to 5173:80 but still doesn't work


Solution

  • Summary of Problems

    1. localhost:5173 fails – That’s expected. You're no longer running Vite dev server.

    You wrote the correct nginx.conf, but you didn't add it to the Dockerfile.

    Fix: Update your Dockerfile to copy your nginx.conf:

    # Step 2: Serve the app using Nginx
    FROM nginx:alpine
    
    # Copy custom nginx config
    COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf
    
    # Copy build output
    COPY --from=build /app/dist /usr/share/nginx/html
    
    EXPOSE 80
    
    CMD ["nginx", "-g", "daemon off;"]