ForgePod ForgePod

Introduction to ForgePod

ForgePod is your self-hosted Platform-as-a-Service powered by Podman — deploy containerized applications to your own infrastructure with a single API call. Multi-node cluster architecture with automatic load balancing, built-in monitoring, and zero Docker dependency.

Prerequisites

Prerequisites

  • Ubuntu 24.04 LTS
  • Root or sudo access
  • At least 1 GB RAM + 10 GB disk per node

Control Plane

git clone <repo> forgepod && cd forgepod
sudo ./scripts/forgepod-cp-install.sh

This installs:

  • PostgreSQL + Redis
  • Podman v5 (via APT pinning from Plucky/25.04)
  • Buildah
  • Traefik (latest binary)
  • Python venv with FastAPI + dependencies
  • Systemd services: forgepod-api, forgepod-traefik

Verify Installation

systemctl status forgepod-api
systemctl status forgepod-traefik
curl http://localhost:9000/health
curl http://localhost:9000/docs # Swagger UI

Worker Node

git clone <repo> forgepod && cd forgepod
sudo ./scripts/forgepod-worker-install.sh \
http://CONTROL_PLANE_IP:9000

This installs:

  • Podman v5 (APT pinning)
  • Buildah
  • Python venv with Flask + psutil
  • Systemd services: forgepod-podman-api, forgepod-worker

Verify Worker

systemctl status forgepod-worker
systemctl status forgepod-podman-api

# On control plane:
curl http://CONTROL_PLANE_IP:9000/nodes

Troubleshooting

IssueSolution
forgepod-api fails to startCheck PostgreSQL: systemctl status postgresql
Worker not in /nodesCheck CONTROL_PLANE_URL env, verify connectivity
Podman v5 not installedRun apt-cache policy podman to verify pinning
Traefik unreachableCheck ufw status, ensure port 80 is open

Quick Start

Get ForgePod running with two commands:

git clone <repo> forgepod && cd forgepod
sudo ./scripts/forgepod-cp-install.sh

Then deploy your first app:

curl -X POST http://localhost:9000/deploy \
-H "Content-Type: application/json" \
-d '{"name": "demo", "image": "nginx", "replicas": 2}'

Your app is now available at http://demo.apps.example.com

API Reference

Base URL: http://CONTROL_PLANE_IP:9000 · Interactive Swagger UI at /docs

MethodEndpointDescription
GET/healthLiveness probe — returns {"status": "ok"}
GET/readyzReadiness probe — verifies database connection
POST/deployDeploy a new app or update existing
POST/scaleScale app to desired replica count
GET/appsList all deployed applications
GET/apps/{name}/logsStream aggregated logs
POST/stop/{name}Stop all containers, remove route
GET/nodesList worker nodes with status
POST/internal/node/registerRegister worker (internal)
POST/internal/node/heartbeat/{hostname}Heartbeat ping every 30s

Deploy Example

Request

curl -X POST http://CP_IP:9000/deploy \
-H "Content-Type: application/json" \
-d '{
"name": "myapp",
"image": "nginx",
"container_port": 80,
"replicas": 2
}'

Response

{
"status": "deployed",
"url": "http://myapp.apps.local",
"replicas_requested": 2,
"replicas_running": 2
}

Scale Example

Request

curl -X POST http://CP_IP:9000/scale \
-H "Content-Type: application/json" \
-d '{"name": "myapp", "replicas": 4}'

Response

{
"status": "scaled",
"app": "myapp",
"replicas": 4
}

CLI Reference

Use forgepodctl to manage your cluster from the terminal:

python3 cli/forgepodctl.py deploy demo nginx --replicas 2 # Deploy
python3 cli/forgepodctl.py apps # List apps
python3 cli/forgepodctl.py nodes # List nodes
python3 cli/forgepodctl.py logs demo # View logs
python3 cli/forgepodctl.py stop demo # Stop app

DNS & Cloudflare Setup

Point these DNS records to your Control Plane server's public IP:

TypeNameContentProxy
AapiSERVER_IPProxied ☁️
A*.appsSERVER_IPProxied ☁️

The wildcard *.apps.example.com allows Traefik to dynamically route traffic to each deployed app.

SSL/TLS Mode

Full (Strict) — encrypts traffic end-to-end between visitors ↔ Cloudflare ↔ server.

Environment Variable

# /etc/systemd/system/forgepod-api.service:
Environment="BASE_DOMAIN=apps.example.com"

sudo systemctl daemon-reload
sudo systemctl restart forgepod-api

Local Development Setup (Mac)

Test the entire ForgePod flow on Mac without Ubuntu, using Podman (lighter than Docker Desktop).

1. Install Podman

make podman-setup

# Or manually:
brew install podman
podman machine init \
--cpus 2 --memory 2048
podman machine start

2. Install Deps

make setup

3. Run Services

# Terminal 1
make dev-infra

# Terminal 2
make dev-api

# Terminal 3
make dev-worker

Cheat Sheet

CommandFunction
make podman-setupInstall Podman (one-time)
make setupInstall Python deps (one-time)
make dev-infraStart PostgreSQL + Redis
make dev-apiStart API server (port 9000)
make dev-workerStart mock worker (port 9001)
make testRun smoke tests
make dev-stopStop all services
make qualityRun all quality checks

Uninstall

Works on both control plane and worker nodes:

sudo ./scripts/forgepod-uninstall.sh