Skip to content

Instantly share code, notes, and snippets.

@AtharvaCM
Created October 1, 2024 18:08
Show Gist options
  • Save AtharvaCM/c0e5dcbe9eab79ae12ed29bb400413bc to your computer and use it in GitHub Desktop.
Save AtharvaCM/c0e5dcbe9eab79ae12ed29bb400413bc to your computer and use it in GitHub Desktop.
Step-by-step guide to deploy a Next.js app on a VPS with PM2, Nginx, GitHub Actions, and Certbot SSL

VPS Next.js App Deployment Guide

This guide explains how to deploy a Next.js app on a VPS running Ubuntu Server, using PM2, Nginx, and GitHub Actions for continuous deployment. SSL is handled by Certbot, and Fail2Ban with Nginx rate limiting is used for basic security.


1. Provision a VPS and Set Up SSH Access

  • Get a VPS: Purchase a VPS running Ubuntu Server from your preferred cloud provider.
  • Connect via SSH: Open a terminal and connect to your VPS.
    ssh username@your-vps-ip

2. Install Node.js via NVM

  • Install NVM (Node Version Manager):
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
    source ~/.bashrc
    nvm install --lts
  • Verify installation:
    node -v

3. Install PM2

  • Install PM2:
    npm install pm2@latest -g
  • Verify PM2 installation:
    pm2 -v

4. Clone Your Next.js Application

  • Create a directory for your app:
    mkdir ~/my-app
    cd ~/my-app
  • Clone your repository:
    git clone https://github.com/your-username/your-repo.git .

5. Install Dependencies

  • Install your application dependencies:
    npm install

6. Run Your Application with PM2

  • Start your Next.js app using PM2:
    pm2 start npm --name "my-app" -- start
  • Save the PM2 process:
    pm2 save
  • Configure PM2 to start on server boot:
    pm2 startup

7. Configure Nginx as a Reverse Proxy

  • Install Nginx:
    sudo apt update
    sudo apt install nginx
  • Configure Nginx to point to your Node.js app:
    sudo nano /etc/nginx/sites-available/my-app
  • Add the following Nginx configuration:
    server {
        listen 80;
        server_name my-app.example.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;
        }
    }
  • Enable the configuration:
    sudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/
  • Test and reload Nginx:
    sudo nginx -t
    sudo systemctl reload nginx

8. Update DNS to Point to Your VPS

  • Go to your DNS/domain provider and set up an A record pointing my-app.example.com to your VPS's public IP.

9. Install and Configure Certbot for SSL

  • Install Certbot:
    sudo apt install certbot python3-certbot-nginx
  • Generate SSL certificate:
    sudo certbot --nginx -d my-app.example.com
  • Enable auto-renewal:
    sudo systemctl enable certbot.timer

10. Harden Security with Fail2Ban and Nginx Rate Limiting

  • Install Fail2Ban:
    sudo apt install fail2ban
  • Configure Nginx rate limiting by adding these lines to /etc/nginx/nginx.conf:
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
  • Apply rate limiting to your app:
    location / {
        limit_req zone=one burst=5;
        proxy_pass http://localhost:3000;
    }
  • Restart Nginx:
    sudo systemctl restart nginx

11. Automate Deployment with a Bash Script

  • Create a deploy.sh script for building and restarting your app.
    #!/bin/bash
    cd /path/to/your/app
    git pull origin main
    npm run build
    rm -rf .next && mv .next_temp .next
    pm2 restart my-app
  • Make the script executable:
    chmod +x deploy.sh

12. Set Up a Basic Node.js App for Webhooks

  • Create a simple Node.js webhook listener:
    const express = require('express');
    const { exec } = require('child_process');
    const app = express();
    app.use(express.json());
    
    const SECRET = 'your-secret-token';
    
    app.post('/webhook', (req, res) => {
        const token = req.headers['x-secret'];
        if (token === SECRET) {
            exec('./deploy.sh', (err, stdout, stderr) => {
                if (err) return res.status(500).send('Deployment failed.');
                res.status(200).send('Deployment successful.');
            });
        } else {
            res.status(401).send('Unauthorized');
        }
    });
    
    app.listen(4000, () => console.log('Webhook listener running on port 4000'));
  • Start the app with PM2:
    pm2 start node webhook.js --name "webhook"

13. Automate Deployment with GitHub Actions

  • Add a GitHub Actions workflow under .github/workflows/deploy.yml:
    name: Deploy to VPS
    
    on:
      push:
        branches:
          - main
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout code
            uses: actions/checkout@v2
    
          - name: Trigger deployment webhook
            run: |
              curl -X POST https://my-app.example.com/webhook             -H "x-secret: your-secret-token"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment