Back to articles
Technology Insight

Self-Hosting a Branded Open-Source Link Shortener: A Complete Guide to Deploying Dub.sh with Docker on a VPS

May 30, 2026

Introduction: The Business Case for Branded Link Shorteners

In the modern digital ecosystem, every touchpoint with your audience impacts brand trust and conversion rates. Generic link shorteners like Bitly or TinyURL have served their purpose, but they come with significant trade-offs: high recurring subscription costs for premium features, potential security risks, and a loss of brand identity. For enterprise organizations and growing businesses, branded links (e.g., yourbrand.co/join) increase click-through rates by up to 34% compared to generic alternatives.

Enter Dub.sh, the leading open-source link management platform designed for modern marketing and engineering teams. Boasting built-in geo-targeting, device routing, and deep analytical insights, Dub.sh matches the feature set of expensive enterprise tiers while allowing you to retain 100% data ownership. In this technical guide, we will demonstrate how to architect and self-host Dub.sh on your own Virtual Private Server (VPS) utilizing Docker and Docker Compose, ensuring a secure, scalable, and highly performant deployment.

Prerequisites and Infrastructure Requirements

Before initiating the deployment process, ensure your infrastructure meets the following baseline requirements to guarantee optimal performance and stability:

  • Virtual Private Server (VPS): A minimum of 2 vCPUs, 4GB RAM, and 40GB SSD storage (Ubuntu 22.04 LTS or 24.04 LTS is highly recommended).
  • Domain Configuration: A primary domain or subdomain (e.g., ln.yourbrand.com) with access to its DNS management console.
  • Containerization Tools: Docker Engine (v24.0+) and Docker Compose (v2.0+) installed on the host system.
  • External Managed Services: Dub.sh utilizes powerful background utilities. You will need access to an external PostgreSQL database, a Redis instance (for caching and rate-limiting), and a Upstash Redis or similar queue system if handling extreme traffic loads. Upstash is particularly recommended due to its seamless integration with Dub.sh's core architecture.

Step 1: Preparing the VPS Environment

To begin, establish an SSH connection to your VPS and ensure the underlying system packages are fully updated. Run the following commands sequentially:

sudo apt update && sudo apt upgrade -y
sudo apt install curl git apt-transport-https ca-certificates gnupg lsb-release -y

Next, construct a dedicated directory structure for your Dub.sh application deployment. This isolates application configurations and persistent volumes effectively:

mkdir -p ~/dub-sh && cd ~/dub-sh

Step 2: Configuring Essential Environment Variables

Dub.sh relies extensively on environment variables to manage security tokens, database connection strings, and application behavior. Create an .env file in your deployment directory:

nano .env

Populate the file with the following critical parameters, substituting the placeholder text with your actual production credentials:

Security Note: Always utilize cryptographically secure, random keys for NEXTAUTH_SECRET and DUB_SECRET to prevent unauthorized session manipulation.
# Core Application Configuration
NEXT_PUBLIC_APP_NAME="Your Brand Shortener"
NEXTAUTH_URL="[https://ln.yourbrand.com](https://ln.yourbrand.com)"
NEXTAUTH_SECRET="your-super-secret-nextauth-key-change-me"
DUB_SECRET="your-internal-dub-secret-key-change-me"

# Database Configurations
DATABASE_URL="postgresql://username:password@your-postgres-host:5432/dubdb?sslmode=require"
CLICKHOUSE_URL="https://your-clickhouse-host:8123"
CLICKHOUSE_USER="default"
CLICKHOUSE_PASSWORD="your-clickhouse-password"

# Redis Cache Configuration
REDIS_URL="rediss://default:your-redis-password@your-redis-host:6379"

# Storage & Emails (For assets and notifications)
STORAGE_PROVIDER="s3"
STORAGE_ACCESS_KEY_ID="your-s3-access-key"
STORAGE_SECRET_ACCESS_KEY="your-s3-secret-key"
STORAGE_BUCKET="your-dub-bucket-name"

SMTP_HOST="smtp.sendgrid.net"
SMTP_PORT=587
SMTP_USER="apikey"
SMTP_PASSWORD="your-smtp-api-key"
NEXT_PUBLIC_APP_DOMAIN="ln.yourbrand.com"

Step 3: Writing the Docker Compose File

With environment parameters safely defined, define the orchestration structure utilizing Docker Compose. Create a docker-compose.yml file within the same directory:

nano docker-compose.yml

Insert the standard multi-container application blueprint configuration below:

version: '3.8'

services:
  dub:
    image: dubinc/dub:latest
    container_name: dub-app
    restart: always
    ports:
      - "3000:3000"
    env_file:
      - .env
    environment:
      - NODE_ENV=production
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  nginx-proxy:
    image: nginx:alpine
    container_name: dub-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
    depends_on:
      - dub

Step 4: Nginx Reverse Proxy and SSL Configuration

To safely expose Dub.sh to the web and route SSL encrypted traffic efficiently, establish an Nginx reverse proxy configuration. Create the nginx.conf file referencing the upstream container node:

nano nginx.conf

Incorporate the following block mapping traffic securely to internal container port 3000:

events { worker_connections 1024; }

http {
    upstream dub_upstream {
        server dub:3000;
    }

    server {
        listen 80;
        server_name ln.yourbrand.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name ln.yourbrand.com;

        ssl_certificate /etc/letsencrypt/live/[ln.yourbrand.com/fullchain.pem](https://ln.yourbrand.com/fullchain.pem);
        ssl_certificate_key /etc/letsencrypt/live/[ln.yourbrand.com/privkey.pem](https://ln.yourbrand.com/privkey.pem);
        ssl_protocols TLSv1.2 TLSv1.3;

        location / {
            proxy_pass http://dub_upstream;
            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;
        }
    }
}

Note: Before deploying Nginx via Compose, ensure you run Certbot locally on the host to generate the SSL keys specified in the /etc/letsencrypt directory mapping.

Step 5: Launching and Initializing the Infrastructure

Execute the container builds and initialize the microservices in detached daemon mode utilizing the Docker Compose binary ecosystem:

docker compose up -d

Verify application initialization and check server health runtime responses via container log output stream commands:

docker compose logs -f dub

Once logs indicate successful database schema syncs and Next.js engine bindings, navigate directly to [https://ln.yourbrand.com](https://ln.yourbrand.com) via a desktop web browser to access the administrator creation onboarding interface.

Conclusion and Best Maintenance Practices

Congratulations! You have successfully broken away from restrictive software-as-a-service frameworks by deploying your own enterprise-grade open-source link shortener. By controlling your own instance of Dub.sh with Docker on a private VPS, your team secures unmatched analytic granularity alongside pristine data sovereign parameters.

To keep your production deployment stable long-term, adopt these essential infrastructure maintenance practices:

  1. Automate Backups: Schedule daily cron jobs to back up your underlying PostgreSQL data storage layer securely to remote cloud targets.
  2. Monitor Resources: Implement metrics aggregators like Prometheus or basic system monitoring tools to keep track of CPU and RAM spikes.
  3. Perform Timely Updates: Regularly pull down newer production Docker images from dubinc/dub to patch potential application-level vulnerabilities and seamlessly deploy newly released feature enhancements.
Self-Hosting a Branded Open-Source Link Shortener: A Complete Guide to Deploying Dub.sh with Docker on a VPS | DPTCloud