πŸ“¦
Bunty

Deploy to DigitalOcean

Deploy your Bunty application to DigitalOcean using Droplets (VPS) or the App Platform (PaaS).

DigitalOcean App Platform is the easiest way to deploy with zero DevOps.

Quick Deploy

  1. Connect Repository

  2. Configure App

# .do/app.yaml
name: bunty-app
region: nyc
services:
  - name: api
    github:
      repo: yourusername/bunty-app
      branch: main
      deploy_on_push: true
    build_command: bun install
    run_command: bun run src/main.ts
    environment_slug: node-js
    instance_count: 2
    instance_size_slug: basic-xs
    http_port: 3000
    routes:
      - path: /
    envs:
      - key: NODE_ENV
        value: production
      - key: PORT
        value: "3000"
      - key: DATABASE_URL
        scope: RUN_TIME
        type: SECRET
    health_check:
      http_path: /health
      initial_delay_seconds: 30
      period_seconds: 10

databases:
  - name: bunty-db
    engine: PG
    production: true
    version: "15"

  - name: bunty-redis
    engine: REDIS
    production: true
    version: "7"

workers:
  - name: worker
    github:
      repo: yourusername/bunty-app
      branch: main
    build_command: bun install
    run_command: bun run src/worker.ts
    instance_count: 1
    instance_size_slug: basic-xs
    envs:
      - key: NODE_ENV
        value: production

jobs:
  - name: cleanup
    kind: PRE_DEPLOY
    github:
      repo: yourusername/bunty-app
      branch: main
    run_command: bun run migrate

Deploy via CLI

# Install doctl
# macOS
brew install doctl

# Linux
cd ~
wget https://github.com/digitalocean/doctl/releases/download/v1.94.0/doctl-1.94.0-linux-amd64.tar.gz
tar xf doctl-1.94.0-linux-amd64.tar.gz
sudo mv doctl /usr/local/bin

# Authenticate
doctl auth init

# Create app
doctl apps create --spec .do/app.yaml

# List apps
doctl apps list

# Deploy update
doctl apps update <app-id> --spec .do/app.yaml

# View logs
doctl apps logs <app-id>

Using Dockerfile

# .do/app.yaml
services:
  - name: api
    dockerfile_path: Dockerfile
    source_dir: /
    github:
      repo: yourusername/bunty-app
      branch: main

Option 2: Droplets (VPS)

Create Droplet

# Create droplet via CLI
doctl compute droplet create bunty-app \
  --size s-2vcpu-2gb \
  --image ubuntu-22-04-x64 \
  --region nyc1 \
  --ssh-keys <your-ssh-key-id> \
  --enable-monitoring \
  --wait

# Get droplet IP
doctl compute droplet list

Setup Droplet

# SSH into droplet
ssh root@your-droplet-ip

# Update system
apt update && apt upgrade -y

# Install Bun
curl -fsSL https://bun.sh/install | bash
source ~/.bashrc

# Install Node.js (optional)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
apt-get install -y nodejs

# Install PM2
npm install -g pm2

# Create deployment user
adduser --disabled-password deploy
usermod -aG sudo deploy
su - deploy

Deploy Application

# As deploy user
cd /home/deploy

# Clone repository
git clone https://github.com/yourusername/bunty-app.git
cd bunty-app

# Install dependencies
bun install --production

# Set up environment
nano .env.production
# Add your environment variables

# Start with PM2
pm2 start ecosystem.config.js --env production

# Save PM2 configuration
pm2 save
pm2 startup

# Setup Nginx
sudo apt install nginx -y

Configure Nginx

sudo nano /etc/nginx/sites-available/bunty-app
server {
    listen 80;
    server_name your-domain.com www.your-domain.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;
    }
}
# Enable site
sudo ln -s /etc/nginx/sites-available/bunty-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

# Install SSL with Let's Encrypt
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Managed Databases

Create PostgreSQL Database

# Via doctl
doctl databases create bunty-db \
  --engine pg \
  --region nyc1 \
  --size db-s-1vcpu-1gb \
  --version 15

# Get connection details
doctl databases connection bunty-db

# Create database
doctl databases db create bunty-db bunty

Create Redis Cluster

# Create Redis cluster
doctl databases create bunty-cache \
  --engine redis \
  --region nyc1 \
  --size db-s-1vcpu-1gb \
  --version 7

# Get connection string
doctl databases connection bunty-cache

Use in Application

import { DatabaseModule } from '@bunty/orm';

@Module({
  imports: [
    DatabaseModule.forRoot({
      host: 'bunty-db-do-user-xxx.db.ondigitalocean.com',
      port: 25060,
      database: 'bunty',
      user: 'doadmin',
      password: process.env.DB_PASSWORD,
      ssl: {
        rejectUnauthorized: true,
        ca: process.env.DB_CA_CERT,
      },
    }),
  ],
})
export class AppModule {}

Spaces (Object Storage)

Create Space

# Create Space (S3-compatible)
doctl compute spaces create bunty-uploads --region nyc3

# List spaces
doctl compute spaces list

Use in Application

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  endpoint: 'https://nyc3.digitaloceanspaces.com',
  region: 'us-east-1', // Can be any region
  credentials: {
    accessKeyId: process.env.SPACES_KEY,
    secretAccessKey: process.env.SPACES_SECRET,
  },
});

async function upload(key: string, body: Buffer) {
  await s3.send(new PutObjectCommand({
    Bucket: 'bunty-uploads',
    Key: key,
    Body: body,
    ACL: 'public-read',
  }));

  return `https://bunty-uploads.nyc3.digitaloceanspaces.com/${key}`;
}

Load Balancer

Create Load Balancer

# Create load balancer
doctl compute load-balancer create \
  --name bunty-lb \
  --region nyc1 \
  --forwarding-rules entry_protocol:http,entry_port:80,target_protocol:http,target_port:3000 \
  --health-check protocol:http,port:3000,path:/health,check_interval_seconds:10 \
  --droplet-ids <droplet-id-1>,<droplet-id-2>

Configure SSL

# Add HTTPS forwarding rule
doctl compute load-balancer update <lb-id> \
  --forwarding-rules entry_protocol:https,entry_port:443,target_protocol:http,target_port:3000,certificate_id:<cert-id>

Container Registry

Push to Container Registry

# Create registry
doctl registry create bunty-registry

# Login
doctl registry login

# Build and tag
docker build -t bunty-app .
docker tag bunty-app registry.digitalocean.com/bunty-registry/bunty-app:latest

# Push
docker push registry.digitalocean.com/bunty-registry/bunty-app:latest

Kubernetes (DOKS)

Create Kubernetes Cluster

# Create cluster
doctl kubernetes cluster create bunty-k8s \
  --region nyc1 \
  --node-pool "name=workers;size=s-2vcpu-2gb;count=3;auto-scale=true;min-nodes=2;max-nodes=5"

# Get kubeconfig
doctl kubernetes cluster kubeconfig save bunty-k8s

# Deploy
kubectl apply -f k8s/

Monitoring

Enable Monitoring

# Create monitoring alert
doctl monitoring alert create \
  --type v1/insights/droplet/cpu \
  --compare GreaterThan \
  --value 80 \
  --window 5m \
  --emails your@email.com

# View metrics
doctl monitoring metrics cpu <droplet-id>

Install Monitoring Agent

# On droplet
curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash

# Verify
systemctl status do-agent

Automated Deployments

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to DigitalOcean

on:
  push:
    branches: [ main ]

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

      - name: Install doctl
        uses: digitalocean/action-doctl@v2
        with:
          token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

      - name: Build and push to DOCR
        run: |
          doctl registry login
          docker build -t registry.digitalocean.com/bunty-registry/bunty-app:${{ github.sha }} .
          docker push registry.digitalocean.com/bunty-registry/bunty-app:${{ github.sha }}

      - name: Update App Platform
        run: |
          doctl apps update ${{ secrets.APP_ID }} \
            --image registry.digitalocean.com/bunty-registry/bunty-app:${{ github.sha }}

Deploy Script

#!/bin/bash
# deploy.sh

echo "Deploying to DigitalOcean..."

# Pull latest code
git pull origin main

# Install dependencies
bun install --production

# Run migrations
bun run migrate

# Reload PM2
pm2 reload bunty-app --update-env

echo "Deployment complete!"

Firewall

Create Firewall

# Create firewall
doctl compute firewall create \
  --name bunty-firewall \
  --inbound-rules "protocol:tcp,ports:22,sources:addresses:0.0.0.0/0,sources:addresses:::/0 protocol:tcp,ports:80,sources:addresses:0.0.0.0/0,sources:addresses:::/0 protocol:tcp,ports:443,sources:addresses:0.0.0.0/0,sources:addresses:::/0" \
  --outbound-rules "protocol:tcp,ports:all,destinations:addresses:0.0.0.0/0,destinations:addresses:::/0" \
  --droplet-ids <droplet-id>

Backups

Enable Droplet Backups

# Enable backups
doctl compute droplet-action enable-backups <droplet-id>

# List backups
doctl compute droplet-action snapshots <droplet-id>

Database Backups

# Get backup info
doctl databases backups list bunty-db

# Restore from backup
doctl databases restore bunty-db <backup-id>

Cost Optimization

  • Use App Platform for variable workloads ($5-12/month)
  • Start with smaller droplets ($6/month)
  • Use auto-scaling
  • Enable database backups
  • Use Spaces instead of block storage when possible

Next Steps

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