Skip to main content

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:

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:

  1. Go to GitHub.com β†’ Settings β†’ SSH and GPG keys
  2. Click New SSH key
  3. Give it a title (e.g., "YorkHost VPS") and paste the key
  4. 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:

  1. Go to GitHub.com β†’ Settings β†’ Developer settings β†’ Personal access tokens β†’ Tokens (classic)
  2. Click Generate new token (classic)
  3. Give it a name, select an expiration
  4. Check at least the repo scope
  5. 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​

Serve static files with serve:

npm install -g serve
pm2 start serve --name "mysite" -- -s build -l 3000
Vite

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​

TypeNameValue
A@your-vps-ip
Awwwyour-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:

  1. Log in to the Cloudflare dashboard
  2. Select your domain
  3. Go to DNS β†’ Records
  4. Add the A records above
Cloudflare Proxy Option

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:

  1. In Cloudflare, go to SSL/TLS
  2. Select Full mode (or Full (Strict) with an origin certificate)
  3. 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​

ActionCommand
View app statuspm2 status
View logspm2 logs mysite
Restart apppm2 restart mysite
Stop apppm2 stop mysite
Test Nginx confignginx -t
Reload Nginxsudo 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 status and 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
Environment Variables

For applications requiring environment variables, create a .env file:

nano /var/www/mysite/.env

And add it to .gitignore to avoid versioning it.