Skip to main content

Overview

This guide covers deploying Dub to various hosting platforms. Dub is a Next.js application that can be deployed to any platform that supports Node.js.

Deployment Requirements

System Requirements

  • Node.js 23.11.0 or higher
  • pnpm 9.15.9 or higher
  • 2GB+ RAM (4GB+ recommended)
  • 10GB+ disk space
  • MySQL 8.0+ database

External Services

Ensure you have the following services configured:
  • MySQL Database - See Database Setup
  • Tinybird - For analytics
  • Upstash Redis - For caching
  • Upstash QStash - For background jobs
  • Email Service - Resend or SMTP
  • Domain Provider - For custom domains
Vercel is the recommended platform for deploying Next.js applications, including Dub.
1

Connect Repository

  1. Push your Dub fork to GitHub
  2. Go to vercel.com/new
  3. Import your repository
  4. Select the apps/web directory as the root
2

Configure Build Settings

Set the following build configuration:
  • Framework Preset: Next.js
  • Root Directory: apps/web
  • Build Command: cd ../.. && pnpm install && pnpm build --filter=web
  • Install Command: pnpm install
  • Output Directory: .next
3

Set Environment Variables

Add all required environment variables in Vercel project settings.See Environment Variables for the complete list.
You don’t need to set NEXTAUTH_URL on Vercel - it’s automatically detected.
4

Configure Domains

  1. Add your custom domain in Vercel project settings
  2. Update DNS records as instructed
  3. Wait for SSL certificate provisioning
5

Enable Cron Jobs

Vercel automatically detects cron jobs from vercel.json.Verify cron jobs are enabled in Project Settings → Cron Jobs.
Cron jobs require a Vercel Pro plan or higher.
6

Deploy

Click “Deploy” and wait for the build to complete.Vercel will:
  • Install dependencies
  • Build the application
  • Deploy to production
  • Set up automatic deployments for future commits

Vercel Configuration

Dub includes a vercel.json configuration file:
vercel.json
{
  "crons": [
    {
      "path": "/api/cron/domains/verify",
      "schedule": "0 * * * *"
    },
    {
      "path": "/api/cron/streams/update-workspace-clicks",
      "schedule": "* * * * *"
    },
    {
      "path": "/api/cron/usage",
      "schedule": "0 12 * * *"
    },
    {
      "path": "/api/cron/aggregate-clicks",
      "schedule": "0 0 * * *"
    }
  ],
  "functions": {
    "app/(ee)/api/cron/**/*.ts": {
      "maxDuration": 600
    }
  }
}

Railway

Railway provides simple deployment for full-stack applications.
1

Create New Project

  1. Go to railway.app
  2. Click “New Project”
  3. Select “Deploy from GitHub repo”
  4. Choose your Dub repository
2

Configure Service

Add the following configuration:
# Root directory
apps/web

# Build command
cd ../.. && pnpm install && pnpm build --filter=web

# Start command
cd apps/web && pnpm start
3

Set Environment Variables

Add all environment variables in Railway service settings.Railway provides a PostgreSQL database, but Dub requires MySQL. Add a MySQL service separately.
4

Add MySQL Service

  1. Click “New” → “Database” → “Add MySQL”
  2. Copy the connection string
  3. Add as DATABASE_URL environment variable
5

Configure Domain

  1. Go to service settings
  2. Add custom domain
  3. Update DNS records as instructed
6

Deploy

Railway automatically deploys when you push to your repository.

Railway Cron Jobs

Railway doesn’t have built-in cron support. Use external services:
  • Upstash QStash Schedules - Set up scheduled HTTP requests
  • Cron-job.org - Free cron job service
  • EasyCron - Paid cron service with monitoring
Configure scheduled requests to your cron endpoints with the CRON_SECRET header.

Docker Deployment

Deploy Dub using Docker for maximum control.

Create Dockerfile

Create Dockerfile in the repository root:
Dockerfile
FROM node:23-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install pnpm
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate

# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/web/package.json ./apps/web/
COPY packages ./packages/

# Install dependencies
RUN pnpm install --frozen-lockfile

# Build the application
FROM base AS builder
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate

COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Generate Prisma client
RUN pnpm --filter=@dub/prisma generate

# Build web app
RUN pnpm build --filter=web

# Production image
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Copy built application
COPY --from=builder /app/apps/web/.next/standalone ./
COPY --from=builder /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=builder /app/apps/web/public ./apps/web/public

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "apps/web/server.js"]

Build and Run

# Build image
docker build -t dub .

# Run container
docker run -d \
  --name dub \
  -p 3000:3000 \
  --env-file .env \
  dub

Docker Compose

Create docker-compose.prod.yml:
docker-compose.prod.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    env_file:
      - .env
    depends_on:
      - mysql
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: dub
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped
    command:
      [
        "--max_connections=1000",
        "--default-authentication-plugin=mysql_native_password",
      ]

volumes:
  mysql_data:
Deploy:
docker compose -f docker-compose.prod.yml up -d

AWS EC2

Deploy to Amazon EC2 for full infrastructure control.
1

Launch EC2 Instance

  1. Choose Ubuntu Server 22.04 LTS
  2. Instance type: t3.medium or larger
  3. Configure security group:
    • Allow SSH (port 22)
    • Allow HTTP (port 80)
    • Allow HTTPS (port 443)
2

Install Dependencies

SSH into your instance and install Node.js:
# Install Node.js 23
curl -fsSL https://deb.nodesource.com/setup_23.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install pnpm
npm install -g pnpm@9.15.9

# Install Nginx
sudo apt-get install -y nginx
3

Clone and Build

# Clone repository
git clone https://github.com/yourusername/dub.git
cd dub

# Install dependencies
pnpm install

# Build application
cd apps/web
pnpm build
4

Configure Environment

# Create .env file
nano .env
# Add all environment variables
5

Set Up PM2

Use PM2 for process management:
# Install PM2
npm install -g pm2

# Start application
pm2 start pnpm --name "dub" -- start

# Set up auto-restart
pm2 startup
pm2 save
6

Configure Nginx

Create Nginx configuration:
/etc/nginx/sites-available/dub
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_cache_bypass $http_upgrade;
        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;
    }
}
Enable site:
sudo ln -s /etc/nginx/sites-available/dub /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
7

Set Up SSL

Install Certbot for free SSL certificates:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com

EC2 Cron Jobs

Set up cron jobs using crontab:
crontab -e
Add cron jobs:
# Domain verification - hourly
0 * * * * curl -H "Authorization: Bearer $CRON_SECRET" https://yourdomain.com/api/cron/domains/verify

# Update workspace clicks - every minute
* * * * * curl -H "Authorization: Bearer $CRON_SECRET" https://yourdomain.com/api/cron/streams/update-workspace-clicks

# Usage reporting - daily at noon
0 12 * * * curl -H "Authorization: Bearer $CRON_SECRET" https://yourdomain.com/api/cron/usage

# Aggregate clicks - daily at midnight
0 0 * * * curl -H "Authorization: Bearer $CRON_SECRET" https://yourdomain.com/api/cron/aggregate-clicks

DigitalOcean App Platform

1

Create New App

  1. Go to DigitalOcean App Platform
  2. Click “Create App”
  3. Connect your GitHub repository
2

Configure Build

  • Source Directory: apps/web
  • Build Command: cd ../.. && pnpm install && pnpm build --filter=web
  • Run Command: cd apps/web && pnpm start
3

Add Database

Add a managed MySQL database in the same project.
4

Set Environment Variables

Add all required environment variables in app settings.
5

Deploy

Click “Deploy” and wait for the build to complete.

Render

1

Create Web Service

  1. Go to render.com
  2. Click “New” → “Web Service”
  3. Connect your repository
2

Configure Service

  • Root Directory: apps/web
  • Build Command: cd ../.. && pnpm install && pnpm build --filter=web
  • Start Command: cd apps/web && pnpm start
3

Set Environment Variables

Add all environment variables in service settings.
4

Deploy

Render automatically builds and deploys your application.

Cloudflare Pages

Cloudflare Pages has limitations with Next.js API routes and server-side rendering. Use Cloudflare Workers for API routes or choose a different platform.

Environment-Specific Configuration

Production Environment Variables

For production, ensure these are properly configured:
# Use production URLs
NEXTAUTH_URL=https://yourdomain.com
NEXT_PUBLIC_APP_DOMAIN=yourdomain.com

# Strong secret (32+ characters)
NEXTAUTH_SECRET=<generate-strong-secret>

# Production database
DATABASE_URL=<production-mysql-url>

# Production Redis
UPSTASH_REDIS_REST_URL=<production-redis-url>
UPSTASH_REDIS_REST_TOKEN=<production-redis-token>

Cron Jobs Configuration

Dub requires several cron jobs for proper operation:

Required Cron Jobs

EndpointScheduleDescription
/api/cron/domains/verify0 * * * *Verify domain DNS records
/api/cron/email-domains/verify0 * * * *Verify email domains
/api/cron/streams/update-workspace-clicks* * * * *Update workspace click counts
/api/cron/streams/update-partner-stats*/2 * * * *Update partner statistics
/api/cron/usage0 12 * * *Generate usage reports
/api/cron/aggregate-clicks0 0 * * *Aggregate daily click data

Securing Cron Endpoints

Set CRON_SECRET environment variable and include it in cron requests:
CRON_SECRET=<random-secret>
Cron job example:
curl -H "Authorization: Bearer $CRON_SECRET" https://yourdomain.com/api/cron/usage

Health Checks

Set up health checks for monitoring:
# Basic health check
curl https://yourdomain.com/api/health

# Database connectivity
curl https://yourdomain.com/api/health/db

Monitoring & Logging

Application Monitoring

Configure Axiom for logging:
AXIOM_TOKEN=<your-token>
AXIOM_DATASET=dub-production

Uptime Monitoring

Use services like:
  • UptimeRobot - Free uptime monitoring
  • Pingdom - Advanced monitoring and alerts
  • Better Uptime - Status pages and incident management

Scaling Considerations

Horizontal Scaling

For high traffic:
  1. Deploy multiple instances
  2. Use a load balancer (AWS ALB, Cloudflare, etc.)
  3. Ensure session affinity if using in-memory sessions
  4. Use Redis for session storage

Vertical Scaling

Increase server resources:
  • CPU: 2+ cores for production
  • RAM: 4GB minimum, 8GB+ recommended
  • Storage: SSD with 20GB+ free space

Database Scaling

  • Use read replicas for analytics queries
  • Enable query caching
  • Optimize indexes
  • Consider database connection pooling

Troubleshooting

Build Failures

# Clear cache and rebuild
find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +
find . -name '.next' -type d -prune -exec rm -rf '{}' +
pnpm install
pnpm build

Runtime Errors

Check logs:
# PM2 logs
pm2 logs dub

# Docker logs
docker logs dub

# Vercel logs
vercel logs

Database Connection Issues

Verify connectivity:
# Test connection
pnpm prisma:studio

# Check environment variables
env | grep DATABASE_URL

Production Checklist

  • All environment variables are set
  • Database is configured and accessible
  • SSL/TLS certificates are installed
  • Cron jobs are scheduled and running
  • Monitoring and logging are configured
  • Backup procedures are in place
  • Health checks are configured
  • Domain DNS is properly configured
  • Email delivery is tested and working
  • Rate limiting is enabled (via Edge Config)
  • Security headers are configured
  • Application performance is optimized

Next Steps

Build docs developers (and LLMs) love