React remains the most popular JavaScript framework for building modern web applications. But deploying to your own Ubuntu server gives you complete control, better performance, and significant cost savings. This comprehensive guide covers everything you need to know about React hosting on Ubuntu servers in 2025, from basic deployments to advanced optimization techniques.
Note: This guide focuses on deploying React on Ubuntu servers. CloudPloy currently supports Laravel applications, with React support coming soon. Stay tuned for updates!
Understanding React Hosting Requirements
React applications have unique hosting needs that differ from traditional server-side applications:
- Static File Serving: Build outputs need efficient web server configuration
- Client-Side Routing: Proper nginx configuration for SPA routing
- API Integration: Backend proxy and CORS handling
- SEO Optimization: Server-side rendering for better search visibility
- Performance: Code splitting, compression, and caching
- Security: XSS protection, Content Security Policies, and HTTPS
Ubuntu servers provide the perfect foundation for hosting React applications with complete control over your infrastructure.
Quick Start: Deploy React on Ubuntu Server
Step 1: Prepare Your Ubuntu Server
# Update system packages
sudo apt update && sudo apt upgrade -y
# Install Node.js (using NodeSource repository)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# Install nginx
sudo apt install nginx -y
# Install certbot for SSL certificates
sudo apt install certbot python3-certbot-nginx -y
Step 2: Prepare Your React Application
# Create a new React app (if needed)
npx create-react-app my-react-app
cd my-react-app
# Or use Vite for faster builds
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
# Build for production
npm run build
Step 3: Deploy to Your Ubuntu Server
# Copy build files to server
scp -r build/ user@your-server:/var/www/my-react-app/
# Or use git deployment (recommended)
git clone https://github.com/yourusername/my-react-app.git /var/www/my-react-app
cd /var/www/my-react-app
npm ci --production
npm run build
Step 4: Configure Nginx
# Create nginx server block
sudo nano /etc/nginx/sites-available/my-react-app
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/my-react-app/build;
index index.html;
# Handle client-side routing
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
}
# Enable the site
sudo ln -s /etc/nginx/sites-available/my-react-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 5: Set Up SSL Certificate
# Get SSL certificate with certbot
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Verify auto-renewal
sudo certbot renew --dry-run
Your React app is now live with HTTPS, optimized caching, and production-ready configuration!
React Build Optimization for Production
1. Environment Configuration
Create a .env.production file for production settings:
REACT_APP_API_URL=https://api.yourdomain.com
REACT_APP_ENVIRONMENT=production
REACT_APP_VERSION=$npm_package_version
Load environment variables in your build process:
// src/config/api.js
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:3001';
export const fetchData = async (endpoint) => {
const response = await fetch(`${API_URL}${endpoint}`);
return response.json();
};
2. Build Optimization Techniques
Code Splitting with React.lazy()
// src/App.js
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Lazy load route components
const Home = lazy(() => import('./pages/Home'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Profile = lazy(() => import('./pages/Profile'));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
</Router>
);
}
Bundle Size Optimization
// webpack.config.js (for ejected apps)
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
},
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true
}
}
}
}
};
3. Advanced Nginx Configuration for React
Create an optimized nginx configuration for React applications:
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
root /var/www/my-react-app/build;
index index.html;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Handle client-side routing
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets aggressively
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# API proxy (if needed)
location /api/ {
proxy_pass http://localhost:3001/;
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;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
Advanced React Hosting Scenarios
Server-Side Rendering with Next.js
For SEO-critical React applications, deploy Next.js on Ubuntu:
# Create Next.js app
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
# Install PM2 for process management
sudo npm install -g pm2
# Create ecosystem file
echo 'module.exports = {
apps: [{
name: "nextjs-app",
script: "npm",
args: "start",
cwd: "/var/www/my-nextjs-app",
env: {
NODE_ENV: "production",
PORT: 3000
}
}]
}' > ecosystem.config.js
# Build and start
npm run build
pm2 start ecosystem.config.js
pm2 save
pm2 startup
Configure nginx as reverse proxy:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
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;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
React with Express Backend
Deploy full-stack React applications on Ubuntu:
// server.js
const express = require('express');
const path = require('path');
const app = express();
// API routes
app.use('/api', require('./routes/api'));
// Serve React build
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Create systemd service for your full-stack app:
# Create service file
sudo nano /etc/systemd/system/react-express-app.service
[Unit]
Description=React Express App
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/react-express-app
Environment=NODE_ENV=production
Environment=PORT=5000
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
# Enable and start service
sudo systemctl enable react-express-app
sudo systemctl start react-express-app
sudo systemctl status react-express-app
Micro-Frontend Architecture
Deploy multiple React apps as micro-frontends using nginx routing:
# Main nginx configuration for micro-frontends
server {
listen 443 ssl http2;
server_name yourdomain.com;
# Main app (shell)
location / {
root /var/www/main-app/build;
try_files $uri $uri/ /index.html;
}
# Dashboard micro-frontend
location /dashboard {
alias /var/www/dashboard-app/build;
try_files $uri $uri/ /dashboard/index.html;
}
# Settings micro-frontend
location /settings {
alias /var/www/settings-app/build;
try_files $uri $uri/ /settings/index.html;
}
# API gateway
location /api/ {
proxy_pass http://localhost:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
// main-app/src/App.js
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'dashboard',
entry: '/dashboard/',
container: '#dashboard-container',
activeRule: '/dashboard'
},
{
name: 'settings',
entry: '/settings/',
container: '#settings-container',
activeRule: '/settings'
}
]);
start();
Performance Optimization for React on Ubuntu
1. Enable HTTP/2 and Compression
Optimize nginx for maximum performance:
# Update nginx.conf
sudo nano /etc/nginx/nginx.conf
http {
# Enable HTTP/2
listen 443 ssl http2;
# Optimize gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# Enable brotli compression (if installed)
brotli on;
brotli_comp_level 6;
brotli_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# Connection optimization
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
}
2. Implement Service Workers
// src/serviceWorker.js
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/',
'/static/js/bundle.js',
'/static/css/main.css'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
3. Image Optimization with ImageMagick
Install and configure ImageMagick for automatic image optimization:
# Install ImageMagick
sudo apt install imagemagick -y
# Create image optimization script
sudo nano /usr/local/bin/optimize-images.sh
#!/bin/bash
# Image optimization script
WEBROOT="/var/www/my-react-app/build"
find "$WEBROOT" -name "*.jpg" -o -name "*.jpeg" | while read img; do
convert "$img" -strip -interlace Plane -gaussian-blur 0.05 -quality 85% "$img"
done
find "$WEBROOT" -name "*.png" | while read img; do
convert "$img" -strip "$img"
done
echo "Image optimization completed"
# Make script executable
sudo chmod +x /usr/local/bin/optimize-images.sh
# Run after each deployment
/usr/local/bin/optimize-images.sh
// src/components/OptimizedImage.js
import { useState, useEffect } from 'react';
const OptimizedImage = ({ src, alt, ...props }) => {
const [loaded, setLoaded] = useState(false);
return (
<img
src={src}
alt={alt}
{...props}
loading="lazy"
onLoad={() => setLoaded(true)}
style={{
opacity: loaded ? 1 : 0,
transition: 'opacity 0.3s',
...props.style
}}
/>
);
};
export default OptimizedImage;
Security Best Practices for React Hosting
1. Content Security Policy with Nginx
# Add to your nginx server block
server {
# ... other configuration
# Security headers
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:; connect-src 'self' https:; media-src 'self'; object-src 'none'; child-src 'self';" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Remove server tokens
server_tokens off;
# Limit request size
client_max_body_size 10M;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
}
2. Firewall Configuration
# Configure UFW firewall
sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw status
2. Environment Variable Security
// Never expose sensitive data in React
// ❌ Wrong
const API_KEY = process.env.REACT_APP_SECRET_KEY;
// ✅ Correct - Use backend proxy
const fetchSecureData = async () => {
const response = await fetch('/api/secure-endpoint');
return response.json();
};
3. XSS Protection
// Always sanitize user input
import DOMPurify from 'dompurify';
const SafeHTML = ({ html }) => {
const cleanHTML = DOMPurify.sanitize(html);
return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;
};
Monitoring and Analytics
Server Monitoring with Netdata
# Install Netdata for real-time monitoring
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
# Configure nginx monitoring
sudo nano /etc/netdata/python.d/nginx.conf
localhost:
name: 'local'
url: 'http://localhost/nginx_status'
# Add nginx status endpoint
sudo nano /etc/nginx/sites-available/default
# Add to server block
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Application Monitoring
// Error tracking and performance monitoring
window.addEventListener('error', (event) => {
// Send error to your logging service
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: event.error.message,
stack: event.error.stack,
url: window.location.href,
timestamp: new Date().toISOString()
})
});
});
// Performance monitoring
if ('performance' in window) {
window.addEventListener('load', () => {
const perfData = performance.getEntriesByType('navigation')[0];
const metrics = {
loadTime: perfData.loadEventEnd - perfData.loadEventStart,
domContentLoaded: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
firstPaint: performance.getEntriesByType('paint')[0]?.startTime,
url: window.location.href
};
fetch('/api/metrics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(metrics)
});
});
}
Custom Analytics Integration
// src/analytics.js
export const trackEvent = (action, category, label, value) => {
if (window.gtag) {
window.gtag('event', action, {
event_category: category,
event_label: label,
value: value
});
}
};
// Usage in components
import { trackEvent } from '../analytics';
const Button = ({ onClick, children }) => {
const handleClick = (e) => {
trackEvent('click', 'UI', children);
onClick(e);
};
return <button onClick={handleClick}>{children}</button>;
};
CI/CD Pipeline for React Apps
GitHub Actions with Ubuntu Server Deployment
# .github/workflows/deploy.yml
name: Deploy React to Ubuntu Server
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage --watchAll=false
- name: Build production
run: npm run build
- name: Deploy to Ubuntu Server
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/my-react-app
git pull origin main
npm ci --production
npm run build
sudo systemctl reload nginx
- name: Health Check
run: |
sleep 30
curl -f https://yourdomain.com || exit 1
Alternative: Deploy Script
#!/bin/bash
# deploy.sh - Simple deployment script
set -e
APP_DIR="/var/www/my-react-app"
BACKUP_DIR="/var/backups/my-react-app"
# Create backup
echo "Creating backup..."
sudo mkdir -p "$BACKUP_DIR"
sudo cp -r "$APP_DIR/build" "$BACKUP_DIR/build-$(date +%Y%m%d_%H%M%S)"
# Pull latest changes
echo "Pulling latest changes..."
cd "$APP_DIR"
git pull origin main
# Install dependencies and build
echo "Building application..."
npm ci --production
npm run build
# Test build
if [ ! -f "build/index.html" ]; then
echo "Build failed - restoring backup"
sudo rm -rf "$APP_DIR/build"
sudo cp -r "$BACKUP_DIR/build-$(ls -t $BACKUP_DIR | head -1)" "$APP_DIR/build"
exit 1
fi
# Reload nginx
echo "Reloading nginx..."
sudo nginx -t && sudo systemctl reload nginx
# Health check
echo "Performing health check..."
sleep 5
if curl -f https://yourdomain.com > /dev/null 2>&1; then
echo "Deployment successful!"
else
echo "Health check failed!"
exit 1
fi
Cost Comparison: React Hosting Platforms
| Platform | Monthly Cost | Setup Time | SSL | CDN | Control Level |
|---|---|---|---|---|---|
| Ubuntu Server | $5-20 | 30min | Free | Optional | Complete |
| Vercel | $20+ | 2-3min | Free | Yes | Limited |
| Netlify | $19+ | 2-4min | Free | Yes | Limited |
| AWS Amplify | $15+ | 3-5min | Free | Yes | Moderate |
| DigitalOcean App | $12+ | 2-4min | Free | Yes | Limited |
| Railway | $20+ | 3-5min | Free | No | Limited |
Ubuntu Server Advantages:
- Complete Control: Full server access and customization
- Cost Effective: $5-20/month for powerful VPS
- No Vendor Lock-in: Switch providers anytime
- Learning Experience: Understand deployment internals
- Scalability: Easily upgrade resources
- Multiple Apps: Host multiple projects on one server
Troubleshooting Common React Hosting Issues
Issue 1: Blank Page After Deployment
Solution: Configure proper routing for SPAs:
// cloudploy.json
{
"routes": [
{ "src": "/(.*)", "dest": "/index.html" }
]
}
Issue 2: Environment Variables Not Working
Solution: Use REACT_APP_ prefix:
# .env.production
REACT_APP_API_URL=https://api.example.com
Issue 3: Large Bundle Size
Solution: Implement code splitting and tree shaking:
// Use dynamic imports
const HeavyComponent = lazy(() =>
import(/* webpackChunkName: "heavy" */ './HeavyComponent')
);
Issue 4: CORS Errors
Solution: Configure nginx proxy:
# Add to your nginx server block
location /api/ {
# Remove trailing slash and proxy to backend
proxy_pass http://localhost:3001/;
# CORS headers
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
# Handle preflight OPTIONS requests
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization, Content-Type";
add_header Access-Control-Max-Age 1728000;
add_header Content-Type "text/plain; charset=utf-8";
add_header Content-Length 0;
return 204;
}
# Standard proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
React Hosting Best Practices Checklist
✅ Pre-Deployment:
- Optimize bundle size (< 200KB gzipped)
- Implement code splitting
- Configure environment variables
- Add error boundaries
- Test production build locally
✅ Deployment:
- Use CI/CD pipeline
- Enable CDN caching
- Configure custom domain
- Set up SSL certificate
- Implement monitoring
✅ Post-Deployment:
- Monitor Core Web Vitals
- Set up error tracking
- Configure analytics
- Implement A/B testing
- Regular performance audits
Migrating Existing React Apps to Ubuntu Server
From Shared Hosting
# Download your current files
wget -r --no-parent http://youroldsite.com/
# Upload to Ubuntu server
scp -r youroldsite.com/ user@your-server:/var/www/
# Set proper permissions
sudo chown -R www-data:www-data /var/www/youroldsite.com/
sudo chmod -R 755 /var/www/youroldsite.com/
From Vercel/Netlify
# Clone your repository
git clone https://github.com/yourusername/your-react-app.git /var/www/your-react-app
cd /var/www/your-react-app
# Install dependencies and build
npm ci --production
npm run build
# Configure nginx (use configuration from earlier sections)
sudo nano /etc/nginx/sites-available/your-react-app
From Heroku
# If using git deployment
heroku git:remote -a your-app-name
git remote add ubuntu user@your-server:/var/www/your-react-app.git
# Push to Ubuntu server
git push ubuntu main
# SSH into server and build
ssh user@your-server
cd /var/www/your-react-app
npm ci --production
npm run build
Advanced Features for React Developers
1. Staging Environment Setup
Create separate staging environment:
# Create staging directory
sudo mkdir -p /var/www/staging.yourdomain.com
# Configure staging nginx server block
sudo nano /etc/nginx/sites-available/staging.yourdomain.com
server {
listen 80;
server_name staging.yourdomain.com;
root /var/www/staging.yourdomain.com/build;
index index.html;
# Basic auth for staging
auth_basic "Staging Environment";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
try_files $uri $uri/ /index.html;
}
}
# Create basic auth file
sudo htpasswd -c /etc/nginx/.htpasswd staging_user
# Enable staging site
sudo ln -s /etc/nginx/sites-available/staging.yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
2. Rollback System with Git
#!/bin/bash
# rollback.sh - Simple rollback script
APP_DIR="/var/www/my-react-app"
BACKUP_DIR="/var/backups/my-react-app"
if [ -z "$1" ]; then
echo "Available backups:"
ls -la "$BACKUP_DIR"
echo "Usage: ./rollback.sh <backup-name>"
exit 1
fi
BACKUP_NAME="$1"
if [ ! -d "$BACKUP_DIR/$BACKUP_NAME" ]; then
echo "Backup $BACKUP_NAME not found!"
exit 1
fi
# Stop application
echo "Rolling back to $BACKUP_NAME..."
# Backup current version
sudo cp -r "$APP_DIR/build" "$BACKUP_DIR/build-rollback-$(date +%Y%m%d_%H%M%S)"
# Restore backup
sudo rm -rf "$APP_DIR/build"
sudo cp -r "$BACKUP_DIR/$BACKUP_NAME" "$APP_DIR/build"
# Reload nginx
sudo systemctl reload nginx
echo "Rollback completed!"
3. A/B Testing with Nginx
# A/B testing with nginx split testing
server {
listen 443 ssl http2;
server_name yourdomain.com;
# A/B testing logic
set $variant "A";
if ($cookie_ab_test = "B") {
set $variant "B";
}
if ($cookie_ab_test = "") {
set $variant $split_clients_$remote_addr;
}
# Split traffic 50/50
split_clients $remote_addr $split_clients_$remote_addr {
50% "A";
50% "B";
}
# Serve different builds based on variant
location / {
if ($variant = "A") {
root /var/www/my-react-app/build-a;
}
if ($variant = "B") {
root /var/www/my-react-app/build-b;
}
add_header Set-Cookie "ab_test=$variant; Path=/; HttpOnly; Secure";
try_files $uri $uri/ /index.html;
}
}
Conclusion: Why Ubuntu Server for React Hosting?
Ubuntu servers offer the perfect combination of control, performance, and cost-effectiveness for React developers:
- ⚡ Complete Control - Configure everything exactly as needed
- 💰 Cost Effective - $5-20/month for powerful hosting
- 🔒 Security First - Full control over security configuration
- 📈 Scalable - Easy to upgrade resources as you grow
- 🎓 Learning Experience - Understand deployment and DevOps
- 🌐 No Vendor Lock-in - Switch providers anytime
Whether you’re building a simple portfolio or a complex enterprise application, Ubuntu servers provide the foundation you need to succeed while keeping costs low and maintaining complete control.
Get Started with Ubuntu Server React Hosting Today
Ready to take control of your React deployment?
- Get a VPS: DigitalOcean, Linode, or AWS EC2 ($5-20/month)
- Follow this guide: Complete setup in 30 minutes
- Deploy with confidence: Full control over your infrastructure
For managed deployment automation, consider using the Ploy CLI tool to streamline your Ubuntu server deployments while maintaining full control over your infrastructure.
Popular VPS Providers:
- DigitalOcean - Developer-friendly, $6/month
- Linode - High performance, $5/month
- Vultr - Global locations, $6/month
- AWS EC2 - Enterprise grade, varies
Last updated: September 2025. React is a trademark of Meta Platforms, Inc.