Skip to content

Multi-Site Hosting on a Single VPS

Learn how epd lets you run multiple independent applications on a single $5 VPS without port collisions, conflicting SSL certificates, or downtime.


The Problem with Other Deployment Tools

Many deployment tools (like Kamal or basic Docker Compose setups) assume that one application owns the host's ports 80 and 443.

When you try to deploy a second application on the same machine:

  • The second proxy container fails to bind to port 80/443.
  • Or you have to manually configure an external Nginx or Traefik reverse proxy outside of your deployment tooling.
  • SSL certificates for different domains collide.

How EPD Solves Multi-Site Hosting

epd provisions a single, shared Traefik proxy on the host. Every application deployed with epd writes its own isolated dynamic routing file:

/var/lib/epd/proxy/dynamic/
├── blog.yml            # Managed by App 1 (blog.example.com)
├── store.yml           # Managed by App 2 (store.example.com)
└── docs.yml            # Managed by App 3 (docs.example.com)

Each app specifies its own domains and routes in its own epd.yml. When you deploy blog:

  1. epd only updates /var/lib/epd/proxy/dynamic/blog.yml.
  2. Traefik hot-reloads the changes in milliseconds.
  3. store and docs remain completely unaffected!

Example: Deploying Two Apps to One Server

App 1: Blog (epd.yml)

yaml
name: blog
mode: docker
image: my-dockerhub-user/blog

servers:
  web:
    hosts: [203.0.113.10]
    port: 3000
    domains: [blog.example.com]

proxy:
  email: admin@example.com

App 2: Store (epd.yml)

yaml
name: store
mode: process

process:
  install: bun install
  build: bun run build
  start: bun run start

servers:
  web:
    hosts: [203.0.113.10]
    port: 4000
    domains: [store.example.com]

proxy:
  email: admin@example.com

Both apps can be deployed, updated, or rolled back independently.


Isolated Decommissioning

If you ever want to permanently decommission an app:

bash
cd my-store-repo
epd remove

epd remove:

  • Stops and removes all containers or PM2 processes for store.
  • Deletes /var/lib/epd/proxy/dynamic/store.yml.
  • Traefik ceases routing traffic for store.example.com.
  • blog and all other applications continue running without interruption.

Next Steps

Released under the MIT License.