📦
Bunty

Deploy with PM2

PM2 is a production-grade process manager for Node.js and Bun applications. It provides automatic restarts, clustering, monitoring, and log management.

Installation

Install PM2 Globally

npm install -g pm2
# or
bun install -g pm2

Verify Installation

pm2 --version

Basic Setup

1. Create PM2 Ecosystem File

Create ecosystem.config.js in your project root:

module.exports = {
  apps: [{
    name: 'bunty-app',
    script: 'bun',
    args: 'run src/main.ts',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
    env_development: {
      NODE_ENV: 'development',
      PORT: 3001,
    }
  }]
};

2. Start Your Application

# Start with ecosystem file
pm2 start ecosystem.config.js

# Start in production mode
pm2 start ecosystem.config.js --env production

# Start with custom name
pm2 start ecosystem.config.js --name "my-bunty-app"

Advanced Configuration

Full Ecosystem Configuration

module.exports = {
  apps: [{
    name: 'bunty-api',
    script: 'bun',
    args: 'run src/main.ts',
    
    // Instances
    instances: 4, // or 'max' for all CPUs
    exec_mode: 'cluster',
    
    // Auto restart
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    
    // Restart delays
    min_uptime: '10s',
    max_restarts: 10,
    restart_delay: 4000,
    
    // Logs
    error_file: './logs/error.log',
    out_file: './logs/out.log',
    log_file: './logs/combined.log',
    time: true,
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    
    // Environment variables
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
    
    // Advanced
    kill_timeout: 5000,
    wait_ready: true,
    listen_timeout: 10000,
    
    // Cron restart (optional)
    cron_restart: '0 0 * * *', // Restart daily at midnight
  }]
};

Multiple Applications

module.exports = {
  apps: [
    {
      name: 'bunty-api',
      script: 'bun',
      args: 'run src/main.ts',
      instances: 'max',
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3000,
      }
    },
    {
      name: 'bunty-worker',
      script: 'bun',
      args: 'run src/worker.ts',
      instances: 2,
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
      }
    }
  ]
};

PM2 Commands

Process Management

# Start
pm2 start ecosystem.config.js

# Stop
pm2 stop bunty-app
pm2 stop all

# Restart
pm2 restart bunty-app
pm2 restart all

# Reload (zero-downtime)
pm2 reload bunty-app

# Delete
pm2 delete bunty-app
pm2 delete all

# List all processes
pm2 list
pm2 ls

Monitoring

# Monitor all processes
pm2 monit

# Show process details
pm2 show bunty-app

# Get process info
pm2 info bunty-app

# Dashboard
pm2 plus

Logs

# View all logs
pm2 logs

# View specific app logs
pm2 logs bunty-app

# View only errors
pm2 logs --err

# Clear logs
pm2 flush

# Enable log rotation
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7

Cluster Management

# Scale to 4 instances
pm2 scale bunty-app 4

# Scale up by 2
pm2 scale bunty-app +2

# Scale down by 1
pm2 scale bunty-app -1

Zero-Downtime Deployments

Using PM2 Reload

# Graceful reload (zero-downtime)
pm2 reload bunty-app

Application Code for Graceful Shutdown

// src/main.ts
import { BuntyApplication } from '@bunty/common';

async function bootstrap() {
  const app = await BuntyApplication.create({
    // ... config
  });

  await app.listen(3000);

  // Signal ready to PM2
  if (process.send) {
    process.send('ready');
  }

  // Graceful shutdown
  process.on('SIGINT', async () => {
    console.log('Received SIGINT, closing server...');
    await app.close();
    process.exit(0);
  });
}

bootstrap();

Update ecosystem config:

module.exports = {
  apps: [{
    name: 'bunty-app',
    script: 'bun',
    args: 'run src/main.ts',
    wait_ready: true,
    listen_timeout: 10000,
    kill_timeout: 5000,
  }]
};

Startup Scripts

Auto-start on Server Boot

# Generate startup script
pm2 startup

# This will output a command like:
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u youruser --hp /home/youruser

# Run the generated command
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u youruser --hp /home/youruser

# Save current process list
pm2 save

# To disable startup
pm2 unstartup systemd

Monitoring with PM2 Plus

Enable PM2 Plus

# Link to PM2 Plus
pm2 link <secret_key> <public_key>

# Or register
pm2 plus

Custom Metrics

import pmx from '@pm2/io';

// Custom metric
const activeUsers = pmx.metric({
  name: 'Active Users',
  value: () => {
    return getUserCount();
  }
});

// Custom action
pmx.action('clear cache', (reply) => {
  clearCache();
  reply({ success: true });
});

Environment Management

Multiple Environments

# Start with specific environment
pm2 start ecosystem.config.js --env production
pm2 start ecosystem.config.js --env development

# Update environment
pm2 restart bunty-app --update-env

Using .env Files

// ecosystem.config.js
require('dotenv').config();

module.exports = {
  apps: [{
    name: 'bunty-app',
    script: 'bun',
    args: 'run src/main.ts',
    env: {
      NODE_ENV: 'production',
      DATABASE_URL: process.env.DATABASE_URL,
      REDIS_URL: process.env.REDIS_URL,
    }
  }]
};

Deployment Workflow

Git-based Deployment

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'bunty-app',
    script: 'bun',
    args: 'run src/main.ts',
  }],
  deploy: {
    production: {
      user: 'deploy',
      host: 'your-server.com',
      ref: 'origin/main',
      repo: 'git@github.com:user/repo.git',
      path: '/var/www/bunty-app',
      'post-deploy': 'bun install && pm2 reload ecosystem.config.js --env production'
    }
  }
};

Deploy with:

# Setup
pm2 deploy ecosystem.config.js production setup

# Deploy
pm2 deploy ecosystem.config.js production

# Revert
pm2 deploy ecosystem.config.js production revert 1

Best Practices

1. Use Cluster Mode

{
  instances: 'max', // Use all CPUs
  exec_mode: 'cluster'
}

2. Set Memory Limits

{
  max_memory_restart: '1G'
}

3. Configure Log Rotation

pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 100M
pm2 set pm2-logrotate:retain 10
pm2 set pm2-logrotate:compress true

4. Use Wait Ready

{
  wait_ready: true,
  listen_timeout: 10000
}

5. Health Checks

{
  health_check: {
    path: '/health',
    interval: 30000, // 30 seconds
    timeout: 5000
  }
}

Troubleshooting

View Logs

pm2 logs bunty-app --lines 100

Check Process Status

pm2 status
pm2 describe bunty-app

Restart on Error

pm2 restart bunty-app

Clear Everything

pm2 kill
pm2 resurrect

Next Steps

Have questions? Join our Discord community
Found an issue? Edit this page on GitHub