How to Deploy a Node.js App on a UK VPS in 15 Minutes

Deploy any Node.js app — Express, Fastify, Next.js, or NestJS — on a UK VPS in under 15 minutes for as little as $5/mo. Includes PM2, NGINX, SSL, PostgreSQL, and CI/CD.

Introduction

Deploying a Node.js app shouldn't cost $50/mo on Heroku or require a DevOps degree. With a UK VPS from Hostingowy, you can deploy any Node.js application — Express, Fastify, Next.js, or NestJS — in under 15 minutes for as little as $5/mo.

In this guide, you'll set up a production-grade Node.js deployment with: - PM2 process manager (auto-restart on crash) - NGINX reverse proxy with SSL - PostgreSQL database - GitHub Actions CI/CD - Monitoring and log rotation

---

Step 1: Provision Your VPS

Log into Hostingowy.com and deploy a VPS:

  • OS: Ubuntu 24.04 LTS
  • Plan: Starter ($5/mo) for small apps, Business ($12/mo) for production
  • Location: UK (London datacentre)

Once deployed, you'll receive your root password and IP address.

Step 2: Initial Server Setup

SSH into your server:

ssh root@your-vps-ip

Run these essential security steps:

# Update packages
apt update && apt upgrade -y

Create a deploy user

adduser deploy usermod -aG sudo deploy

Copy SSH key

mkdir -p /home/deploy/.ssh cp ~/.ssh/authorized_keys /home/deploy/.ssh/ chown -R deploy:deploy /home/deploy/.ssh

Harden SSH

sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config systemctl restart sshd

Step 3: Install Node.js

Install Node.js 20 LTS:

curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
node --version  # Should show v20.x
npm --version   # Should show 10.x

Install PM2 globally:

npm install -g pm2
pm2 startup systemd

Step 4: Install and Configure PostgreSQL

apt install -y postgresql
systemctl start postgresql
systemctl enable postgresql

Create database

sudo -u postgres createuser --interactive # Create user: app_user sudo -u postgres createdb app_db -O app_user

Set a password for your database user:

sudo -u postgres psql -c "ALTER USER app_user WITH PASSWORD 'secure_password';"

Step 5: Deploy Your Application

On your local machine, prepare your app for deployment. Example ecosystem.config.js for PM2:

module.exports = {
  apps: [{
    name: 'myapp',
    script: 'server.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
      DATABASE_URL: 'postgresql://app_user:secure_password@localhost:5432/app_db'
    },
    max_memory_restart: '500M',
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    error_file: '/var/log/myapp/error.log',
    out_file: '/var/log/myapp/out.log',
    merge_logs: true
  }]
};

Deploy the code to your server:

# From your local machine
rsync -avz --exclude 'node_modules' --exclude '.env' ./app/ deploy@your-vps-ip:/home/deploy/myapp/

SSH into server

ssh deploy@your-vps-ip

Install dependencies and start

cd /home/deploy/myapp npm install --production pm2 start ecosystem.config.js pm2 save

Step 6: Set Up NGINX Reverse Proxy with SSL

Install NGINX:

apt install -y nginx

Create the site configuration at /etc/nginx/sites-available/myapp:

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_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; proxy_read_timeout 60s; } }

Enable the site and get SSL:

ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Install SSL with Certbot

apt install -y certbot python3-certbot-nginx certbot --nginx -d yourdomain.com --non-interactive --agree-tos -m admin@yourdomain.com

Step 7: Set Up CI/CD with GitHub Actions

Create .github/workflows/deploy.yml in your repository:

name: Deploy to UK VPS
on:
  push:
    branches: [main]

jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4

  • name: Install dependencies
  • run: npm ci --production
  • name: Deploy via rsync
  • uses: easingthemes/ssh-deploy@v4.1.0
  • with:
  • ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
  • remote-host: ${{ secrets.VPS_HOST }}
  • remote-user: deploy
  • source: "."
  • target: "/home/deploy/myapp"
  • name: Restart application
  • uses: appleboy/ssh-action@v1.0.3
  • with:
  • host: ${{ secrets.VPS_HOST }}
  • username: deploy
  • key: ${{ secrets.SSH_PRIVATE_KEY }}
  • script: |
  • cd /home/deploy/myapp
  • pm2 reload ecosystem.config.js

Step 8: Monitoring and Logs

Health checks with UptimeRobot

Get notified within 5 minutes if your app goes down:

  1. Create an UptimeRobot account
  2. Add a HTTP monitor for https://yourdomain.com
  3. Set check interval to 5 minutes
  4. Add SMS/email alert contacts

View logs

# PM2 logs
pm2 logs myapp --lines 100

System logs

journalctl -u nginx --since "1 hour ago"

Application error log

tail -f /var/log/myapp/error.log

Auto-healing

PM2 restarts your app automatically if it crashes. Add a health check endpoint:

// server.js
app.get('/health', (req, res) => {
  res.json({ status: 'ok', uptime: process.uptime() });
});

Then configure PM2 to check it:

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myapp',
    script: 'server.js',
    instances: 'max',
    exec_mode: 'cluster',
    max_memory_restart: '500M',
    // Auto-healing health check
    min_uptime: '10s',
    max_restarts: 10,
    restart_delay: 5000
  }]
};

Cost Comparison: UK VPS vs Heroku vs DigitalOcean Apps

Service1 GB RAM / 1 vCPU4 GB RAM / 2 vCPUNotes
Hostingowy Starter/Business$5/mo$12/moFull root access, UK datacentre
Heroku Basic$25/mo$50/moNo root, ephemeral storage
DigitalOcean App Platform$24/mo$48/moLimited customisation
Railway$12/mo$36/moNo SSH access
AWS Elastic Beanstalk~$15/mo~$45/moComplex setup, surprise fees

Annual saving with Hostingowy Business plan vs Heroku: $456/year.

Troubleshooting

App crashes immediately

pm2 logs myapp --lines 50  # Check error output
journalctl -u nginx        # Check for port conflicts

Cannot connect to database

# Check PostgreSQL status
systemctl status postgresql
sudo -u postgres psql -c "\l"

SSL certificate not renewing

certbot renew --dry-run

Check port 80 is accessible from internet

NGINX 502 Bad Gateway

# App is likely not running
pm2 list

Restart if needed

pm2 restart myapp

Next Steps

Your Node.js app is now deployed on a UK VPS with: - ✅ Automatic restarts (PM2) - ✅ SSL/TLS (Certbot) - ✅ Auto-deploy from GitHub - ✅ Database (PostgreSQL) - ✅ Monitoring (UptimeRobot) - ✅ UK data residency (GDPR compliant)

Ready to deploy? Use code LAUNCH100 for your first month free.

Deploy Your VPS → | View Pricing →

🚀 Ready for VPS hosting that actually performs?

Spin up your first UK VPS in under 60 seconds. NVMe storage, UK data centre, root access.

Get Started — From $5/mo
Hostingowy Engineering
Hostingowy Team — UK VPS Infrastructure