Skip to content

Getting Started with EPD

Deploy any application to one server or a fleet of servers with zero downtime, automatic Let's Encrypt SSL, and a shared Traefik proxy.

This guide will take you from zero to a live production deployment in under 5 minutes.


Prerequisites

Before starting, ensure you have:

  1. A Linux Server (VPS):

    • Any clean Linux VPS (Ubuntu 22.04/24.04, Debian 11/12, Fedora, Arch, etc.)
    • An open SSH port (22) with root or passwordless sudo access.
    • Public ports 80 (HTTP) and 443 (HTTPS) accessible from the internet.
    • A DNS A record pointing your domain to the server's public IP address.
  2. Local Machine:

    • Bun (v1.1+) or Node.js (v18+).
    • Standard ssh client.
    • Docker installed locally (if deploying in Docker mode).

No Server Yet?

If you don't have a server, you can provision one in 30 seconds using the built-in Hetzner Cloud integration:

bash
epd hetzner create my-server --setup

1. Install EPD

Install epd globally using your preferred package manager or download the standalone binary:

bash
bun install -g @fabioplunser/epd
bash
npm install -g @fabioplunser/epd
bash
pnpm add -g @fabioplunser/epd
bash
npx @fabioplunser/epd --help
bash
curl -fsSL https://github.com/FabioPlunser/epd/releases/latest/download/epd-linux-x64 -o /usr/local/bin/epd
chmod +x /usr/local/bin/epd

Verify installation:

bash
epd --version

2. Initialize Your Project

Navigate to your application's root directory:

bash
cd my-app
epd init

epd init will inspect your project:

  • Automatically detects your runtime (Node.js, Bun, Python, Go, Ruby, or static).
  • Detects whether you already have a Dockerfile.
  • Prompts for your server IP, domain name, and ACME SSL email.
  • Generates a tailored epd.yml config file (and an optimized starter Dockerfile if needed).

GitHub Actions Starter

Run epd init --ci to also generate a ready-to-run GitHub Actions workflow (.github/workflows/deploy.yml).


3. Configure epd.yml

Open epd.yml in your editor. Here is a typical single-server configuration:

yaml
# Application name (used for container naming and routing isolation)
name: my-app
mode: docker

# Docker image name (built locally, or pulled from registry)
image: my-app

# SSH connection details
ssh:
  user: root

# Server & Routing
servers:
  web:
    hosts: [203.0.113.10]
    port: 3000
    domains: [app.example.com]

# Shared Traefik Proxy & Automatic SSL
proxy:
  email: admin@example.com

# Health check probe before switching live traffic
healthcheck:
  path: /health
  timeout: 30

# Environment variables & secrets
env:
  clear:
    NODE_ENV: production
  secret:
    - DATABASE_URL
yaml
# Run code directly under PM2 without Docker on the host
name: my-app
mode: process

process:
  install: bun install --frozen-lockfile
  build: bun run build
  start: bun run start
  exclude: [".git", "node_modules", ".env", "dist"]

ssh:
  user: root

servers:
  web:
    hosts: [203.0.113.10]
    replicas: 2
    port: 3000
    domains: [app.example.com]

proxy:
  email: admin@example.com

Secrets Setup

Any secret declared under env.secret is resolved automatically from your local shell or .env file:

bash
# In your local .env or current shell:
export DATABASE_URL="postgres://user:password@host/dbname"

When you deploy, epd securely uploads secrets into a root-owned 0600 file on the remote server without saving secrets in git or container image layers.


4. Run Server Setup

Run epd setup once for each new server:

bash
epd setup

What epd setup does automatically:

  1. Validates SSH Connectivity to all configured servers.
  2. Installs Host Prerequisites: Installs Docker (or PM2 and Node/Bun in process mode) if not already present.
  3. Provisions Shared Traefik Reverse Proxy: Launches Traefik listening on ports 80 and 443 with Let's Encrypt automated ACME SSL certificate issuance.
  4. Creates Network & Storage: Configures the shared Docker bridge network (epd) and volume directories (/var/lib/epd).
  5. Runs Your First Deployment: Builds the app, starts the blue slot, verifies health checks, and registers the domain in Traefik.

5. Deploy Updates with Zero Downtime

Whenever you commit changes or want to deploy an update:

bash
epd deploy

epd deploy executes a zero-downtime blue/green swap:

  1. Builds the latest container image (or syncs process code).
  2. Starts the new version in the idle slot (e.g., green).
  3. Probes the internal health check endpoint until healthy.
  4. Atomically updates Traefik's dynamic routing to direct incoming requests to the new slot.
  5. Drains in-flight connections to the previous slot (blue) before gracefully stopping it.

Rollback Anytime

If an issue occurs after deployment, revert instantly to the previous version with:

bash
epd rollback

This re-activates the previous slot in seconds without rebuilding or re-uploading!


6. Inspect & Monitor

Use epd CLI commands to check your application's health:

bash
# Check running containers, active slots, and route status
epd status

# Stream live container logs
epd logs -f

# Follow logs specifically from your web service
epd logs --service web -f --lines 100

# Open an interactive shell inside a running replica
epd shell

Next Steps

Now that your application is live, explore additional capabilities:

Released under the MIT License.