How to Self-Host Dub Link Attribution Platform with Docker on Ubuntu 24.04 in 2025
How to Self-Host Dub Link Attribution Platform with Docker on Ubuntu 24.04 in 2025
Dub is an open-source link attribution platform that powers over 100M+ clicks monthly for companies like Twilio, Buffer, and Vercel. While Dub offers a hosted solution, self-hosting gives you complete control over your data, customization options, and cost management. This guide walks you through deploying Dub on Ubuntu 24.04 using Docker.
Why Self-Host Dub Instead of Using the Managed Service
Before diving into the setup, understand when self-hosting makes sense:
- Data sovereignty: Keep all link tracking data on your infrastructure
- Custom domain requirements: Full control over DNS and SSL configurations
- Cost optimization: Eliminate per-click pricing for high-volume scenarios
- Compliance needs: Meet specific regulatory requirements (GDPR, HIPAA)
- Development environment: Test features before production deployment
Self-hosting requires maintaining your own infrastructure, but for teams processing millions of clicks or those with strict data policies, the tradeoff is worthwhile.
Prerequisites for Self-Hosting Dub
Before starting, ensure you have:
- Ubuntu 24.04 LTS server (minimum 4GB RAM, 2 CPU cores)
- Root or sudo access
- Domain name with DNS access
- Node.js v23.11.0 installed
- pnpm 9.15.9 package manager
- Docker and Docker Compose installed
- Basic knowledge of environment variables and database connections
Step 1: Install Required Dependencies on Ubuntu 24.04
First, update your system and install Docker:
# Update package index
sudo apt update && sudo apt upgrade -y
# Install Docker prerequisites
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
# Add Docker GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Add your user to docker group
sudo usermod -aG docker $USER
newgrp docker
Install Node.js v23.11.0 using nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install 23.11.0
nvm use 23.11.0
# Install pnpm
npm install -g pnpm@9.15.9
Step 2: Clone and Configure the Dub Repository
Clone the official Dub repository:
cd /opt
sudo git clone https://github.com/dubinc/dub.git
sudo chown -R $USER:$USER dub
cd dub
Create your environment configuration file:
cp .env.example .env
Edit the .env file with your specific configuration. Here are the critical variables:
# Database Configuration
DATABASE_URL="mysql://user:password@localhost:3306/dub"
# Redis Configuration (Upstash or self-hosted)
UPSTASH_REDIS_REST_URL="your-redis-url"
UPSTASH_REDIS_REST_TOKEN="your-redis-token"
# NextAuth Configuration
NEXTAUTH_SECRET="generate-with-openssl-rand-base64-32"
NEXTAUTH_URL="https://yourdomain.com"
# Tinybird Analytics (optional for analytics)
TINYBIRD_API_KEY="your-tinybird-key"
# Email Configuration (Resend)
RESEND_API_KEY="your-resend-key"
# Stripe (if using payments)
STRIPE_SECRET_KEY="your-stripe-key"
STRIPE_WEBHOOK_SECRET="your-webhook-secret"
Generate a secure NextAuth secret:
openssl rand -base64 32
Step 3: Set Up Supporting Services
Dub's tech stack requires several services. Create a docker-compose.yml for the core infrastructure:
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: dub-mysql
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: dub
MYSQL_USER: dubuser
MYSQL_PASSWORD: dubpassword
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: dub-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: unless-stopped
volumes:
mysql-data:
redis-data:
Start the services:
docker compose up -d
Step 4: Database Setup and Prisma Migration
With MySQL running, initialize the database schema:
cd apps/web
pnpm install
pnpm prisma:push
This command pushes the Prisma schema to your database without creating migration files. If you encounter the error "The table <table-name> does not exist in the current database", this step resolves it.
Seed the database with development data:
pnpm run script dev/seed
For a clean seed (deleting existing data):
pnpm run script dev/seed --truncate
Step 5: Build and Deploy Dub Application
Return to the root directory and build the project:
cd /opt/dub
pnpm install
pnpm build
Common build errors and fixes:
- Build fails with TypeScript errors: Verify Node.js version is exactly v23.11.0
- Module not found errors: Delete all
node_modules,.next, and.turbodirectories:
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
find . -name ".next" -type d -prune -exec rm -rf '{}' +
find . -name ".turbo" -type d -prune -exec rm -rf '{}' +
pnpm install
pnpm build
Step 6: Configure Nginx Reverse Proxy
Install and configure Nginx:
sudo apt install -y nginx certbot python3-certbot-nginx
Create an Nginx configuration:
sudo nano /etc/nginx/sites-available/dub
Add this configuration:
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 the site:
sudo ln -s /etc/nginx/sites-available/dub /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Obtain SSL certificate:
sudo certbot --nginx -d yourdomain.com
Step 7: Create Systemd Service for Production
Create a systemd service to manage Dub:
sudo nano /etc/systemd/system/dub.service
Add this configuration:
[Unit]
Description=Dub Link Attribution Platform
After=network.target mysql.service redis.service
[Service]
Type=simple
User=your-username
WorkingDirectory=/opt/dub/apps/web
Environment=NODE_ENV=production
ExecStart=/home/your-username/.nvm/versions/node/v23.11.0/bin/pnpm start
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable dub
sudo systemctl start dub
sudo systemctl status dub
Comparing Self-Hosted vs Managed Dub Deployment
| Aspect | Self-Hosted | Managed (Vercel) | |--------|-------------|------------------| | Setup Time | 2-4 hours | 5 minutes | | Monthly Cost | $20-100 (VPS) | Usage-based | | Maintenance | Manual updates | Automatic | | Data Control | Full ownership | Third-party | | Scalability | Manual scaling | Auto-scaling | | Customization | Unlimited | Limited | | SSL/DNS | Self-managed | Automatic |
Performance Optimization Tips
- Enable Redis caching: Significantly reduces database queries
- Configure CDN: Use Cloudflare for static assets
- Database indexing: Monitor slow queries with
EXPLAIN - Resource monitoring: Install htop and monitor memory usage
- Log rotation: Configure logrotate to prevent disk space issues
Troubleshooting Common Issues
Port 3000 already in use:
sudo lsof -i :3000
sudo kill -9 <PID>
Database connection failures:
- Verify MySQL is running:
docker ps - Check credentials in
.envmatch docker-compose - Ensure DATABASE_URL format is correct
Prisma schema sync errors:
cd apps/web
pnpm prisma generate
pnpm prisma:push
Monitoring and Maintenance
Set up basic monitoring:
# Check application logs
journalctl -u dub -f
# Monitor Docker containers
docker stats
# Database backup script
mysqldump -u dubuser -p dub > backup-$(date +%Y%m%d).sql
Schedule weekly backups with cron:
crontab -e
# Add: 0 2 * * 0 /opt/dub/backup.sh
Next Steps After Deployment
Once Dub is running:
- Configure your first workspace and custom domain
- Set up conversion tracking with the Dub TypeScript SDK
- Integrate with your marketing automation tools
- Configure team access and SSO if needed (BoxyHQ integration)
- Set up analytics dashboards with Tinybird
For production workloads, consider deploying on managed platforms like DigitalOcean droplets with automated backups, Render for simplified container deployments, or Supabase for the database layer with built-in replication.
Self-hosting Dub gives you the foundation for a scalable link attribution system under your complete control. The open-source nature means you can customize every aspect while benefiting from the same platform used by industry-leading teams.
Recommended Tools
- DigitalOceanSimplicity in the cloud
- SupabaseThe open source Firebase alternative