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
Summary of Problems
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;"]