DEV Community

Cover image for ⚙️ Part 2: Host Your React App & API with NGINX — Step-by-Step Guide
Vishwark
Vishwark

Posted on

⚙️ Part 2: Host Your React App & API with NGINX — Step-by-Step Guide

“You’ve learned what NGINX is — now let’s use it to serve your React app and connect it to your backend!”


🧭 Quick Recap from Part 1

In Part 1, we learned:

  • What NGINX is
  • Why frontend devs should care
  • How it works internally (master/worker model)
  • Where it fits in a React deployment

Now it’s time to get hands-on 💻


🎯 What You’ll Build

We’ll:

  1. Install NGINX locally
  2. Serve a React build folder (build/ or dist/)
  3. Fix React Router 404 issues
  4. Proxy /api requests to a Node.js backend

Here’s the setup we’re aiming for 👇

Browser → NGINX (port 80)
        ├── Serves React build (/)
        └── Proxies API → Node (port 5000)
Enter fullscreen mode Exit fullscreen mode

🧰 Step 1: Install NGINX

🧩 On macOS (Homebrew)

brew install nginx
Enter fullscreen mode Exit fullscreen mode
  • Default config: /usr/local/etc/nginx/nginx.conf
  • Default port: 8080
  • Start server:
  brew services start nginx
Enter fullscreen mode Exit fullscreen mode

🧩 On Ubuntu/Debian (Linux)

sudo apt update
sudo apt install nginx -y
Enter fullscreen mode Exit fullscreen mode
  • Default config: /etc/nginx/nginx.conf
  • Default root: /var/www/html
  • Default port: 80
  • Test: 👉 Visit http://localhost

If you see “Welcome to NGINX!” — 🎉 it’s working!


⚙️ Step 2: Build Your React App

In your project folder:

npm run build
Enter fullscreen mode Exit fullscreen mode

This creates a build/ folder (or dist/ for Vite).

Now copy it to NGINX’s web root:

macOS:

sudo cp -r build/* /usr/local/var/www/
Enter fullscreen mode Exit fullscreen mode

Linux:

sudo cp -r build/* /var/www/html/
Enter fullscreen mode Exit fullscreen mode

⚠️ Step 3: Fix React Router 404s

If you refresh /about or /dashboard, you’ll see a 404 Not Found.
That’s because NGINX tries to find an /about file — which doesn’t exist in your static build.

The fix is simple: tell NGINX to fall back to index.html.

Edit your NGINX config file:

macOS

sudo nano /usr/local/etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

Linux

sudo nano /etc/nginx/sites-available/default
Enter fullscreen mode Exit fullscreen mode

Update the server block:

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri /index.html;
    }
}
Enter fullscreen mode Exit fullscreen mode

Then test & reload:

sudo nginx -t
sudo nginx -s reload
Enter fullscreen mode Exit fullscreen mode

Now /about, /profile, etc. will all load correctly 🎉


🔁 Step 4: Add Reverse Proxy for API

Let’s connect your frontend to your backend — for example, a Node/Express server running on port 5000.

Add this inside the same server {} block:

# Proxy API requests
location /api/ {
    proxy_pass http://localhost:5000/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
}
Enter fullscreen mode Exit fullscreen mode

🧩 What’s Happening Here

Directive Purpose
location /api/ Catch all /api requests
proxy_pass Forward them to backend
proxy_set_header Maintain client connection details
proxy_cache_bypass Avoid caching for development

Now your React app can call:

fetch('/api/users')
Enter fullscreen mode Exit fullscreen mode

instead of:

fetch('http://localhost:5000/api/users')
Enter fullscreen mode Exit fullscreen mode

No more CORS headaches 🚫🎉


🧪 Step 5: Test It

  1. Run your backend:
   node server.js
Enter fullscreen mode Exit fullscreen mode

(Make sure it listens on port 5000)

  1. Visit your app:
   http://localhost
Enter fullscreen mode Exit fullscreen mode
  1. Open browser dev tools → Network tab You should see /api/... calls going through NGINX.

🔒 Bonus: Add HTTPS Locally (Optional)

You can self-sign a certificate for local HTTPS testing:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/nginx-selfsigned.key \
-out /etc/ssl/certs/nginx-selfsigned.crt
Enter fullscreen mode Exit fullscreen mode

Then add this to your config:

listen 443 ssl;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
Enter fullscreen mode Exit fullscreen mode

Now your app will load under https://localhost.


Final Config Recap

Here’s your complete working config for React + API:

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.html;

    # React SPA
    location / {
        try_files $uri /index.html;
    }

    # API Proxy
    location /api/ {
        proxy_pass http://localhost:5000/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Enter fullscreen mode Exit fullscreen mode

🧭 Coming Next: Speed & Scale

In Part 3, we’ll:

  • Enable gzip compression
  • Add browser caching for static assets
  • Secure your app with HTTP headers
  • Scale your backend using load balancing

Here’s what’s coming 👇

Browser → NGINX
          ├─ gzip + cache
          ├─ API proxy
          └─ Multiple backend servers (load balanced)
Enter fullscreen mode Exit fullscreen mode

Summary

Step Description
1 Install NGINX
2 Build & copy React files
3 Fix React Router with try_files
4 Add reverse proxy for backend APIs
5 Test locally
You now have a working frontend + backend behind NGINX!

🧭 Next: Part 3 — Supercharge Your React App with NGINX Caching & Load Balancing


💬 Closing Thought

“Once you proxy your React app and API through NGINX,
you’re no longer just a frontend dev — you’re a full-stack deployer.”


Top comments (0)