“Where each service carries its own deployment logic.”
Build once. Scan everywhere. Deploy with confidence.
💡 The Short Version
CapsuleBay is a self-contained hybrid CI/CD framework I built because I got tired of my homelab breaking every time I breathed near it.
Instead of having one giant deployment script or cloud pipeline that does everything (and fails spectacularly), CapsuleBay lets each service carry its own deployment logic.
Every app becomes a deployment capsule — a small Docker image that contains its own docker-compose.yml, configuration, and brain.
You push your code → CapsuleBay builds it, scans it for vulnerabilities, fetches secrets just-in-time, deploys it to your self-hosted environment, and even pings you on Discord when it’s done.
🧠 The Core Idea
In most setups, you’ve got a big centralized CI/CD pipeline trying to handle multiple apps at once — full of conditionals, shared scripts, and “if environment == prod” nightmares.
CapsuleBay flips that model.
Each app lives in its own folder (called a capsule) with:
- A
Dockerfile - A
docker-compose.yml
That capsule knows how to build and deploy itself, wherever you throw it — like a portable mini-infrastructure.
No shared scripts. No tangled YAMLs. No “why does this only work on staging?” energy.
☁️ The Hybrid CI/CD Setup
CapsuleBay runs across two layers — one in the cloud for validation, one local for deployment.
1️⃣ GitHub Actions – Cloud Validation
This stage makes sure everything’s safe to deploy.
- Builds each capsule image
- Runs Trivy and Snyk scans for vulnerabilities
- Uploads scan reports to GitHub for traceability
2️⃣ Jenkins – Self-Hosted Deployment
This stage actually does the heavy lifting.
- Builds and pushes verified images to a local registry
- Fetches secrets Just-In-Time from HashiCorp Vault (no stored
.envfiles!) - Wakes target VMs using the Proxmox API
- Deploys the capsule using its embedded
docker-compose.yml - Sends status updates to Discord with timestamps and duration
🔐 What “Just-In-Time” Secrets Mean
CapsuleBay doesn’t keep secrets around — it borrows them.
When a deployment starts, Jenkins asks HashiCorp Vault for the credentials needed by that app (like API tokens or DB passwords). Vault hands them over temporarily — Jenkins injects them into the container, then deletes them the moment deployment finishes.
The token Vault gives Jenkins also expires immediately after use, so even if someone snoops around later, there’s nothing left to find.
Think of it like a one-time key that unlocks the door, lets you deploy, then melts in your hand.
🐾 Explained by Cats
Imagine you have three cats:
- N8N
- Portainer
- WhoAmI
In a normal setup, you’d have to chase each cat around the house with a brush, food, and collar every time it’s feeding time (that’s you writing endless bash scripts).
With CapsuleBay, each cat carries its own backpack:
- Bowl (
Dockerfile) - Meal plan (
docker-compose.yml) - Key to the house (Vault secret, fetched only when needed)
When dinner time (deployment) comes, Jenkins yells:
“Alright, everyone to your stations.”
Each cat runs to its corner, fetches its one-time key, eats, and texts you on Discord when it’s full.
When done, the key evaporates — no one else can reuse it.
That’s CapsuleBay. 🐱💻
🧰 What’s Under the Hood
| Layer | What It Does | Tool |
|---|---|---|
| GitHub Actions | Validates builds & runs security scans | Trivy + Snyk |
| Jenkins | Handles self-hosted deployments | Jenkinsfile |
| Vault | Issues one-time, Just-In-Time secrets | HashiCorp Vault |
| Proxmox API | Powers on target VMs automatically | Proxmox |
| Discord Webhook | Sends real-time notifications | Discord |
🧩 Why It’s Cool
| Problem | CapsuleBay’s Fix |
|---|---|
| Shared pipeline chaos | Each service carries its own logic |
| Rebuilding the same image repeatedly | Immutable capsule images |
Leaky .env files |
Vault injects secrets JIT |
| Manual server babysitting | Jenkins powers on VMs automatically |
| No deployment visibility | Discord notifications with time and status |
🧪 Real Example
n8n/Dockerfile
FROM docker:27.0.3-cli-alpine3.20
RUN apk add --no-cache docker-cli-compose bash
WORKDIR /app
COPY . /app
ARG LAN_IP
ENV LAN_IP=$LAN_IP
CMD ["docker", "compose", "up", "-d"]
n8n/docker-compose.yml
version: "3.9"
services:
n8n:
image: n8nio/n8n:latest
ports:
- "5678:5678"
env_file:
- .env
When the image is built, it contains its own compose file — so it can deploy itself anywhere, anytime.
The .env file gets injected at runtime from Vault and is wiped immediately after use.
🪶 Adding a New Capsule
Adding a new service is simple:
- Create a folder like
myservice/ - Add a
Dockerfileanddocker-compose.yml - Add the folder name to Jenkins parameters
That’s it. CapsuleBay takes care of the rest — build, scan, and deploy — automatically.
🧭 Why It Actually Works
CapsuleBay quietly blends solid DevOps principles with homelab practicality:
- Immutable builds (every image is versioned)
- Just-in-Time secrets (no long-term credentials)
- Auditable deploys (Discord logs every step)
- Offline-friendly (no cloud dependency)
It’s basically Kubernetes for people who don’t want Kubernetes.
🚀 TL;DR
CapsuleBay makes deployments behave like collectible trading cards.
Each capsule has everything it needs to play itself — I just tell Jenkins which ones to summon.
It’s not corporate-scale DevOps. It’s homelab discipline meets automation freedom.
Built by @gustav0thethird
“Hold my beer, I am deploying.”


Top comments (0)