Deploy a React App on Ubuntu Web Server in AWS CLoud [week-1]



This content originally appeared on DEV Community and was authored by Suvrajeet Banerjee

High Level OverView: A practical, story-driven guide to take a React SPA on a live Ubuntu EC2 Instance using Nginx — repeatable and beginner-friendly.

terminal + server rack + Nginx logo

📚 Table of contents

  • 🔎 Short version — Summary / Overview
  • 🧭 Why this guide exists — a quick story
  • 🧾 Prerequisites
  • 🔧 Step 1 — Launch Ubuntu AWS EC2 (Free Tier)
  • 🔒 Step 2 — Security Group & key pair
  • 🔑 Step 3 — SSH into the server
  • ⚙ Step 4 — Install Node.js, npm, git & Nginx
  • 🕸 Step 5 — Start Nginx & verify
  • 📥 Step 6 — Clone your React repo to the server
  • ✍ Step 7 — Quick UI tweak to prove workflow
  • 🏗 Step 8 — npm install & npm run build
  • 📦 Step 9 — Deploy build/ to /var/www/html
  • 🔁 Step 10 — Edit Nginx config & validation (Important!)
  • 🔍 Step 11 — Troubleshooting checklist
  • 🧾 Full command block — Copy-Paste
  • 🔮 Next steps — make it production-ready

🔎 Short version — Summary / Overview

  • 🧩 Goal: Host a React SPA (Single Page Application) on an Ubuntu EC2 instance with Nginx serving the production build/ so the app is publicly reachable.
  • 🛠 Why:

    • React outputs static assets;
    • Nginx serves them fast;
    • EC2 gives you a public endpoint.
  • 🗺 Expanded architecture:

    • 💻 Developer laptop → GitHub / local build artifacts
    • 🔐 SSH (key) → EC2 Ubuntu server (t2.micro/t3.micro)
    • 🏗 On EC2: git clonenpm installnpm run buildbuild/
    • 📦 Deploy: copy build/*/var/www/html → Nginx serves files and rewrites routes to index.html
    • 🌐 Public: Browser → http://<EC2-PUBLIC-IP> → Nginx → React app

🧭 Why this guide exists — a quick story

  • 🗣 I once refreshed a deployed site and saw the default Nginx page — pure panic. This guide is the “how I did it” playbook to avoid that 3 AM freakout. Real commands, screenshots, & a repeatable flow.

🧾 Prerequisites

  • 🧾 Active AWS account (Free Tier OK)
  • 💻 React app (local or GitHub)
  • 🔑 EC2 key pair (.pem) and SSH knowledge
  • 🧰 Basic terminal skills

🔧 Step 1 — Launch Ubuntu AWS EC2 (Free Tier)

  • 🖥 Choose Ubuntu Server 22.04 LTS AMI.
  • 🧾 Pick t2.micro / t3.micro for Free Tier eligibility.
  • 🔐 Create & download key pair (demo-react-key.pem) — guard it like your wallet.

EC2 launch & AMI selection

🔒 Step 2 — Security Group & key pair

  • 🔑 Inbound security rule (add these while configuring aws instance):

    • 🔐 SSH — TCP 22 — restrict to your-IP (recommended)
    • type = ssh — protocol = tcp — port = 22 — source = custom — <your-ip>/32[single device — Total Number of Hosts: 1]
    • Check your-ip !
    • OR if that causes access issues: <your-ip>/24[Total Number of Hosts: 256]preferred-option when behind a small NAT range
    • 👉 Copy your public IP from https://checkip.amazonaws.com/ and use it here.
    • 🌍 HTTP — TCP 80 — 0.0.0.0/0
    • type = http — protocol = tcp — port = 80
  • ⚠ Tip: keep SSH locked to your IP. Don’t be casual with port 22.

Security Group inbound rules

ip-subnet-calculator

check-ip.aws

💡 Why this matters: restricting SSH to your IP prevents random scanning and brute-force attempts. Using /32 is the most secure — /24 is a fallback when you’re on a network where your public IP may appear within a small block.

🔑 Step 3 — SSH into the server

  • 🖱 On your machine:
chmod 400 demo-react-key.pem
ssh -i demo-react-key.pem ubuntu@<your-ec2-public-ip>
  • ✅ First connect accepts the host key; type yes to continue.

SSH connection

⚙ Step 4 — Install Node.js, npm, git & Nginx

  • 🧰 On the EC2 Instance:
sudo apt update
sudo apt install -y nodejs npm git nginx
node -v && npm -v
  • ✅ For a specific Node version later use nvm or NodeSource; apt is fine for demos.

packages installation

🕸 Step 5 — Start Nginx & verify

  • 🏁 Start and enable Nginx:
sudo systemctl start nginx
sudo systemctl enable nginx
systemctl status nginx
  • 🌐 Visit http://<your-ec2-public-ip> — Nginx will now greet you with their basic welcome page.

nginx

📥 Step 6 — Clone your React repo to the server

  • 📦 Bring the code:
git clone https://github.com/<your-username>/<your-repo>.git
cd <your-repo>
  • 🔁 Cloning is repeatable and easier to track for deploys.

git clone

✍ Step 7 — Quick UI tweak to prove workflow

  • 🖊 Make a visible change:
cd src
nano App.js   # make a small text change & save
cd ..

App.js

🏗 Step 8 — npm install & npm run build

  • 🏗 Build production assets:
npm install
npm run build
  • 📁 Result: build/ directory containing static files.

npm run build

npm run build-original

📦 Step 9 — Deploy build/ to /var/www/html

  • ⚠ Important note: the build directory is created inside your project root i.e. my-react-app/ — & not inside my-react-app/src/. That means before copying you must ensure you are in the project root (one directory up from src) so the path build/* exists.

  • ✅ Correct flow (from inside your project root my-react-app/):

# make sure you are at: ~/my-react-app
pwd   # confirm you are in the project root, not src/ (should show .../my-react-app)

sudo rm -rf /var/www/html/*
sudo cp -r build/* /var/www/html/
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html
  • 🔍 If you accidentally run the cp from inside src/, the build/ path will not exist — move one directory up: cd .. before running the cp command.

copy build

💡 Quick sanity check: ls build should list index.html and static folders before you copy.

🔁 Step 10 — Edit Nginx config & validation (Important!)

  • ℹ Important: The active Nginx site config for the default site is located at /etc/nginx/sites-available/default. You must edit this file to add SPA-friendly routing and other settings — do NOT rely on rewriting the config via a single echo pipe in an unattended script without first verifying the edit.

  • ✍ Steps:

  1. 🔐 Open the config file for editing:
  sudo vi /etc/nginx/sites-available/default
  • ➕ Add/ensure the location/block includes the SPA rewrite:
  server {
      listen 80;
      server_name _;
      root /var/www/html;
      index index.html;

      location / {
          try_files $uri /index.html;
      }

      error_page 404 /index.html;
  }
  • 💬 Save and exit the editor [Esc → :wq].
  1. ✅ Now to test the edited config — Run:
  sudo nginx -t

nginx-ok

  • 📝 If it returns ok, the config is syntactically valid. If not, review the line numbers and fix syntax errors (missing semicolons, braces, etc).
  1. 🔁 Only after nginx -t reports OK, restart Nginx to apply changes:
  sudo systemctl restart nginx
  • 🔎 Verify: sudo systemctl status nginx and test your site in the browser.

    • 🧾 Why this change? Editing the config file manually first lets you confirm the file was properly updated (and commented/annotated) before restarting Nginx. That prevents downtime from a broken automated replacement and gives you room to validate.

🔍 Step 11 — Troubleshooting checklist

  • ❌ No site → Check Security Group: port 80 must be open.
  • ❌ Nginx downsudo systemctl status nginx.
  • ❌ Config syntax errorssudo nginx -t will show line/column issues.
  • ❌ Blank / broken app → Check browser console errors and ls /var/www/html.
  • ✅ Logs: sudo tail -n 100 /var/log/nginx/error.log

🧾 Full command block — Copy-Paste

# 1) Local: set permissions on your key and SSH into EC2
chmod 400 demo-react-key.pem
ssh -i demo-react-key.pem ubuntu@<your-ec2-public-ip>

# 2) On the EC2: update & install required packages
sudo apt update
sudo apt install -y nodejs npm git nginx

# 3) Start & enable nginx service
sudo systemctl start nginx
sudo systemctl enable nginx

# 4) Clone your repo into the home directory (change to your repo)
git clone https://github.com/<your-username>/<your-repo>.git
cd <your-repo>

# 5) Build the React app (ensure you are in the project root)
npm install
npm run build

# 6) Deploy build into Nginx root (confirm you are in project root, not src/)
pwd   # confirm path ends with your project root
sudo rm -rf /var/www/html/*
sudo cp -r build/* /var/www/html/
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html

# 7) Edit Nginx config manually:
#    sudo nano /etc/nginx/sites-available/default
#    Add the location / block with "try_files $uri /index.html;"
#    Save file. Then validate & restart (run these two commands manually)
#    sudo nginx -t
#    sudo systemctl restart nginx

🔮 Next steps — make it production-ready (smart moves)

  • 🔁 Reserve an Elastic IP so the instance IP doesn’t change.
  • 🔐 Add HTTPS with Certbot (Let’s Encrypt).
  • ⚙ Automate build & deploy with GitHub Actions or keep deploy.sh for local CI.
  • 🐳 Containerize with Docker when you need portability or scaling.

P.S. This post is part of the FREE DevOps Cohort run by Pravin Mishra. You can start your DevOps journey for free from his YouTube Playlist


This content originally appeared on DEV Community and was authored by Suvrajeet Banerjee