React Production Deployment Standards (VPS + Nginx)
A production-grade guide for deploying React applications on Ubuntu-based VPS/VPCs using Nginx—covering secure builds, gzip compression, static asset caching, and SPA routing.
🚀 Deploying a React.js Application on a VPS/VPC Using Nginx (Ubuntu)
This step-by-step guide explains how to deploy a production-ready React.js application on a VPS/VPC running Ubuntu using Nginx.
📌 Prerequisites
-
A VPS/VPC running Ubuntu
-
A React project (CRA or Vite)
-
Valid SSH authentication to the server (valid user)
-
Nginx installed (or install during steps)
-
Optional: A domain name
Step-01: Build the Project
Generate a production build:
yarn build
# or
npm run build
This creates:
-
build/(Create React App) -
dist/(Vite)
Step-02: SSH to the Remote Server
Use the below SSH command to gain access to the remote server:
ssh -p {exposed_port_number} {user}@{server_ip / domain_name}
Step-03: Update & Upgrade Packages
Update & upgrade currently installed packages in the remote server using the following command:
sudo apt update && sudo apt upgrade -y
Step-04: Create Directory for the Project
Create proper directory for the project using below command:
mkdir /home/{user}/{project_name}/frontend
Step-05: Upload or Clone Your Build Files
Option A: Clone from Git
Clone the project codebase from your Git repository (e.g. Gitea, Github etc.) to the directory using the following command:
git clone {Repository HTTPS URL}
Then run build command:
yarn build
# or
npm run build
Option B: Upload build/dist manually
Using FileZilla, upload the contents of:
-
build/(Create React App) -
dist/(Vite)
Step-06: Install Nginx (If Not Installed)
Firstly, check whether Nginx is already installed or not by using the following command:
nginx -v
If you get an output like below then skip this step.
nginx version: nginx/{version} (Ubuntu)
Otherwise, install Nginx using the following command:
sudo apt install nginx
Step-07: Create Nginx Config File
To create Nginx configuration file use the following command:
sudo nano /etc/nginx/sites-available/{project_name}-frontend
Now a text editor will appear in the console in which, the below config code has to be put in
server {
listen {port_number} ssl http2; # for IPv4, add 'ssl' if you are listening through https request, add 'http2' for faster response [MANDATORY]
listen [::]:{port_number} ssl http2; # for IPv6
server_name {server_name}; # optional: add this if you have a domain name
ssl_certificate {certificate_file_path}; # optional: if you have a certificate (e.g. /etc/letsencrypt/live/{domain_name}/fullchain.pem;)
ssl_certificate_key {certificate_key_path}; # optional: if you have a certificate (e.g. /etc/letsencrypt/live/{domain_name}/privkey.pem;)
# add this portion to enable gzipped bundle from server
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
application/json
application/javascript
text/javascript;
root {path_of_index.html_file}; # e.g. /home/{user}/{project_name}/frontend/
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Static assets with long cache
location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Don't cache HTML
location ~* .html$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
}
Save & exit:
Ctrl + S, then Ctrl + X
Step-08: Create Symbolic Link
Create symbolic link to the Nginx configuration file using the following command:
sudo ln -s /etc/nginx/sites-available/{project_name}-frontend /etc/nginx/sites-enabled/
After that, check whether the nginx service is running properly or not using the following command:
sudo nginx -t
If there are any errors in the response, check it using the following command and try to solve the errors:
sudo tail -n 50 /var/log/nginx/error.log
Step-09: Restart the Nginx Service
Now if everything is good till now, restart the Nginx server using the following command:
sudo systemctl reload nginx
sudo systemctl restart nginx
Step-10: Give Port Access Through Firewall
If you are not listening the default ports (e.g. 80 or 443) then you have to expose the port through firewall. Otherwise, browser will not be able to access the port. Use the following commands to do it:
sudo ufw allow {port_number}/tcp
sudo ufw allow {port_number}
# for reloading the firewall
sudo ufw reload
And then check the exposed port list using the below command:
sudo ufw status
🎉 Deployment Complete!
Your React.js application is now successfully deployed and accessible via Nginx on your VPS.
Let's Build Something Scalable
We apply these same engineering principles to client projects. Ready to upgrade your stack?