DEV Community

LaTerral Williams
LaTerral Williams

Posted on

πŸš€ Deploying a React App with NGINX on AWS (Amazon Linux) β€” Beginner Walkthrough

This project documents a beginner-friendly, real-world style deployment of a React application using NGINX on an AWS EC2 instance running Amazon Linux.

The goal was to:

  • Keep costs low
  • Avoid over-engineering
  • Learn how Linux + NGINX actually serve frontend apps
  • Debug real problems instead of hiding them

This walkthrough reflects the exact path taken, including lessons learned during troubleshooting.


🧠 What You’ll Learn

  • How NGINX serves a static React build
  • How to deploy a React app directly on an EC2 instance
  • Why Single Page Applications (SPAs) need special NGINX configuration
  • How to diagnose and fix common NGINX errors (500 errors, redirect loops)
  • How Node.js versions affect modern frontend tooling

πŸ’° Cost & Environment

  • Cloud Provider: AWS
  • Instance Type: t2.micro / t3.micro
  • OS: Amazon Linux 2023
  • Web Server: NGINX
  • Frontend: React (Vite)
  • Estimated Cost: Free tier or a few dollars/month

πŸ—οΈ Architecture Overview

Browser
   ↓
Public IP (EC2)
   ↓
NGINX (port 80)
   ↓
/var/www/react-app
   ↓
React build (index.html, JS, CSS)
Enter fullscreen mode Exit fullscreen mode

NGINX serves static files only. React is built first, then copied into the web root.


πŸ” Phase 1: Launch the EC2 Instance

  1. Launch a new EC2 instance
  2. Select Amazon Linux 2023
  3. Choose instance type: t2.micro or t3.micro
  4. Enable Auto-assign Public IP

Security Group (Inbound Rules)

Type Port Source
SSH 22 Your IP
HTTP 80 0.0.0.0/0

SSH is restricted. HTTP is public so the app is accessible.

Note: Do not forget to create your Key Pair and save in a location you can find later.

I used my linux desktop to connect to the instance so my key needed to be in the same directory where I was launching ssh.

If you are using an ssh tool (like Putty) you will need to upload the key into the ssh tool, so it is important to remember where you saved the key.


πŸ”‘ Phase 2: Connect to the Instance

From your local machine:

ssh -i your-key.pem ec2-user@<PUBLIC_IP>
Enter fullscreen mode Exit fullscreen mode

Amazon Linux uses the ec2-user account by default.


🧰 Phase 3: Install System Dependencies

Update packages

sudo dnf update -y
Enter fullscreen mode Exit fullscreen mode

Install NGINX

sudo dnf install -y nginx
sudo systemctl enable --now nginx
Enter fullscreen mode Exit fullscreen mode

Verify:

sudo systemctl status nginx --no-pager
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Phase 4: Install Node.js (Temporary Session)

Modern React tools require newer Node versions.

For this project, Node was upgraded for the active shell only (not persisted across reboots).

Install nvm:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

Note: I did not use this step, as I completed this in a single sitting. I only used exec bash to refresh the shell. This step may be necessary if you need the shell to persist to continue work later.

Load nvm for the current shell:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

Install and use Node 22:

nvm install 22
nvm use 22
Enter fullscreen mode Exit fullscreen mode

Verify:

node -v
npm -v
Enter fullscreen mode Exit fullscreen mode

Note: Node will revert to the system version after logout unless nvm is persisted.


βš›οΈ Phase 5: Create and Build the React App

Create the project

mkdir -p ~/projects
cd ~/projects
npm create vite@latest react-app -- --template react
cd react-app
npm install
Enter fullscreen mode Exit fullscreen mode

Build for production

npm run build
Enter fullscreen mode Exit fullscreen mode

The production-ready files are created in the dist/ directory.


πŸ“ Phase 6: Create the NGINX Web Root

Create a directory for the React app:

sudo mkdir -p /var/www/react-app
sudo chown -R ec2-user:ec2-user /var/www/react-app
Enter fullscreen mode Exit fullscreen mode

Copy the build output:

sudo rm -rf /var/www/react-app/*
sudo cp -r dist/* /var/www/react-app/
Enter fullscreen mode Exit fullscreen mode

Fix permissions so NGINX can read files:

sudo chown -R nginx:nginx /var/www/react-app
sudo chmod -R 755 /var/www/react-app
Enter fullscreen mode Exit fullscreen mode

🌐 Phase 7: Configure NGINX for React (SPA Routing)

Create the NGINX configuration:

sudo nano /etc/nginx/conf.d/react-app.conf
Enter fullscreen mode Exit fullscreen mode

Paste:

server {
    listen 80 default_server;
    server_name _;

    root /var/www/react-app;
    index index.html;

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

Disable the default config if present:

sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.disabled
Enter fullscreen mode Exit fullscreen mode

Test and restart:

sudo nginx -t
sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

βœ… Phase 8: Verify Deployment

From the server:

curl -I http://localhost
Enter fullscreen mode Exit fullscreen mode

From your browser:

http://<EC2_PUBLIC_IP>
Enter fullscreen mode Exit fullscreen mode

Your React app should now load successfully.


🧯 Troubleshooting (Lessons Learned)

❌ 500 Internal Server Error

Cause

  • NGINX root pointed to a directory that did not exist
  • Missing index.html

Fix

ls -la /var/www/react-app/index.html
Enter fullscreen mode Exit fullscreen mode

Ensure the build was copied correctly.


❌ Infinite redirect / rewrite loop

Error

rewrite or internal redirection cycle while internally redirecting to "/index.html"
Enter fullscreen mode Exit fullscreen mode

Cause

  • SPA routing without proper try_files
  • Conflicting server blocks

Fix

  • Disable default.conf
  • Use a single server block
  • Verify try_files configuration

❌ Vite / crypto.hash error

Cause

  • Node.js version too old

Fix

nvm use 22
rm -rf node_modules package-lock.json
npm install
Enter fullscreen mode Exit fullscreen mode

🧠 Final Thoughts

This project intentionally avoided:

  • Load balancers
  • Containers
  • CI/CD pipelines

Instead, it focused on:

  • Linux fundamentals
  • NGINX configuration
  • Real debugging scenarios

If you can deploy and troubleshoot this setup, you’re building the right foundation.


πŸ”œ Possible Next Steps

  • Persist Node using nvm
  • Add HTTPS with Let’s Encrypt
  • Introduce a release + rollback structure
  • Move the frontend to S3 + CloudFront

πŸ™ Credits & Learning Acknowledgement

This project builds on foundational DevOps concepts learned from Pravin Mishra teaching; beginner-focused content providing an initial framework for understanding how applications move from development to deployment.

The original learning foundation came from the following resources:

How This Project Differs and Expands

While the course introduced core ideas, this implementation represents my own hands-on work and problem-solving, including:

  • Deploying a React application on Amazon Linux 2023
  • Configuring NGINX to serve a Single Page Application (SPA)
  • Troubleshooting real-world issues such as:
    • Node.js version incompatibilities with modern tooling
    • NGINX 500 Internal Server Errors
    • SPA rewrite and redirect loops
  • Adapting the deployment process to fit a low-cost, beginner-accessible AWS setup
  • Documenting mistakes, fixes, and reasoning to reflect the actual learning process

All configuration choices, debugging steps, and documentation in this project reflect my own experimentation and understanding, built on top of the foundational concepts introduced in the referenced materials.

Top comments (0)