React, Django. Gunicorn, nginx , docker setup for production ready and not ablet to server static files for both frontend and backend

This is the current project director for my project as of now

Project/
│── .env 
├── docker-compose.yml               # Docker Compose configuration file
│
├── Frontend/                   # React Frontend (Client-side)
│   ├── Dockerfile                   # Dockerfile for React app build
│   ├── package.json                 # React package file                     
│   ├── public/                      # Public assets for React
│   ├── src/                         # React source code
│   ├── build/                       # React build output (this is where `npm run build`                
│   ├── nginx.conf 
└── Backend/                    # Django Backend (Server-side)
    ├── Dockerfile                   # Dockerfile for Django app build
    ├── manage.py                    # Django manage.py file
    ├── Backend/                 # Django application code (models, views, etc.)
    ├── requirements.txt            
    ├── static/                       # Static files (collected by `collectstatic`)
    ├── media/                        # Media files (user-uploaded files)
    └── .dockerignore                 # Docker ignore file

i have this directory structure where i have 2 folders for backend and front end each is build with Django and react respectively and i have the nginx file in the frontend directory to copy the first build in the frontend container but the thing is that i also share the same volume with the django also but nginx is not ablet to server sttic files to django as well get 404 not found error with nginx as the files are not in the containers but they are mounted with the backend folder volumes.

this below is the yml file i use which uses the shared volume with backend and the build of react

version: "3.8"

services:
  st_mysql_db:
    image: mysql:8.0
    container_name: st_mysql_db
    env_file:
      - .env
    environment:
      MYSQL_ROOT_PASSWORD: '${MYSQL_DB_ROOT_PASSWORD}'
      MYSQL_DATABASE: '${MYSQL_DATABASE_NAME}'
    volumes:
      - st_mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - st_network
    restart: always
    healthcheck:
      test: [
        "CMD", 
        "mysqladmin", "ping", 
        "-h", "localhost", 
        "-u", "root", 
        "-p${MYSQL_DB_ROOT_PASSWORD}", 
        "--silent"
      ]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
    command: ["docker-entrypoint.sh", "mysqld"]

  st_backend:
    build:
      context: ./Backend
      dockerfile: Dockerfile
    container_name: st_backend
    volumes:
      - ./Backend:/app
      - ./Backend/media:/app/media
      - ./Backend/static:/app/static 
    env_file:
      - .env
    #environment:
      #- DATABASE_URL=mysql://root:${MYSQL_DB_ROOT_PASSWORD}@steno_mysql_db:3306/st_db
    ports:
      - "8000:8000"
    depends_on:
      - st_mysql_db
    networks:
      - st_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/admin/"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
    command: >
       bash -c "
          /wait-for-it.sh st_mysql_db:3306 --timeout=60 -- \
          
          # Run makemigrations for the accounts app first
          python manage.py makemigrations accounts && \
          
      
          # Run migrations for any other apps
          python manage.py migrate --noinput && \

          # Run migrations for any other apps
          python manage.py collectstatic --noinput && \
          
          # Start the gunicorn server
          gunicorn --bind 0.0.0.0:8000 Backend.wsgi:application"

    restart: always

  stfrontend:
    build:
      context: ./Frontend
      dockerfile: Dockerfile
    container_name: st_frontend
    env_file:
      - .env
    depends_on:
      - st_backend
      
    networks:
      - st_network
    volumes:
      - ./Backend/static:/usr/share/nginx/html/static  # Map Django static files to NGINX
      - ./Backend/media:/usr/share/nginx/html/media  # Map Django media files to NGINX
    
    restart: always
    ports:
      - "80:80"  # NGINX will serve frontend on port 80
    command: ["nginx", "-g", "daemon off;"]  # Directly run NGINX in the container


networks:
  st_network:
    driver: bridge

volumes:
  st_mysql_data:
  st_backend_data:

This is the docker file for both front end and backend

frontend

# Stage 1: Build the React app
FROM node:14-slim AS builder

WORKDIR /app

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

# Install dependencies
RUN npm install

# Copy all files to the working directory
COPY . .

# Build the React app for production
RUN npm run build

# Stage 2: Serve the React app with NGINX
FROM nginx:alpine



# Copy custom NGINX configuration file from the parent directory
COPY ./nginx.conf /etc/nginx/nginx.conf 

# Copy the React build output to NGINX's HTML directory
COPY --from=builder /app/build /usr/share/nginx/html




# Set the correct permissions for NGINX to access files
RUN chown -R nginx:nginx /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html


# Set the correct ownership for other NGINX critical files
RUN chown -R nginx:nginx /var/cache/nginx /var/log/nginx /etc/nginx/conf.d

# Ensure that NGINX serves the index.html file
# In the NGINX configuration file, the directory index needs to be set correctly.
# The default NGINX configuration should already include this, but we can enforce it.
RUN echo 'server { listen 80; location / { root /usr/share/nginx/html; index index.html index.htm; } }' > /etc/nginx/conf.d/default.conf

# Expose port 80
EXPOSE 80

this is the docker file for backend

# Stage 1: Build stage using a full Python image
FROM python:3.9 as builder

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt ./ 

# Install dependencies and set up virtual environment
RUN apt-get update && apt-get install -y libmariadb-dev curl bash \
    && python -m venv /opt/venv \
    && /opt/venv/bin/pip install --no-cache-dir -r requirements.txt

# Stage 2: Final slim image
FROM python:3.9-slim

# Install dependencies needed for mysqlclient, bash, and curl
RUN apt-get update && apt-get install -y libmariadb-dev curl bash

# Set the working directory in the container
WORKDIR /app

# Copy the virtual environment from the builder stage
COPY --from=builder /opt/venv /opt/venv

# Copy the application code into the container
COPY . . 

# Download the wait-for-it.sh script directly from GitHub
RUN curl -sSL https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -o /wait-for-it.sh && chmod +x /wait-for-it.sh

# Ensure the PATH includes the virtual environment
ENV PATH="/opt/venv/bin:$PATH"


# Expose the application port (adjust as necessary)
EXPOSE 8000

# Command to run the server with wait-for-it.sh to ensure DB is ready
#CMD ["/wait-for-it.sh", "steno_mysql_db:3306", "--timeout=60", "--", "bash", "-c", "python manage.py makemigrations && python manage.py migrate && gunicorn --bind 0.0.0.0:8000 app.wsgi:application"]

and this is the configuration for nginx.conf

worker_processes 1;

events {
    worker_connections 1024;
}

# Main NGINX configuration block
http {
    # Include any additional configurations (if needed)
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # Log configuration
   access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
    

    # Server block for handling HTTP requests
    server {
        listen 80;
        server_name localhost;  # This will match any domain, acting as a catch-all

        # These directives should be outside the location block
            root /usr/share/nginx/html;  # Define the root directory for all requests
            index index.html;  

        # Frontend
        location / {
        
            try_files $uri /index.html;   # Rewrites any missing route to index.html
        }


        location /static/ {
        alias /usr/share/nginx/html/static/;

       
        autoindex on;
        }

        # Serve media files for Django (if you use them)
        location /media/ {
            alias /usr/share/nginx/html/media/;  # Serve media files from shared volume
            autoindex on;
        }


        # Backend API
        location /api/ {
            proxy_pass http://steno_backend:8000/;  # Proxy to Django backend
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        # Serve static files for Django from the shared volume
    
    }
}

this is my setting file for media and static when debug is False

STATIC_URL = 'static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')

# Media files (uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

with this configuration what i want to do is that when i do the collect static in the backend container so the files are storing in the directory but as the volume is shared the nginx is not ablet to server those files and also not able to serve even the react files which are there in the html folder of nginx. and also one thing is that when i do the make migrations and migrate i use the customuser model and i have added the reference in the setting file still when i directly use the

python manage.py make migrations

it shows ok and then migrate it shows the not able to reference things so it goes wrong so because of that i have to do the separate migrations for accounts and then the migrate to apply all other migrations . how can i solve this problem when i am suppose to use the R2 Service form the Cloudflare and the rds form the aws so please help me with this .

if you find any problem with the yml or any configuration please point it out for better use and also suggest the production ready setup for this above configurations.

Вернуться на верх