Most developers stick to easy deployment platforms like Netlify or Heroku. But what if you want more control? Setting up your React app on a cloud virtual machine gives you flexibility and deeper infrastructure knowledge.
This guide walks you through deploying a React application using infrastructure-as-a-service platforms, complete with DNS configuration, SSL certificates, and automated deployment via GitHub Actions. Whether you're using AWS EC2, Google Cloud, Azure, or another provider, these steps apply universally.
Platform-as-a-service solutions handle everything for you, but they come with limitations. When you deploy on a virtual machine, you get complete control over your server environment, configuration, and scaling options. You'll also learn how Git, DNS, Nginx, Let's Encrypt, and cloud services work together in a production environment.
For teams looking to scale beyond basic hosting, understanding virtual machine deployment becomes essential. Modern cloud platforms offer powerful compute services that can handle everything from small projects to enterprise applications. 👉 Explore flexible cloud computing solutions with Alibaba Cloud ECS instances that provide the infrastructure foundation for robust application deployment.
First, you'll need to create a virtual machine on your chosen cloud platform. The process is similar across providers, though interface details vary slightly. For this guide, we're using Ubuntu as the operating system since it's widely supported and well-documented.
Here's what you need to configure during VM creation:
Instance Type: Start with something modest like AWS t3.micro or equivalent to keep costs low while testing. You can always scale up later based on actual usage patterns.
Operating System: Select Ubuntu (preferably the latest LTS version) for consistent command compatibility throughout this tutorial.
Security Groups: Configure firewall rules carefully. Allow SSH access only from specific IP ranges you control, not from anywhere on the internet. Enable HTTP (port 80) and HTTPS (port 443) traffic so visitors can access your application.
Key Pair: Generate and download an SSH key pair. This provides secure access to your server without relying on passwords.
Once your virtual machine launches, note the public IP address. You'll need it for DNS configuration and SSH access.
After launching your server, configure your domain's DNS settings to point visitors to your virtual machine. Add an A record with these details:
Record Type: A
Host: @ (represents your root domain)
Value: Your server's public IP address
DNS propagation can take anywhere from a few minutes to 48 hours, though it's usually quick. This step transforms your numeric IP address into a memorable domain name that users can actually visit.
SSH into your newly created server and install the tools needed to run your React application:
bash
sudo apt update
sudo apt upgrade -y
sudo apt install git nginx -y
sudo apt install snapd -y
sudo snap install certbot --classic
Each component serves a specific purpose in your deployment stack:
Git clones your repository code from GitHub to the server so you can build and run your application.
Nginx acts as a reverse proxy server, routing incoming web traffic to your React app running on a specific port.
Certbot generates free SSL certificates from Let's Encrypt, securing your site with HTTPS encryption.
If your GitHub repository is private, you need to grant your server access. Generate SSH keys on your server:
bash
ssh-keygen -t ecdsa
Press Enter through the prompts to accept defaults. Then copy the public key:
bash
cat ~/.ssh/id_ecdsa.pub
Navigate to your GitHub repository's Settings → Deploy keys and add the copied key. This authenticates your server to pull code without exposing your GitHub credentials.
For automated deployments, GitHub Actions needs to SSH into your server. View your private key:
bash
cat ~/.ssh/id_ecdsa
Copy the entire private key output, then go to your GitHub repository Settings → Secrets and variables → Actions → New repository secret. Name it SSH_PRIVATE_KEY and paste the key as the value.
Also authorize the public key for SSH connections:
bash
cat ~/.ssh/id_ecdsa.pub >> ~/.ssh/authorized_keys
Your React app requires Node.js to run. Install Node Version Manager (nvm) for flexible version management, then install a specific Node version:
bash
sudo apt install nodejs npm -y
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
nvm install 20.13.1
Install PM2 globally to manage your application process:
bash
sudo npm -g install pm2
PM2 keeps your app running continuously, automatically restarting it if crashes occur.
Create a deployment script in your home directory that handles updates:
bash
cd ~
vim deploy_script.sh
Add this content (customize the variables for your setup):
bash
#!/bin/bash
APP_DIR="/home//"
REPO_URL="git@github.com:/.git"
if [ ! -d "$APP_DIR" ]; then
git clone $REPO_URL
fi
cd $APP_DIR
git restore .
git pull origin main
npm install
pm2 restart || pm2 start "npm start" --name
Make it executable:
bash
chmod +x deploy_script.sh
Run the script to perform your initial deployment:
bash
./deploy_script.sh
Your React app is now running on port 3000, but it's not yet accessible via your domain.
Edit Nginx's default configuration:
bash
sudo vim /etc/nginx/sites-available/default
Replace the contents with:
nginx
server {
listen 80;
server_name ;
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;
}
}
Reload Nginx to apply changes:
bash
sudo systemctl reload nginx
Your site is now accessible via your domain, though still over insecure HTTP.
Secure your site with HTTPS using Certbot:
bash
sudo certbot -d your-domain.com --nginx
Follow the prompts to complete certificate installation. Certbot automatically modifies your Nginx configuration to enable HTTPS and redirect HTTP traffic. Your site now has that reassuring padlock icon in browsers.
For organizations managing multiple applications and domains, cloud-based certificate management and load balancing services can streamline SSL configuration across your infrastructure. 👉 Discover enterprise-grade security and networking features on Alibaba Cloud to enhance your deployment architecture.
Manual deployments work, but automation saves time and reduces errors. Create a GitHub Actions workflow in your repository at .github/workflows/deploy.yaml:
yaml
name: Deploy React App
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ecdsa
chmod 600 ~/.ssh/id_ecdsa
ssh-keyscan -H <server-ip-address> >> ~/.ssh/known_hosts
- name: Deploy to VM
run: |
ssh ubuntu@<server-ip-address> './deploy_script.sh'
Replace <server-ip-address> with your actual server IP. Now whenever you push code to the main branch, GitHub Actions automatically deploys your changes to the live server.
You've built a complete deployment pipeline from scratch. Your React app now runs on production infrastructure with professional-grade security, automated deployments, and the flexibility to customize every aspect of your hosting environment.
This foundation scales well as your project grows. You can add database servers, implement load balancing, configure CDN integration, or expand to multiple regions using the same fundamental concepts you've learned here.