Automated Deployments with GitHub Actions (CI/CD)
epd is designed to be executed directly inside GitHub Actions. Because your entire deployment configuration (services, replicas, ports, health probes, zero-downtime blue/green slots, accessories, domains, and DNS sync) is declared in epd.yml, your CI/CD workflow is concise and maintainable.
1. Quick Setup
Generate a preconfigured workflow automatically with:
epd init --ciThis creates .github/workflows/deploy.yml in your repository.
2. Complete Workflow Example
Create .github/workflows/deploy.yml:
name: Deploy
on:
push:
branches: [main]
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # Do not cancel in-flight deployments
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Configure SSH Agent
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy with EPD
run: npx @fabioplunser/epd deploy
env:
# DNS & Cloud Provider Tokens (if used in epd.yml)
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
HETZNER_API_TOKEN: ${{ secrets.HETZNER_API_TOKEN }}
HETZNER_DNS_API_TOKEN: ${{ secrets.HETZNER_DNS_API_TOKEN }}
# Application Secrets referenced in epd.yml
DATABASE_URL: ${{ secrets.DATABASE_URL }}
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}3. Configuring SSH Deploy Keys
To allow GitHub Actions to securely communicate with your server(s):
1. Generate an SSH Key Pair
Run on your local machine:
ssh-keygen -t ed25519 -C "github-actions-epd" -f /tmp/epd_deploy_key2. Add the Public Key to Your Server
Copy the contents of /tmp/epd_deploy_key.pub to /root/.ssh/authorized_keys on each server configured in epd.yml.
3. Add the Private Key to GitHub Secrets
In your GitHub repository:
- Go to Settings → Secrets and variables → Actions.
- Click New repository secret.
- Name:
SSH_PRIVATE_KEY - Secret: Paste the entire contents of
/tmp/epd_deploy_key(including-----BEGIN OPENSSH PRIVATE KEY-----and-----END OPENSSH PRIVATE KEY-----).
4. Docker Image Strategies in CI/CD
epd gives you three flexible approaches for handling Docker container images in GitHub Actions:
Strategy A: Zero Registry (Easiest)
If you do not specify a registry: in epd.yml:
- The image is built on GitHub's runner.
- It is saved and streamed directly over SSH to the target server (
docker save | ssh docker load). - No container registry account or setup required.
Strategy B: GitHub Container Registry (ghcr.io)
If deploying to multiple servers or wanting fast image caching:
In epd.yml:
image: ghcr.io/${{ github.repository }}/app
registry:
server: ghcr.io
username: ${{ github.actor }}
password_env: GITHUB_TOKENIn .github/workflows/deploy.yml:
- name: Deploy with EPD
run: npx @fabioplunser/epd deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Strategy C: Remote Server Build
Build the image directly on the remote server using host CPU/memory and local layer cache:
# epd.yml
build:
remote: true5. Multi-Environment Deployments (Staging vs. Production)
Use epd destination overlays:
# .github/workflows/deploy-staging.yml
on:
push:
branches: [develop]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY_STAGING }}
- run: npx @fabioplunser/epd deploy -d stagingThis applies epd.staging.yml over your base epd.yml.
Related Documentation
- Getting Started Guide: Step-by-step onboarding walkthrough.
- Hetzner Cloud & DNS: Provision servers and sync DNS records automatically.
- CLI Commands Reference: Command-line reference for
epd deploy.