Skip to content

Solved

LOCALLY DEPLOYED APP CRASHED After reloading & refreshing

COPY --from=build /app/<vite_outputdir> /usr/share/nginx/html

to

COPY --from=build /app/dist/client /usr/share/nginx/html

Build and Run Container

docker build -t my-react-app .
docker run -p 3000:80 my-react-app
FROM nginx:alpine

# Copy the build folder
COPY --from=build /app/dist/client /usr/share/nginx/html

# Copy custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

ifconfig command not found [closed]

ifconfig exists in the net-tools package which may not be installed by default;

sudo yum install net-tools

When the package is installed, it will exist as /sbin/ifconfig.


Single Page Application (SPA) Routing with Nginx

The solution you're implementing is often referred to as "Single Page Application (SPA) Routing with Nginx" or "React SPA Deployment with Nginx".

Specific Names for the Concept:
  1. SPA (Single Page Application) Fallback Routing with Nginx:

    • This is the general practice of using Nginx as a reverse proxy server to handle requests and route them to the index.html of a React (or any other SPA) application. Nginx serves the static files but ensures that all non-root URL paths are directed to the index.html file, so the client-side JavaScript (React Router) can handle the routing.
  2. React Deployment on Nginx:

    • Specifically for React apps, this would refer to using Nginx as the web server to serve the built React application (index.html, JavaScript bundles, CSS, etc.) and make sure routing is handled correctly even when users refresh or directly access sub-routes.
  3. Client-Side Routing with Nginx Configuration:

    • A more precise way to describe this would be setting up a client-side routing mechanism (React Router, for example) while ensuring that Nginx handles fallback routes by redirecting all requests to the index.html file.

Why It's Needed:

In a React app (or any other SPA), routing is handled by JavaScript on the client side. When the user refreshes the page or enters a URL directly, the server might try to serve a non-existent file for that path. This happens because the server does not understand client-side routes, so you need a web server (like Nginx) to serve the index.html file for all non-root paths, allowing React Router to take over the routing once the page is loaded.

Key Components:
  • React Router: The library that enables client-side routing in your React app.
  • Nginx: A web server that serves static files and acts as a reverse proxy for handling SPA routing.

By combining React, React Router, and Nginx with this configuration, you're ensuring that the app works smoothly even when users refresh the page or try to access different routes directly via the browser.

Solution 1:

In the root of your directory, create nginx.conf file.

nginx_default.conf
server {
    listen 80;
    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}
Dockerfile
# pull official base image
#FROM node as build-step
FROM node:alpine as build

# Increase memory limit for npm install and npm run
ENV NODE_OPTIONS=--max_old_space_size=4096

# set working directory
WORKDIR /app


# add `/app/node_modules/.bin` to $PATH
#ENV PATH /app/node_modules/.bin:$PATH

# install app dependencies
COPY package.json .
COPY package-lock.json .
#RUN npm --version

#RUN npm install --legacy-peer-deps
RUN npm install react-scripts --legacy-peer-deps
# RUN npm install -g increase-memory-limit
# add app

COPY . .

##CMD ["npm","start"]

#RUN npm run product

# production environment
#FROM nginx
#COPY --from=build-step /app/build /usr/share/nginx/html
##EXPOSE 3000
#CMD ["nginx", "-g", "daemon off;"]
#product end

# start app
#RUN npm run start

#New Production Build Environment

# RUN  set NODE_OPTIONS=--max-old-space-size=16384
# RUN increase-memory-limit

#RUN npm install
#COPY . ./



##BLock Start
RUN npm run dockerbuild

FROM nginx:1.23.1-alpine as production
ENV NODE_ENV production
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY --from=build /app/build .
COPY ./nginx_default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]
builderdocker.sh
if [ -z "$1" ]
    then
        echo "***********************************************"
        echo ""
        echo "Version must be specified e.g. sh build.sh 1.0.0.0"
        echo ""
        echo "***********************************************"
        exit
fi

docker build . -f Dockerfile -t cqnovalweb/crmapp:$1
nginx.conf
server {
    listen 80;
    server_name localhost;

    # Define the root directory where static files are located
    root /usr/share/nginx/html;
    index index.html;

    # Serve index.html for all routes
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Optionally, configure caching for static files (assets like JS, CSS)
    location ~* \.(?:css|js|jpg|jpeg|png|gif|ico|svg|webp)$ {
        expires 30d;
        add_header Cache-Control "public, immutable, max-age=31536000";
    }

    # Handle 404 errors (optional)
    error_page 404 /404.html;
    location = /404.html {
        root /usr/share/nginx/html;
    }
}
# Step 1: Build the React app using pnpm and Vite
FROM node:18 AS build

# Set the working directory inside the container
WORKDIR /app

# Install pnpm globally
RUN npm install -g pnpm

# Copy package.json and pnpm-lock.yaml to install dependencies
COPY package.json pnpm-lock.yaml ./

# Install dependencies using pnpm
RUN pnpm install

# Copy the source code to the container
COPY . .

# Build the React app with Vite
RUN pnpm run build

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

# Copy the build folder from the previous step to Nginx's html directory
COPY --from=build /app/dist/client /usr/share/nginx/html

# Copy custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf


# Expose the port that Nginx is running on
EXPOSE 80

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

Which is the best method ?

Conclusion: Which is the Best Method?
  • For production environments, especially if you need to handle high traffic, require fine-grained control over routing, static asset delivery, caching, or reverse proxying, using Nginx with a custom nginx.conf is generally the best choice. It’s the industry standard for hosting static sites and SPAs and provides the best performance, scalability, and flexibility.

  • If you're looking for simplicity and a full-stack JavaScript solution, using an Express server might be ideal, particularly if your app has backend needs or if you want to consolidate everything in a single codebase.

  • For development purposes, Vite's built-in server is fantastic due to its speed and simplicity, but it should only be used in local development, not for production.

  • For zero-config deployment with automatic scaling, SSL, and edge caching, CDN and static file hosting services (e.g., Netlify, Vercel) are a great choice. They are best suited for simple applications that don't need complex backend integratio

If you're aiming for best practices and long-term scalability, the Nginx approach with proper fallback routing is the most robust solution for production. If you're looking for simplicity and a Node.js ecosystem, Express could be a great alternative.


For Shared Hosting

Login to Your Shared Hosting Control Panel (cPanel)

Most shared hosting services use cPanel for managing web hosting accounts. Here's how you can access it:

  1. Log in to your hosting account.
  2. Go to the cPanel or File Manager.
Configure.htaccess for Client-Side Routing (Optional but Recommended)

React apps, particularly Single Page Applications (SPAs), rely on client-side routing (using React Router, for example). When users refresh the page or navigate to a specific route, the server needs to always serve the index.html file.

Shared hosting servers often expect the URL path to correspond to actual files or directories. However, if you're using client-side routing in React, you’ll need to configure the server to serve the index.html file for all routes. This is done by adding a .htaccess file.

  1. In the root directory (usually public_html), create a .htaccess file (if one does not already exist).
  2. Add the following configuration to the .htaccess file to ensure proper client-side routing:
# Redirect all requests to the index.html file for React Router
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]

This configuration ensures that all requests (other than those for actual files or directories) are redirected to index.html, allowing React Router to handle the routing.

Quick Summary of Key Steps:
  1. Build the React app: npm run build (or vite build).
  2. Upload the build files: Use FTP or cPanel File Manager to upload the contents of the build or dist folder to the public_html folder.
  3. Configure .htaccess: To ensure client-side routing works, add the necessary rewrite rules.
  4. Test: Verify your app works on the shared hosting environment by checking the domain and testing routing.

Create .htaccess in the root folder where your builf file is, means in the index.html.

.htaccess
# Redirect all requests to the index.html file for React Router
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [QSA,L]