Deploy a Node.js/React Application
This comprehensive guide explains how to deploy a Node.js/React application on your YorkHost VPS with PM2, Nginx and SSL.
Prerequisitesβ
Before you begin, make sure you have:
- A YorkHost VPS with SSH access (Ubuntu/Debian)
- A domain name pointing to your VPS
- A GitHub repository containing your Node.js/React project
- Root or sudo access on your VPS
Step 1: Connect and Prepare the VPSβ
Connect to your VPS via SSH:
ssh root@your-vps-ip
Update the system:
sudo apt update && sudo apt upgrade -y
Step 2: Install Node.jsβ
Install Node.js via NodeSource (LTS version recommended):
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
Verify the installation:
node --version
npm --version
Step 3: Install Required Toolsβ
Install Git, PM2 (process manager) and Nginx (reverse proxy):
sudo apt install git nginx -y
sudo npm install -g pm2
Step 4: Clone Your Project from GitHubβ
GitHub Authentication Setupβ
GitHub no longer allows password authentication. You have two options:
Option A: SSH Key (recommended)β
Generate an SSH key on your VPS:
ssh-keygen -t ed25519 -C "your@email.com"
Press Enter to accept the default location, then set a passphrase (optional).
Display the public key:
cat ~/.ssh/id_ed25519.pub
Copy this key, then add it to GitHub:
- Go to GitHub.com β Settings β SSH and GPG keys
- Click New SSH key
- Give it a title (e.g., "YorkHost VPS") and paste the key
- Click Add SSH key
Test the connection:
ssh -T git@github.com
You should see: "Hi username! You've successfully authenticated..."
Option B: Personal Access Token (PAT)β
If you prefer HTTPS, create a token:
- Go to GitHub.com β Settings β Developer settings β Personal access tokens β Tokens (classic)
- Click Generate new token (classic)
- Give it a name, select an expiration
- Check at least the repo scope
- Click Generate token and copy it immediately
Clone the Projectβ
Create a directory for your applications:
sudo mkdir -p /var/www
cd /var/www
With SSH (recommended):
sudo git clone git@github.com:your-username/your-repo.git mysite
With Personal Access Token:
sudo git clone https://your-username:your-token@github.com/your-username/your-repo.git mysite
Navigate to the project directory:
cd /var/www/mysite
Step 5: Install Dependencies and Buildβ
Install Node.js dependencies:
npm install
For a React project (Create React App, Vite, Next.js), build the application:
npm run build
Step 6: Launch the Application with PM2β
Option A: Static React Application (recommended for CRA/Vite)β
Serve static files with serve:
npm install -g serve
pm2 start serve --name "mysite" -- -s build -l 3000
For Vite, the build folder is dist instead of build:
pm2 start serve --name "mysite" -- -s dist -l 3000
Option B: Node.js/Next.js Application with Serverβ
pm2 start npm --name "mysite" -- start
Configure Auto-Startβ
Configure PM2 to start automatically on reboot:
pm2 startup
pm2 save
Verify the application is running:
pm2 status
Step 7: Configure Nginx as Reverse Proxyβ
Create an Nginx configuration file:
sudo nano /etc/nginx/sites-available/mysite
Add this configuration:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
}
}
Enable the site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 8: DNS Configurationβ
Configure DNS records at your registrar or DNS manager to point to your VPS.
Records to Createβ
| Type | Name | Value |
|---|---|---|
| A | @ | your-vps-ip |
| A | www | your-vps-ip |
The @ record represents the root domain (example.com), and www is the www.example.com subdomain.
Cloudflare Exampleβ
If you use Cloudflare as your DNS manager:
- Log in to the Cloudflare dashboard
- Select your domain
- Go to DNS β Records
- Add the A records above
You can enable the proxy (orange cloud) to benefit from DDoS protection and Cloudflare CDN, or disable it (gray cloud) for direct server access.
Step 9: SSL Configuration (HTTPS)β
Secure your site with an SSL certificate. Here are two options depending on your setup.
Option A: Let's Encrypt Certificate (free)β
Install Certbot:
sudo apt install certbot python3-certbot-nginx -y
Obtain and install the certificate:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the instructions and choose to redirect HTTP to HTTPS.
The certificate will renew automatically. Test the renewal:
sudo certbot renew --dry-run
Option B: SSL via Cloudflare (if proxy enabled)β
If you use the Cloudflare proxy (orange cloud), you can use their SSL:
- In Cloudflare, go to SSL/TLS
- Select Full mode (or Full (Strict) with an origin certificate)
- Enable Always Use HTTPS in Edge Certificates
Modify Nginx to get the real visitor IP:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_cf_connecting_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Step 10: Automatic Updates from GitHubβ
Create a deployment script:
sudo nano /var/www/mysite/deploy.sh
#!/bin/bash
cd /var/www/mysite
git pull origin main
npm install
npm run build
pm2 restart mysite
echo "Deployment complete - $(date)"
Make it executable:
chmod +x /var/www/mysite/deploy.sh
To deploy an update, simply run:
/var/www/mysite/deploy.sh
Useful Commandsβ
| Action | Command |
|---|---|
| View app status | pm2 status |
| View logs | pm2 logs mysite |
| Restart app | pm2 restart mysite |
| Stop app | pm2 stop mysite |
| Test Nginx config | nginx -t |
| Reload Nginx | sudo systemctl reload nginx |
Troubleshootingβ
Application won't startβ
- Check the logs:
pm2 logs mysite - Make sure port 3000 is not in use:
lsof -i :3000
502 Bad Gateway Errorβ
- Verify PM2 is running:
pm2 status - Verify the port in Nginx matches the app port
Site not accessibleβ
- Check the firewall:
sudo ufw statusand allow port 80:sudo ufw allow 80 - Verify DNS points to the correct IP
SSL Errorβ
- Make sure Cloudflare SSL mode is set to "Full" and not "Full (Strict)" if you don't have an origin certificate
For applications requiring environment variables, create a .env file:
nano /var/www/mysite/.env
And add it to .gitignore to avoid versioning it.