An open API service indexing awesome lists of open source software.

https://github.com/leostera/gumgum


https://github.com/leostera/gumgum

Last synced: about 1 month ago
JSON representation

Awesome Lists containing this project

README

          

# gumgum

gumgum is a self-hosted app platform for your VPS or local machine. It gives small projects a Cloudflare-like workflow without handing the runtime to a hosted control plane: set up one server, deploy workers, attach databases/KV/buckets/queues/secrets, inspect logs and events, and publish routes from one CLI.

License: GNU Affero General Public License v3.0 only (`AGPL-3.0-only`).

## Table of contents

- [Why gumgum?](#why-gumgum)
- [Core concepts](#core-concepts)
- [What gumgum manages](#what-gumgum-manages)
- [Install the CLI](#install-the-cli)
- [Set up a server](#set-up-a-server)
- [Local server](#local-server)
- [Remote server](#remote-server)
- [Inspect and remove servers](#inspect-and-remove-servers)
- [Create a project or workspace](#create-a-project-or-workspace)
- [Create a workspace](#create-a-workspace)
- [Create workers](#create-workers)
- [Manage domains and ingress](#manage-domains-and-ingress)
- [Manage resources](#manage-resources)
- [Databases](#databases)
- [KV namespaces](#kv-namespaces)
- [Buckets](#buckets)
- [Queues](#queues)
- [Secrets](#secrets)
- [Bind resources to workers](#bind-resources-to-workers)
- [Observability and platform services](#observability-and-platform-services)
- [Deploy](#deploy)
- [Logs, environment, status, and events](#logs-environment-status-and-events)
- [Graph inspection](#graph-inspection)
- [Bucket object operations](#bucket-object-operations)
- [Publish](#publish)
- [Rollback and revisions](#rollback-and-revisions)
- [Configuration](#configuration)
- [JSON output](#json-output)
- [End-to-end example](#end-to-end-example)
- [Command reference](#command-reference)
- [License](#license)

## Why gumgum?

- **One server, one simple platform.** Turn a Linux host or your local computer into a small PaaS.
- **Batteries included.** gumgum starts the backing services most apps need: Postgres, Redis, MinIO/S3 buckets, Redpanda queues, secrets, and an observability stack.
- **Project-first workflow.** Create resources, bind them to workers, deploy, view logs, and inspect events from the project directory.
- **Local-first control.** The daemon runs on your server. Your CLI sends intent; gumgum handles runtime/provider convergence there.
- **Human CLI by default.** Commands print readable output unless you ask for `--json`.

## Core concepts

- **Server**: the machine that runs `gumgumd`, Docker workloads, the gateway, and built-in providers. A server can have a public control-plane domain used for default routes.
- **Domain**: a DNS zone or delegated domain GumGum may use for routes. Domains can be manual or Cloudflare-managed.
- **Project**: one app/workspace with a production domain in `gumgum.toml`.
- **Environment**: an isolated deployment target. GumGum uses `preview` and `prod`; app/provider containers and data objects are environment-scoped.
- **Workspace**: a directory containing multiple worker projects.
- **Resource**: a backing service object such as a database, KV namespace, bucket, queue, or secret.
- **Binding**: an environment projection from a resource into a worker, for example `DATABASE_URL` or `UPLOADS_BUCKET`.
- **Desired state**: the resources, bindings, routes, and deployments gumgum should maintain on the server.

## What gumgum manages

gumgum can manage:

- app/worker deployment to Docker
- explicit HTTP routes through the gumgum gateway
- Postgres databases on host volumes under `/gumgum/volumes/providers/*/postgres`
- Redis KV namespaces on host volumes under `/gumgum/volumes/providers/*/redis` with append-only persistence
- MinIO/S3 buckets and bucket objects on host volumes under `/gumgum/volumes/providers/*/minio`
- Redpanda queues/topics on host volumes under `/gumgum/volumes/providers/*/redpanda`
- platform secrets and observability services
- Prometheus scraping, host metrics, Docker/container metrics, Grafana dashboards, Loki logs, Tempo traces, and OTEL collector plumbing
- worker environment bindings
- logs, events, grouped event summaries, rollback metadata, and publish previews

## Install the CLI

Build the CLI from this repository:

```bash
git clone https://github.com/leostera/gumgum.git
cd gumgum
cargo build --release
install -m 0755 target/release/gumgum ~/.local/bin/gumgum
```

Make sure `~/.local/bin` is on your `PATH`:

```bash
export PATH="$HOME/.local/bin:$PATH"
```

Check the CLI:

```bash
gumgum --help
gumgum version
```

## Set up a server

`gumgum server add` is the main setup command. It installs/configures `gumgumd`, starts built-in providers, and saves the server locally. GumGum upgrades also migrate the daemon's own internal SQLite graph database automatically before the daemon starts serving requests.

### Local server

Use this when you want to run apps on your own machine:

```bash
gumgum server add 0.0.0.0 --name local --domain example.dev
```

This configures a local gumgum server named `local`. GumGum does not install local DNS resolver entries; use real DNS, `/etc/hosts`, or `curl --resolve` for local testing.

### Remote server

Use this when you want to run apps on another machine over SSH:

```bash
gumgum server add 203.0.113.10 --name prod --domain example.com
```

If SSH needs a user:

```bash
gumgum server add 203.0.113.10 \
--user root \
--name prod \
--domain example.com
```

Preview setup without changing anything:

```bash
gumgum --dry-run server add 203.0.113.10 --name prod --domain example.com
```

### Inspect and remove servers

List configured servers:

```bash
gumgum server list
```

Ping the daemon:

```bash
gumgum server ping --host prod
```

Inspect daemon capabilities:

```bash
gumgum server capabilities list --host prod
```

Require specific daemon capabilities:

```bash
gumgum server capabilities list --host prod \
--require gumgum:events,gumgum:buckets:objects
```

Remove a server from your local config:

```bash
gumgum server rm prod
```

Removing a server record does not delete remote containers or resources.

## Create a project or workspace

### Create a workspace

`gumgum init` creates a workspace manifest in the current directory:

```bash
gumgum init --name my-app
```

Useful options:

```bash
gumgum init --name my-app --domain example.com
gumgum init --name my-app --namespace production
gumgum init --name my-app --force
```

### Create workers

Workers are managed with `gumgum worker`, separate from workspace initialization.

Create workers inside the current workspace:

```bash
gumgum worker create api --port 3000
gumgum worker create jobs --port 3001
```

This creates worker folders with their own `gumgum.toml` files and adds them to the workspace members list.

Choose an explicit directory or zones:

```bash
gumgum worker create api --dir apps/api --port 3000
gumgum worker create api --zone example.com --zone example.net
```

List workers:

```bash
gumgum worker list
```

Remove a worker from the workspace:

```bash
gumgum worker delete api
```

`worker delete` only removes the worker from the workspace manifest. It never deletes source files.

Workspace-aware commands such as `logs`, `env`, and `publish --dry-run` can operate across all workers from the workspace root.

## Manage domains and ingress

Servers run the GumGum control plane; domains describe DNS zones that a server can use for routes. Add a domain after a server is available:

```bash
gumgum domain add leostera.dev --server starbase2 --provider cloudflare --ingress cloudflare
```

`--provider manual` records the domain and prints the desired intent without changing DNS. `--provider cloudflare` prompts for a Cloudflare API token and saves it on the GumGum server so future route convergence can manage DNS/tunnel state there.

Required Cloudflare token permissions:

| Scope | Permission | Applies to |
| --- | --- | --- |
| Zone | DNS: Edit | Every domain GumGum should manage |
| Zone | Zone: Read | Every domain GumGum should manage |
| Account | Cloudflare Tunnel: Edit | Account used for Cloudflare Tunnel ingress |

If `Cloudflare Tunnel: Edit` is not available in your dashboard, use `Account / Zero Trust: Edit` as the broader fallback. You do not need Zone Access permissions unless you are separately creating Cloudflare Access apps/policies. Scoping the token to all zones is convenient when one GumGum server will host multiple domains; for stricter isolation, scope it only to domains GumGum should manage and update/recreate it before adding another domain.

As setup sugar, `gumgum server add ... --domain leostera.dev --ingress cloudflare` installs the server and then adds that domain with Cloudflare ingress.

When a deployed worker has `public = true`, GumGum converges public ingress for its derived route. For a Cloudflare-managed domain with Cloudflare ingress, deploy ensures a proxied CNAME to the GumGum Cloudflare Tunnel and adds a tunnel rule to the server gateway.

## Manage resources

Resource commands share a common shape:

```bash
gumgum list
gumgum create
gumgum delete --preview
gumgum delete
```

`` is one of:

- `db`
- `kv`
- `bucket`
- `queue`
- `secret`

Pass `--host ` when you want to target a specific server instead of the configured/default one.

### Databases

Create and list Postgres databases:

```bash
gumgum db create app-db
gumgum db list
```

Delete safely with a preview first:

```bash
gumgum db delete app-db --preview
gumgum db delete app-db
```

Create with an explicit namespace or root domain when needed:

```bash
gumgum db create app-db --namespace prod
gumgum db create app-db --domain example.com
```

### KV namespaces

Create and list Redis-backed KV namespaces:

```bash
gumgum kv create app-cache
gumgum kv list
```

Delete:

```bash
gumgum kv delete app-cache --preview
gumgum kv delete app-cache
```

### Buckets

Create and list MinIO/S3-backed buckets:

```bash
gumgum bucket create uploads
gumgum bucket list
```

Delete:

```bash
gumgum bucket delete uploads --preview
gumgum bucket delete uploads
```

Bucket object commands are covered in [Bucket object operations](#bucket-object-operations).

### Queues

Create and list Redpanda-backed queues/topics:

```bash
gumgum queue create jobs
gumgum queue list
```

Delete:

```bash
gumgum queue delete jobs --preview
gumgum queue delete jobs
```

### Secrets

Create and list secrets:

```bash
gumgum secret create api-token
gumgum secret list
```

Delete:

```bash
gumgum secret delete api-token --preview
gumgum secret delete api-token
```

## Bind resources to workers

Bindings project resource connection information into a worker's environment.

General shape:

```bash
gumgum bind --to --as
gumgum unbind --to --as --preview
gumgum unbind --to --as
```

Examples:

```bash
gumgum db bind app-db --to api --as DATABASE_URL
gumgum kv bind app-cache --to api --as CACHE
gumgum bucket bind uploads --to api --as UPLOADS_BUCKET
gumgum queue bind jobs --to api --as JOBS_QUEUE
gumgum secret bind api-token --to api --as API_TOKEN
```

Bindings default to read-write access. You can request another access mode:

```bash
gumgum bucket bind uploads --to api --as UPLOADS_BUCKET --access read-only
```

## Observability and platform services

GumGum boots a singleton platform stack on each server, separate from per-environment app data providers:

| Service | Container | Purpose |
| --- | --- | --- |
| Vaultwarden | `gumgum-vaultwarden` | platform-scoped secret service |
| OpenTelemetry Collector | `gumgum-otel` | OTLP ingress and forwarding to Tempo |
| Prometheus | `gumgum-prometheus` | app/platform/host/container metrics |
| Grafana | `gumgum-grafana` | dashboards, logs, traces, and datasources at `grafana.` |
| Loki | `gumgum-loki` | log backend |
| Tempo | `gumgum-tempo` | trace backend |
| Grafana Alloy | `gumgum-alloy` | Docker log shipping to Loki |
| node-exporter | `gumgum-node-exporter` | host metrics |
| cAdvisor | `gumgum-cadvisor` | Docker/container metrics |
| Docker socket proxy | `gumgum-docker-proxy` | read-only Docker discovery for Prometheus |
| Caddy | `gumgum-caddy` | TLS ingress, route labels, and ingress trace spans |

Declare app metrics, required secrets, Grafana datasource files, and dashboard files in a worker manifest:

```toml
[observability]
enable = true
prometheus_metrics = "/_/metrics"

[observability.grafana]
sources = "../grafana/sources.json"

[[secret]]
name = "my-app/api-token"
binding = "API_TOKEN"

[[dashboard]]
name = "API Overview"
path = "../grafana/dashboards/api-overview.json"
```

When deployed, GumGum:

- injects declared secret bindings and OTEL environment into workers
- configures Prometheus scrapes for declared metrics endpoints
- labels app containers for Docker service discovery (`prometheus.scrape=true`, `prometheus.port`, `prometheus.path`, `prometheus.label_*`)
- ships GumGum-managed Docker logs to Loki with `project`, `domain`, `environment`, `worker`, and platform labels
- enables Tempo traces from the Caddy ingress span through instrumented workers and logical provider operations
- applies Grafana datasources and dashboards through the daemon
- stores Grafana dashboards under `` → `` folders

Grafana dashboards should include a top-level `GUMGUM_ENV` variable for switching between `preview` and `prod`. Query app metrics with that environment label, for example:

```promql
visit_counter_requests_total{environment="$GUMGUM_ENV"}
```

`gumgum status` includes platform provider health. A healthy server with the current default stack reports `Providers: 10/10 running`.

Stateful platform services use host volume paths under `/gumgum/volumes/platform/*` for durability across container and machine restarts: Grafana, Prometheus, Loki, Tempo, Alloy, Vaultwarden, and Caddy all keep their data outside the container filesystem.

## Deploy

Deploy the current project:

```bash
gumgum deploy
```

Deploy a specific manifest:

```bash
gumgum deploy api/gumgum.toml
```

Target a specific server:

```bash
gumgum deploy --host prod
```

Deploy the prod environment:

```bash
gumgum deploy --env prod
```

Deployments are rolling by default. GumGum starts a new revision-specific container, waits for its health check to pass, lets Caddy discover the new route labels, and then removes stale containers for that worker/route. Running containers therefore use stable GumGum labels but revision-suffixed Docker names, for example:

```text
gumgum-prod-dev-leostera-visit-counter-api-d6fcec95161ecc48
```

Delete desired deployment state for a worker:

```bash
gumgum deploy api/gumgum.toml --delete
```

Preview deploy behavior without mutating state:

```bash
gumgum --dry-run deploy
```

Ingress routes are declared in worker manifests:

```toml
[[ingress]]
name = "http"
protocol = "http"
port = 3000
public = true
```

Default deploy routes use the server/control-plane domain:

```text
..
# api.visit-counter.leostera.dev
```

`deploy --env prod` uses the project domain from the workspace manifest:

```toml
[project]
name = "visit-counter"
domain = "kava.fund"
server = "starbase2"
```

Ingress records are relative to that route base:

| `record` | Preview env route | Prod env route |
| --- | --- | --- |
| omitted | `..` | `.` |
| `"api"` | `api..` | `api.` |
| `"@"` | `.` | `` |

For example, to publish the project apex instead of `api.`:

```toml
[[ingress]]
name = "http"
protocol = "http"
port = 3000
public = true
record = "@"
```

## Logs, environment, status, and events

Check overall server status:

```bash
gumgum status
gumgum status --host prod
```

Show logs for the current project or workspace:

```bash
gumgum logs
gumgum logs --tail 200
```

The CLI can still read Docker logs directly, and the platform also ships GumGum-managed Docker logs into Loki. In Grafana Explore, useful Loki selectors include:

```logql
{gumgum_managed="deployment", project="visit-counter"}
{environment="prod", worker="api-prod"}
```

Show logs for one worker:

```bash
gumgum logs api
gumgum logs api --tail 100
```

Follow logs for a single worker:

```bash
gumgum logs api --follow
```

Print environment for the current project or workspace:

```bash
gumgum env
```

Narrow environment output:

```bash
gumgum env --project my-app
gumgum env --worker api
gumgum env --project my-app --worker api
```

Environment keys are namespaced by worker by default:

```dotenv
API_DATABASE_URL=...
API_CACHE_URL=...
```

Use `--qualified` when exporting a whole workspace and you want project + worker prefixes:

```bash
gumgum env --qualified
```

```dotenv
MY_APP_API_DATABASE_URL=...
MY_APP_API_CACHE_URL=...
```

Trace data is sent to Tempo through the OpenTelemetry Collector. Instrumented apps can use standard OTEL environment variables projected by GumGum; Caddy emits the ingress span and propagates W3C trace context upstream. In Grafana Traces, a visit-counter request should show a chain like:

```text
gumgum-caddy api-prod-ingress
api-prod GET /
api-prod redis increment user counter
api-prod minio put visit request
api-prod redpanda produce visit event
visit-counter-worker-prod visit-counter.process_message
visit-counter-worker-prod minio get visit request
visit-counter-worker-prod postgres insert visit
```

Show control-plane events:

```bash
gumgum events
gumgum events --limit 20
gumgum events --grouped
gumgum events --kind mutation
gumgum events --kind reconciliation
```

## Graph inspection

Render the desired graph:

```bash
gumgum graph
gumgum graph show
```

Show the subgraph affected by a target:

```bash
gumgum graph affected worker/api
gumgum graph affected api
```

The target must exist in the workspace/desired graph. Invalid targets fail instead of returning an empty affected list.

## Bucket object operations

Bucket object commands only exist under `gumgum bucket`.

List objects in a bucket:

```bash
gumgum bucket ls uploads
gumgum bucket ls uploads raw/
```

Read an object to stdout:

```bash
gumgum bucket get uploads path/to/file.json
```

Copy local to remote:

```bash
gumgum bucket cp ./local.json uploads/local.json
```

Copy remote to local:

```bash
gumgum bucket cp uploads/local.json ./local-copy.json
```

Copy remote to remote:

```bash
gumgum bucket cp uploads/local.json uploads/archive/local.json
```

Sync a remote prefix to another remote prefix:

```bash
gumgum bucket sync uploads/raw uploads/archive/raw
```

Remove an object:

```bash
gumgum bucket rm uploads archive/local.json
```

## Publish

Preview public publishing before changing public route state:

```bash
gumgum --dry-run publish
```

Preview a specific target:

```bash
gumgum --dry-run publish api/gumgum.toml
```

Plan an explicit public domain:

```bash
gumgum --dry-run publish api/gumgum.toml --public-domain api.example.com
```

Apply publishing only after reviewing the dry-run:

```bash
gumgum publish api/gumgum.toml --public-domain api.example.com
```

Workspace dry-runs plan each member. `--public-domain` is only valid when publishing one worker.

## Rollback and revisions

Preview rollback for the current project:

```bash
gumgum rollback --preview
```

Preview rollback for a worker:

```bash
gumgum rollback api/gumgum.toml --worker api --preview
```

List deployment revisions:

```bash
gumgum rollback api/gumgum.toml --worker api --revisions
gumgum rollback api/gumgum.toml --worker api --revisions --limit 20
```

Preview or apply a specific revision:

```bash
gumgum rollback api/gumgum.toml --worker api --revision-id 12 --preview
gumgum rollback api/gumgum.toml --worker api --revision-id 12
```

Delete stale revision metadata without changing containers:

```bash
gumgum rollback api/gumgum.toml --worker api --delete-revision-id 12
```

## Configuration

View local gumgum config:

```bash
gumgum config list
```

Read and write known config keys:

```bash
gumgum config get ui.color
gumgum config set ui.color true
gumgum config get format
gumgum config set format human
gumgum config get registry_port
gumgum config set registry_port 5000
```

Config is schema-backed, not arbitrary key/value storage. Unknown keys fail with a human-readable error.

Server-scoped config uses the same schema:

```bash
gumgum server config --host prod list
gumgum server config --host prod get ui.color
gumgum server config --host prod set ui.color true
```

## JSON output

Use `--json` when scripting:

```bash
gumgum --json status
gumgum --json events --limit 10
gumgum --json db list
gumgum --json bucket list
```

Errors are human-readable by default and structured as JSON only with `--json`.

## End-to-end example

The `examples/visit-counter` workspace demonstrates:

- API and background worker projects
- preview/prod environment isolation
- DB/KV/bucket/queue resources
- platform-scoped secrets and observability declarations
- Prometheus metrics from both API and worker
- Loki logs labelled by project/domain/environment/worker
- Tempo traces spanning Caddy → API → Redis/MinIO/Redpanda logical operations → worker → MinIO/Postgres logical operations
- Grafana datasource/dashboard application under `` → `` folders
- resource bindings
- rolling deploys with revision-suffixed containers
- logs and environment inspection
- events and grouped events
- rollback previews
- publish dry-runs

Try it after configuring a server:

```bash
cd examples/visit-counter
gumgum db create visits
gumgum kv create user-counters
gumgum bucket create visit-requests
gumgum queue create visit-events

gumgum db bind visits --to worker --as DATABASE_URL
gumgum kv bind user-counters --to api --as USER_COUNTERS
gumgum bucket bind visit-requests --to api --as VISIT_REQUESTS_BUCKET
gumgum bucket bind visit-requests --to worker --as VISIT_REQUESTS_BUCKET
gumgum queue bind visit-events --to api --as VISIT_EVENTS_QUEUE
gumgum queue bind visit-events --to worker --as VISIT_EVENTS_QUEUE

gumgum deploy --env preview
gumgum deploy --env prod
gumgum logs
gumgum events --grouped
gumgum --dry-run publish
```

The API worker uses `record = "@"`, so prod serves the project domain itself, for example `https://kava.fund/`, while preview serves the project route under the server domain, for example `https://visit-counter.leostera.dev/`.

## Command reference

Global flags:

```bash
gumgum --json
gumgum --dry-run
```

Server commands:

```bash
gumgum server
gumgum server list
gumgum server add [--name ] [--user ] [--domain ] [--ingress direct|cloudflare]
gumgum server rm
gumgum server ping --host
gumgum server capabilities list --host [--require ]
gumgum server config --host list|get|set
gumgum server upgrade --host
```

Domain commands:

```bash
gumgum domain add [--server ] [--provider manual|cloudflare] [--ingress direct|cloudflare]
```

Project/runtime commands:

```bash
gumgum init [--name ] [--domain ] [--server ] [--force]
gumgum worker create [--port ] [--dir ] [--force]
gumgum worker list [workspace]
gumgum worker delete [workspace]
gumgum deploy [path] [--host ] [--env preview|prod] [--delete]
gumgum publish [target] [--host ] [--public-domain ] [--tunnel ]
gumgum logs [path-or-worker] [--host ] [--tail ] [--follow]
gumgum env [path] [--host ] [--project ] [--worker ] [--qualified]
gumgum status [--host ]
gumgum events [--host ] [--limit ] [--kind mutation|reconciliation] [--grouped]
gumgum graph [--host ] [show|affected ]
gumgum rollback [path] [--host ] [--worker ] [--preview] [--revisions] [--revision-id ] [--delete-revision-id ]
```

Resource commands:

```bash
gumgum db list|create|delete|bind|unbind
gumgum kv list|create|delete|bind|unbind
gumgum bucket list|create|delete|bind|unbind|ls|get|rm|cp|sync
gumgum queue list|create|delete|bind|unbind
gumgum secret list|create|delete|bind|unbind
```

## License

GumGum is licensed under the GNU Affero General Public License v3.0 only (`AGPL-3.0-only`). See [`LICENSE`](LICENSE) for the full license text.