akerdock

module
v0.0.0-...-79934c9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: Apache-2.0

README

AkerDock

Self-hosted PaaS in Go. Deploy applications, databases and Docker Compose stacks to your own servers over SSH, with a managed reverse proxy, automatic HTTPS, PR previews, backups and monitoring — no vendor lock-in.

A single static Go binary. PostgreSQL is the only dependency — it holds both the state and the job queue (no Redis, no external bus). The API is spec-first (OpenAPI), and the control plane never runs your workloads: Docker operations ride an outbound channel opened by a small agent on each server (ADR-051/052), with SSH kept for bootstrap, repair, git clones and Nixpacks builds only.

Design docs (PRD, ADRs, specs), code, the CLI and this README are all in English.

What it does

  • Deploy apps from a Dockerfile, a git repo (Nixpacks / Dockerfile / static) or a Docker image; databases (Postgres, MySQL, Redis…) and Docker Compose stacks — with zero-downtime rolling switches when a health check is configured.
  • Reverse proxy + automatic HTTPS (Traefik + Let's Encrypt, HTTP-01 or DNS-01 wildcard), per server.
  • PR previews: every pull request gets its own isolated instance and URL, torn down on merge/close.
  • Backups of databases and volumes with local + S3 retention and restore drills.
  • Auth: password, passkeys (WebAuthn), OIDC SSO (Google, Entra…), enforced MFA, and SCIM 2.0 provisioning; granular team RBAC, with an invitee able to create their account straight from the invitation link.
  • Teams as the isolation boundary: a user can belong to several teams with a different role in each, and switches between them from the sidebar; everything else (servers, resources, tokens, notifications) is scoped per team.
  • Adopt containers and compose stacks already running on a server, without restarting them (migrate in place).
  • Scale to zero: idle apps stop and wake on the first request (ADR-036).
  • Bastion: declared external endpoints and audited TCP tunnels to them (ADR-045).
  • Local CLI for day-to-day debugging: logs, shell, TCP port-forward and typed DB consoles — see Using the CLI.
  • MCP server (read-only, opt-in) so an assistant can inspect the instance — akerdock mcp (ADR-043).

Run your own instance

Requirements: Docker Engine ≥ 24 with Compose v2, and openssl.

git clone https://github.com/deepteams/akerdock.git
cd akerdock
./install.sh

install.sh builds the image from the local Dockerfile (no published image needed), generates the master key (keys/master.keyback it up off the machine immediately) and the .env, starts the reference two-service stack (AkerDock + PostgreSQL), and prints the first root user's credentials. Customise the first run with AKERDOCK_PORT, AKERDOCK_INSTANCE_FQDN, AKERDOCK_ROOT_EMAIL, etc. (see the script header). Two variables matter for server onboarding since ADR-051: AKERDOCK_IMAGE (the instance's own image, from which the per-server agent helper is deployed — the compose derives it from AKERDOCK_TAG) and AKERDOCK_INSTANCE_URL (the base URL agents dial back; derived from the instance FQDN or host gateway when unset).

Update an existing instance: git pull && ./install.sh — the image is rebuilt, migrations apply at boot, and state persists in the named volumes. The manual install is documented in docs/runbooks/install.md.

Migrating from another platform

AkerDock adopts containers and compose stacks already deployed, without restarting them (PRD §20.7): scan the server, preview the mapping, adopt, then normalise on the first redeploy — volumes and domains kept, de-adoption possible at any time. For a Coolify server, scripts/migrate/coolify.sh drives the whole migration over the public API (dry-run by default).

Using the CLI

akerdock is the same binary as the server (Cobra subcommands). It talks only to your instance over HTTPS, opens no local port, and works from anywhere — behind a proxy, over SSH, in a container. This is what team members use to debug a resource without a manual SSH tunnel.

Get the CLI
# straight from the repo — installs `akerdock` into $GOBIN (usually ~/go/bin):
go install github.com/deepteams/akerdock/cmd/akerdock@latest

# or build from a checkout, or grab a release binary:
go build -o akerdock ./cmd/akerdock && sudo mv akerdock /usr/local/bin/

Make sure $GOBIN (or $(go env GOPATH)/bin) is on your PATH.

Log in
akerdock login --url https://manager.example.com

This opens your browser to authorise (SSO / password / passkey), then stores a named, revocable token under ~/.akerdock/ (directory 0700, files 0600; the token lives in credentials.yaml, apart from the inspectable config.yaml). No port is opened — the browser flow is a poll bound by PKCE, with a confirmation code you match on screen. The token defaults to read,write — never root, deploy or read:sensitive unless you ask for them with --scopes, and never more than the approving session holds — and expires after 30 days.

CI or headless? Paste an existing API token instead, or print the URL rather than opening a browser:

akerdock login --url https://manager.example.com --with-token < token.txt
akerdock login --url https://manager.example.com --no-browser
Everyday commands

A resource is addressed by a REF of the form type/name, where the name is the resource's name or its UUID: app/…, db/…, svc/…, preview/…, and endpoint/… for a declared external target.

akerdock ls                              # apps, databases and services in the team
akerdock ls servers                      # or one kind: apps|databases|services|servers
akerdock logs app/varuna -f              # follow container logs
akerdock logs app/varuna -n 500          # snapshot, last N lines (default 200)
akerdock logs app/varuna --deployment    # logs of the latest build/deploy
akerdock shell app/varuna                # interactive shell in the container
akerdock shell app/varuna -c postgres    # a specific compose service

# Tunnel a container port to localhost through the manager (never exposes it):
akerdock port-forward db/pg 15432:5432
akerdock port-forward app/varuna 15432:5432 -c postgres --pr 8   # a PR preview

# …or to a declared external endpoint — a managed DB, an internal API (ADR-045).
# No remote port to give: the endpoint froze its own host and port. Without a
# local port either, the OS picks a free one and the CLI prints it.
akerdock port-forward endpoint/prod-replica
akerdock port-forward endpoint/prod-replica 15432   # …on a chosen local port

# Typed console: opens a forward + the right client
# (psql / mysql / redis-cli / mongosh, picked from the engine):
akerdock db db/pg

Output is human tables by default; add -o json for scripting, --quiet for bare output. Exit codes: 0 success, 1 error, 2 usage.

Give a local assistant read-only access (MCP)

akerdock mcp bridges the instance's MCP server over stdio, using the current context's credentials. The tools are read-only, and the server-side surface is off by default — enable it in the instance settings first (ADR-043).

Contexts (multiple instances, multiple teams)

Each login creates a context: one instance, and the team its token belongs to. Switch between them without re-typing the URL:

akerdock context list
akerdock context use staging
akerdock context current
akerdock logout --context staging --revoke   # also revoke the server-side token

An API token is bound to one team when it is created, so a context acts in that team and nothing else — --team does not move it (it only tells logout --revoke where to look for the token to delete). To work in another team, log in again into a separate context with a token of that team. The dashboard's team switcher moves a session; the CLI holds a token, and tokens do not move.

Per-directory defaults (.akerdock)

Drop a committable .akerdock file in a repo to set defaults for that directory tree — no more repeating --context or the target on every command (found by walking up, like .git; it never holds secrets):

# .akerdock — every field optional
context: prod          # a context created by `akerdock login`
application: varuna    # default target for logs / shell
component: web         # default compose service
project: platform
environment: production

Then, from that repo:

akerdock logs -f          # follows the default app on the configured instance
akerdock shell            # shell into it

Resolution precedence (most specific wins): flags > AKERDOCK_* env vars > .akerdock > ~/.akerdock (global) — with AKERDOCK_CONTEXT, AKERDOCK_APPLICATION, AKERDOCK_COMPONENT, AKERDOCK_PROJECT, AKERDOCK_ENVIRONMENT, AKERDOCK_TEAM.

Server modes

The same binary runs the control plane, which is why akerdock --help lists more than the client commands:

akerdock serve            # all-in-one (default, or $AKERDOCK_MODE)
akerdock serve api        # HTTP API only …  worker | scheduler for the others
akerdock healthcheck      # probe used by the compose healthcheck
akerdock agent            # server agent helper container (ADR-051/056; `waker` is a deprecated alias)
akerdock version

The full contract is in docs/specs/cli.md.

Documentation

Directory Contents
docs/PRD.md Product spec: functional scope and verifiable requirements
docs/adr/ Architecture Decision Records (accepted)
docs/specs/ Technical specs: OpenAPI v1, CLI, ERD, threat model, RBAC matrix, proxy contract, deployment engine…
docs/runbooks/ Operational runbooks (install, failures, key rotation, upgrades…)

Key architecture decisions

  • Transport: SSH first, outbound agent on the target (ADR-001)
  • Durable queue in PostgreSQL, no external bus (ADR-002)
  • Standalone Docker runtime — Kubernetes and Swarm ruled out (ADR-004)
  • Go core: pgx + sqlc, chi + oapi-codegen, spec-first (ADR-025)
  • Distribution: minimal two-service compose (AkerDock + PostgreSQL) (ADR-021)
  • Real-time: SSE, WebSocket reserved for the terminal and tunnels (ADR-024)
  • Single-binary CLI (Cobra), client and server modes (ADR-033)

Development

Requirements: Go ≥ 1.26 and golangci-lint v2 (the other tools — sqlc, oapi-codegen, goose — are pinned in go.mod and run via go tool).

make generate   # regenerate code from the OpenAPI spec and sqlc queries
make build      # compile bin/akerdock
make test lint  # tests and lint

Conventions (commits, spec-first workflow, migrations) are in CONTRIBUTING.md.

License

Apache 2.0 (ADR-020).

Directories

Path Synopsis
cmd
akerdock command
Command akerdock is both the AkerDock control plane and its local CLI (ADR-033).
Command akerdock is both the AkerDock control plane and its local CLI (ADR-033).
Package db embeds the versioned SQL migrations applied at startup (ADR-025, instance-config §6.1 step 3).
Package db embeds the versioned SQL migrations applied at startup (ADR-025, instance-config §6.1 step 3).
internal
accessroute
Package accessroute validates and renders the deliberately small language used to publish selected paths through an otherwise protected resource.
Package accessroute validates and renders the deliberately small language used to publish selected paths through an otherwise protected resource.
adoption
Package adoption maps unmanaged Docker resources onto the AkerDock model (PRD §20.7, ADR-013).
Package adoption maps unmanaged Docker resources onto the AkerDock model (PRD §20.7, ADR-013).
agent
Agent loop (ADR-040 phase 1): the helper pushes outbound observations — Docker state transitions of managed containers, scale-to-zero wakes, a heartbeat — to the control plane over HTTPS, authenticated by a per-server token injected at container creation.
Agent loop (ADR-040 phase 1): the helper pushes outbound observations — Docker state transitions of managed containers, scale-to-zero wakes, a heartbeat — to the control plane over HTTPS, authenticated by a per-server token injected at container creation.
agentrelay
Package agentrelay reaches a server's agent channel from a process that does not terminate it — worker, scheduler (ADR-052 §8).
Package agentrelay reaches a server's agent channel from a process that does not terminate it — worker, scheduler (ADR-052 §8).
agentwire
Package agentwire defines the wire protocol of the agent channel: the ADR-041 observation frames (v1) and the ADR-052 typed command frames (v2).
Package agentwire defines the wire protocol of the agent channel: the ADR-041 observation frames (v1) and the ADR-052 typed command frames (v2).
api
Package api provides primitives to interact with the openapi HTTP API.
Package api provides primitives to interact with the openapi HTTP API.
audit
Package audit records the append-only audit trail of §23.4 and the transactional outbox events of §24.2.
Package audit records the append-only audit trail of §23.4 and the transactional outbox events of §24.2.
auth
Package auth implements the bearer-token authentication and permission model of the public API (§10.3): team-scoped tokens with granular permissions, SHA-256 hashed with an identification prefix.
Package auth implements the bearer-token authentication and permission model of the public API (§10.3): team-scoped tokens with granular permissions, SHA-256 hashed with an identification prefix.
bootstrap
Package bootstrap implements the first-start seeding of instance-config §6.2/§6.3: instance_settings singleton and root user.
Package bootstrap implements the first-start seeding of instance-config §6.2/§6.3: instance_settings singleton and root user.
cli
Package cli implements the local `akerdock` client subcommands (ADR-031, ADR-032, ADR-033, spec docs/specs/cli.md).
Package cli implements the local `akerdock` client subcommands (ADR-031, ADR-032, ADR-033, spec docs/specs/cli.md).
compose
Package compose parses, validates and transforms the Docker Compose subset of compose-spec.md.
Package compose parses, validates and transforms the Docker Compose subset of compose-spec.md.
config
Package config loads and validates the instance configuration following docs/specs/instance-config.md: environment variables take precedence over an optional YAML file (AKERDOCK_CONFIG_FILE), which takes precedence over compiled defaults.
Package config loads and validates the instance configuration following docs/specs/instance-config.md: environment variables take precedence over an optional YAML file (AKERDOCK_CONFIG_FILE), which takes precedence over compiled defaults.
cronexpr
Package cronexpr parses the 5-field cron expressions of the backup plans (§7.1) and computes their next occurrence in a given timezone.
Package cronexpr parses the 5-field cron expressions of the backup plans (§7.1) and computes their next occurrence in a given timezone.
dockerruntime
Package dockerruntime is the single Docker runtime adapter (PRD §18.1, ADR-004, ADR-051): every Docker Engine API call AkerDock makes — from the control plane's jobs and handlers or from the server agent — goes through the Runtime interface.
Package dockerruntime is the single Docker runtime adapter (PRD §18.1, ADR-004, ADR-051): every Docker Engine API call AkerDock makes — from the control plane's jobs and handlers or from the server agent — goes through the Runtime interface.
dockerruntime/fake
Package fake is the test double for dockerruntime.Runtime: a typed recorder.
Package fake is the test double for dockerruntime.Runtime: a typed recorder.
envelope
Package envelope implements the multi-version master key file (instance-config §3) and the envelope encryption format of every *_enc column (data-dictionary §2.7, ADR-003).
Package envelope implements the multi-version master key file (instance-config §3) and the envelope encryption format of every *_enc column (data-dictionary §2.7, ADR-003).
events
Package events publishes the transactional outbox (§18.2, §24.2) and fans the published events out to the SSE subscribers of each team (ADR-024).
Package events publishes the transactional outbox (§18.2, §24.2) and fans the published events out to the SSE subscribers of each team (ADR-024).
gitforge
Package gitforge implements the degraded preview feedback path (§20.4.6, protocols §4.4/§6.3): commit statuses and ONE upserted comment against the GitLab and Gitea APIs, authenticated by a provider API token stored on the git source.
Package gitforge implements the degraded preview feedback path (§20.4.6, protocols §4.4/§6.3): commit statuses and ONE upserted comment against the GitLab and Gitea APIs, authenticated by a provider API token stored on the git source.
githubapp
Package githubapp implements the GitHub App integration of git-webhook-protocols.md §2: manifest conversion, App JWTs, installation access tokens, repository discovery and the rich preview feedback (checks, deployments, upserted PR comment).
Package githubapp implements the GitHub App integration of git-webhook-protocols.md §2: manifest conversion, App JWTs, installation access tokens, repository discovery and the rich preview feedback (checks, deployments, upserted PR comment).
gitwebhook
Package gitwebhook receives and authenticates the webhooks Git providers send (spec git-webhook-protocols).
Package gitwebhook receives and authenticates the webhooks Git providers send (spec git-webhook-protocols).
handlers
Agent ingestion (ADR-040 phase 1): the server helper POSTs observation batches here, authenticated by its per-server token.
Agent ingestion (ADR-040 phase 1): the server helper POSTs observation batches here, authenticated by its per-server token.
hostops
The ADR-055 phase-2 build primitive, agent side: a BuildKit build driven against the LOCAL daemon's embedded builder — the exact rail `docker build` uses — with the context read from the mounted tree.
The ADR-055 phase-2 build primitive, agent side: a BuildKit build driven against the LOCAL daemon's embedded builder — the exact rail `docker build` uses — with the context read from the mounted tree.
hostops/fake
Package fake is the typed test double for hostops.Ops: a call journal plus overridable behaviors, mirroring dockerruntime/fake.
Package fake is the typed test double for hostops.Ops: a call journal plus overridable behaviors, mirroring dockerruntime/fake.
httpapi
Package httpapi holds the shared HTTP plumbing of the public API: the single Error schema of §24.1 and JSON response helpers.
Package httpapi holds the shared HTTP plumbing of the public API: the single Error schema of §24.1 and JSON response helpers.
httpserver
Package httpserver serves the single control-plane port (ADR-021, instance-config §2.1 AKERDOCK_PORT).
Package httpserver serves the single control-plane port (ADR-021, instance-config §2.1 AKERDOCK_PORT).
instance
Package instance caches the instance_settings singleton.
Package instance caches the instance_settings singleton.
jobs
Scale-to-zero provisioning (ADR-036): deploy the agent helper (born akerdock-waker, renamed by ADR-056) container in front of a preview and maintain its shared routing table.
Scale-to-zero provisioning (ADR-036): deploy the agent helper (born akerdock-waker, renamed by ADR-056) container in front of a preview and maintain its shared routing table.
logredact
Package logredact wraps a slog.Handler to mask the values of sensitive attributes before they are written anywhere (§23.4, INV-003, ISO A.8.12).
Package logredact wraps a slog.Handler to mask the values of sensitive attributes before they are written anywhere (§23.4, INV-003, ISO A.8.12).
mcp
Package mcp implements the built-in Model Context Protocol server (ADR-043, PRD §12): JSON-RPC 2.0 over Streamable HTTP, ten READ-ONLY tools scoped to one team.
Package mcp implements the built-in Model Context Protocol server (ADR-043, PRD §12): JSON-RPC 2.0 over Streamable HTTP, ten READ-ONLY tools scoped to one team.
notify
Package notify turns an outbox event into a message on a channel (§11, ADR-019).
Package notify turns an outbox event into a message on a channel (§11, ADR-019).
oidc
Package oidc implements the relying-party side of the dashboard's federated login (PRD §10.2): OpenID Connect for Google, Azure and a generic IdP, plain OAuth2-plus-userinfo for GitHub, GitLab and Bitbucket.
Package oidc implements the relying-party side of the dashboard's federated login (PRD §10.2): OpenID Connect for Google, Azure and a generic IdP, plain OAuth2-plus-userinfo for GitHub, GitLab and Bitbucket.
password
Package password hashes user passwords with Argon2id (PRD §23.2) using the PHC string format, so parameters can evolve without a schema change.
Package password hashes user passwords with Argon2id (PRD §23.2) using the PHC string format, so parameters can evolve without a schema change.
pguuid
Package pguuid bridges pgtype.UUID with the string form used by the API and generates application-side UUIDs (needed when the envelope AAD must bind a ciphertext to its row uuid before the insert).
Package pguuid bridges pgtype.UUID with the string form used by the API and generates application-side UUIDs (needed when the envelope AAD must bind a ciphertext to its row uuid before the insert).
pki
Package pki mints the per-server certificate authority that signs the TLS certificates of the managed databases (§6.3).
Package pki mints the per-server certificate authority that signs the TLS certificates of the managed databases (§6.3).
postgres
Package postgres opens the application pool and applies the embedded migrations, following the startup sequence of instance-config §6.1.
Package postgres opens the application pool and applies the embedded migrations, following the startup sequence of instance-config §6.1.
proxy
Package proxy implements the intermediate representation of docs/specs/proxy-contract.md and its Traefik generation (P0).
Package proxy implements the intermediate representation of docs/specs/proxy-contract.md and its Traefik generation (P0).
queue
Package queue implements the durable PostgreSQL job queue of ADR-002: enqueue with idempotency keys, FOR UPDATE SKIP LOCKED dequeue, leases with heartbeat, bounded retries with jitter, and a dead letter (§21.3).
Package queue implements the durable PostgreSQL job queue of ADR-002: enqueue with idempotency keys, FOR UPDATE SKIP LOCKED dequeue, leases with heartbeat, bounded retries with jitter, and a dead letter (§21.3).
s3
Package s3 speaks just enough of the S3 REST API to store and retrieve database backups: PUT, GET, HEAD, DELETE and a listing of one prefix.
Package s3 speaks just enough of the S3 REST API to store and retrieve database backups: PUT, GET, HEAD, DELETE and a listing of one prefix.
safedial
Package safedial hardens outbound HTTP against SSRF (PRD §23.3, ISO A.8.23): a request whose URL comes from a low-privilege user must never reach the control plane's own network — loopback, private ranges, link-local (including the cloud metadata endpoint 169.254.169.254), CGNAT space, or the unspecified address.
Package safedial hardens outbound HTTP against SSRF (PRD §23.3, ISO A.8.23): a request whose URL comes from a low-privilege user must never reach the control plane's own network — loopback, private ranges, link-local (including the cloud metadata endpoint 169.254.169.254), CGNAT space, or the unspecified address.
scheduler
Package scheduler runs the instance maintenance crons (§18.2): retention purges and proxy drift reconciliation.
Package scheduler runs the instance maintenance crons (§18.2): retention purges and proxy drift reconciliation.
scim
Package scim implements the JSON contract of SCIM 2.0 (RFC 7643/7644) used to provision and deprovision users from an identity provider (ISO A.5.16/A.5.18).
Package scim implements the JSON contract of SCIM 2.0 (RFC 7643/7644) used to provision and deprovision users from an identity provider (ISO A.5.16/A.5.18).
serverdial
Package serverdial opens the SSH connection to a managed server: the provisioned private key comes from the store, is decrypted by the keyring, and the server's host key is pinned (§20.1).
Package serverdial opens the SSH connection to a managed server: the provisioned private key comes from the store, is decrypted by the keyring, and the server's host key is pinned (§20.1).
session
Package session implements browser authentication for the dashboard (PRD §698): a login endpoint, HttpOnly session cookies, CSRF protection, session rotation and lockout.
Package session implements browser authentication for the dashboard (PRD §698): a login endpoint, HttpOnly session cookies, CSRF protection, session rotation and lockout.
sshexec
Package sshexec runs commands on target servers over SSH (§3.1).
Package sshexec runs commands on target servers over SSH (§3.1).
sshkey
Package sshkey parses and generates SSH key material (PRD §3.1: keys without passphrase, public part and SHA256 fingerprint derived from the private material).
Package sshkey parses and generates SSH key material (PRD §3.1: keys without passphrase, public part and SHA256 fingerprint derived from the private material).
telemetry
Package telemetry wires traces, metrics and logs to an OTLP endpoint (ADR-008: "OTLP everywhere, no proprietary protocol").
Package telemetry wires traces, metrics and logs to an OTLP endpoint (ADR-008: "OTLP everywhere, no proprietary protocol").
terminal
Package terminal bridges a WebSocket connection to a remote PTY (§24.4, ADR-024).
Package terminal bridges a WebSocket connection to a remote PTY (§24.4, ADR-024).
totp
Package totp implements RFC 6238 time-based one-time passwords over the RFC 4226 HOTP construction, for the dashboard's 2FA (PRD §10.2, §23.3).
Package totp implements RFC 6238 time-based one-time passwords over the RFC 4226 HOTP construction, for the dashboard's 2FA (PRD §10.2, §23.3).
tunnel
Package tunnel bridges a WebSocket to TCP streams multiplexed over it (ADR-032, subprotocol akerdock-tunnel-v1).
Package tunnel bridges a WebSocket to TCP streams multiplexed over it (ADR-032, subprotocol akerdock-tunnel-v1).
uptime
Package uptime implements the integrated uptime monitoring of ADR-017: simple HTTP/TCP probes run from the control plane — outside the monitored workload, which is the whole point: a struggling server must not be the one vouching for its own workloads — and a threshold-based state machine whose transitions ARE the anti-flapping.
Package uptime implements the integrated uptime monitoring of ADR-017: simple HTTP/TCP probes run from the control plane — outside the monitored workload, which is the whole point: a struggling server must not be the one vouching for its own workloads — and a threshold-based state machine whose transitions ARE the anti-flapping.
web
Package web serves the dashboard from the single port of the control plane (§27.1, ADR-021): UI, API, SSE and terminal all live behind one port, so an operator opens one URL and a reverse proxy has one thing to forward.
Package web serves the dashboard from the single port of the control plane (§27.1, ADR-021): UI, API, SSE and terminal all live behind one port, so an operator opens one URL and a reverse proxy has one thing to forward.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL