A comprehensive, production-ready guide to deploying a ReactJS single-page application (SPA) on an AWS EC2 Ubuntu Server using Nginx as a high-performance web server, configured with custom domain mapping and free automated SSL/TLS certificates via Let's Encrypt (Certbot).
πΊ Full YouTube Video Tutorial: https://youtu.be/UK_OVKDRArs
- Architecture Overview
- Prerequisites & AWS Security Group Rules
- Step 1: Launch an AWS EC2 Ubuntu Server
- Step 2: Connect to EC2 via SSH
- Step 3: Install Node.js, NPM, and Nginx
- Step 4: Clone the React Application
- Step 5: Install Dependencies & Build for Production
- Step 6: Configure Nginx as Web Server
- Step 7: Map Custom Domain (DNS A Record)
- Step 8: Secure with Free SSL/TLS (Certbot / Let's Encrypt)
- Troubleshooting & Common Pitfalls
- Author & Community
- License
flowchart LR
User([User Browser]) -->|HTTPS :443 / HTTP :80| DNS[DNS Provider<br/>GoDaddy / Cloudflare / Route53]
DNS -->|A Record points to Public IP| EC2[AWS EC2 Ubuntu Instance]
subgraph EC2 [AWS EC2 Instance]
SG[Security Group<br/>Inbound: 22, 80, 443] --> NGINX[Nginx Web Server]
NGINX -->|Serves Static Files| BUILD["/var/www/vhosts/frontend/build<br/>(React Production Assets)"]
CERT[Certbot / Let's Encrypt<br/>Auto-renews SSL Certificate] -. manages .-> NGINX
end
Before beginning, ensure your AWS EC2 Security Group allows the following Inbound Rules:
| Type | Protocol | Port Range | Source | Purpose |
|---|---|---|---|---|
| SSH | TCP | 22 |
My IP (recommended) or 0.0.0.0/0 |
Secure shell administration |
| HTTP | TCP | 80 |
0.0.0.0/0 |
Standard web traffic & ACME challenge |
| HTTPS | TCP | 443 |
0.0.0.0/0 |
Encrypted web traffic (SSL) |
- Log into your AWS Management Console.
- Navigate to EC2 Dashboard β Click Launch Instance.
- Choose Ubuntu Server 22.04 LTS or 24.04 LTS (64-bit x86).
- Instance type:
t2.microort3.micro(Eligible for AWS Free Tier). - Select or create an SSH Key Pair (
.pem) and download it. - Under Network Settings, attach the Security Group configured with ports
22,80, and443. - Click Launch Instance.
Open your terminal on macOS / Linux (or PowerShell / Git Bash on Windows):
chmod 400 /path/to/your-key.pem
ssh -i /path/to/your-key.pem ubuntu@<YOUR-EC2-PUBLIC-IP>Update package repositories and install Node.js LTS (v20) and Nginx:
# Update Ubuntu system
sudo apt-get update -y && sudo apt-get upgrade -y
# Setup Node.js 20.x repository
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# Install Node.js, NPM, and Nginx
sudo apt-get install -y nodejs npm nginx
# Verify installations
node -v
npm -v
nginx -vNavigate to your home directory and clone your code:
cd ~
git clone https://github.com/codewithmuh/react-aws-ec2-nginx.git
cd react-aws-ec2-nginx(If cloning a private repository, generate and use a GitHub Personal Access Token).
Install project packages and compile optimized static assets:
# Install npm dependencies
npm install
# Create production build
npm run build
# Create web root directory and copy build files
sudo mkdir -p /var/www/vhosts/frontend/
sudo cp -R build/ /var/www/vhosts/frontend/
sudo chown -R www-data:www-data /var/www/vhosts/frontend/-
Remove the default Nginx welcome configuration:
sudo rm -f /etc/nginx/sites-enabled/default
-
Create a new virtual host configuration:
sudo nano /etc/nginx/sites-available/react-app
-
Paste the following configuration (replace
yourdomain.comwith your domain or_if using IP):server { listen 80; server_name yourdomain.com www.yourdomain.com; root /var/www/vhosts/frontend/build; index index.html index.htm; location / { try_files $uri $uri/ /index.html; } # Cache static assets location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; add_header Cache-Control "public, no-transform"; } }
-
Enable the site and test the configuration:
sudo ln -s /etc/nginx/sites-available/react-app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx
In your domain registrar (GoDaddy, Namecheap, Cloudflare, AWS Route 53):
- Add an A Record:
- Host / Name:
@ - Value / Points to:
<Your-EC2-Public-IP> - TTL: Auto or 300 seconds
- Host / Name:
- Add a CNAME or A Record for
wwwpointing to@or<Your-EC2-Public-IP>. - Wait 2-5 minutes for DNS propagation.
Run Certbot to automatically configure HTTPS and redirect HTTP to HTTPS:
# Install Certbot and the Nginx plugin
sudo apt-get install -y certbot python3-certbot-nginx
# Obtain and install SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Verify auto-renewal timer
sudo systemctl status certbot.timer| Issue | Cause | Solution |
|---|---|---|
| Site cannot be reached (Timeout) | AWS Security Group missing port 80/443 | Open port 80 and 443 to 0.0.0.0/0 in EC2 Security Group inbound rules. |
| 404 Not Found on Route Refresh | Nginx missing try_files SPA routing fallback |
Ensure try_files $uri $uri/ /index.html; is present in your Nginx config. |
| 403 Forbidden | Incorrect file permissions on build folder | Run sudo chown -R www-data:www-data /var/www/vhosts/frontend/ and sudo chmod -R 755 /var/www/vhosts/frontend/. |
| Certbot DNS Verification Failed | Domain DNS has not propagated yet | Verify your domain points to your EC2 public IP using nslookup yourdomain.com. |
Muhammad Rashid β DevOps & Cloud Engineer, AWS Community Builder.
- π₯ YouTube: @codewithmuh
- πΌ LinkedIn: Muhammad Rashid
- π Website: codewithmuh.com Β· devopsbymuh.com
β If you found this guide helpful, please star the repository!
This project is open-source under the MIT License.
