Getting Started

Deploy Kwirth in your Kubernetes cluster in under 5 minutes. No external dependencies, no complex configuration.

Prerequisites

RequirementMinimum versionNotes
Kubernetes1.24+Any distribution: EKS, GKE, AKS, k3s, Kind, Docker Desktop
Helm3.xRequired for Helm install method
kubectl1.24+For manual install or port-forwarding
ClusterRole—Kwirth needs read access to cluster resources. If you write your own role instead of using the supplied manifests, include the batch API group, or jobs will not appear in the resource selector

Those are the prerequisites for running Kwirth on Kubernetes. Deploying on AWS ECS or with Docker Compose has its own, listed with that option — and running there without a cluster to observe is a supported configuration in its own right.

Installation

Option 1 — Helm (recommended)

Add the Helm repository
helm repo add kwirth https://kwirthmagnify.github.io/kwirth/helm-charts
helm repo update
Install Kwirth
helm install kwirth kwirth/kwirth \
  --namespace kwirth \
  --create-namespace
Access the UI
kubectl port-forward -n kwirth svc/kwirth 3883:3883
# Open http://localhost:3883

Option 2 — kubectl apply

Three manifests, and they differ in one thing: how much of the cluster Kwirth is allowed to touch. Each is a single file, each is applied the same way. Pick one.

ManifestWhat the cluster lets it doNode metricsConfig lives in
kwirth.yamlverbs: ['*'] on 15 API groupsyesSecrets and ConfigMaps
kwirth-full-ro.yamlget, list, watch. Nothing else, anywhereyesa PersistentVolumeClaim
kwirth-zero.yamlnothing at all — not one RBAC object in the filenoa PersistentVolumeClaim

kwirth.yaml — everything works. The express setup: up in two minutes with every feature available. It is a broad grant, and deliberately so — verbs: ['*'] is create and delete on every Secret in the cluster and exec into any pod, which is what makes the ops and fileman plugins, and the Magnify commands, work at all.

kubectl apply -f \
  https://raw.githubusercontent.com/kwirthmagnify/kwirth/master/deploy/kubernetes/manifests/kwirth.yaml

kubectl get pods -n kwirth --watch

kwirth-full-ro.yaml — not one write. The same deployment with every verb that changes the cluster removed: one rule, three verbs. And it loses no observability for it, metrics included — Kwirth reads the ServiceAccount token Kubernetes already projects into every pod and that the kubelet rotates, so reaching each node's kubelet costs no permission at all. That needs Kwirth 0.6.65 or later; on an older image it starts fine and says There is no SA Token, no metrics will be available.

kubectl apply -f \
  https://raw.githubusercontent.com/kwirthmagnify/kwirth/master/deploy/kubernetes/manifests/kwirth-full-ro.yaml

What it gives up are the actions: the Magnify commands — restart, scale, cordon, drain, evict, apply, delete — and the ops and fileman plugins. The button stays in the UI and the API server answers 403, so if you do not want buttons that cannot work, do not install those two plugins. Its configuration also moves to a PersistentVolumeClaim instead of Secrets, and that is what removes the write permission rather than a detail of persistence: MASTERKEY becomes the key that configuration is encrypted with: leave it unset and kwirth generates a random one on the first boot and keeps it on the volume, so each installation gets its own instead of a shared default — it must then never change. For at-rest encryption that also resists someone reading the volume, set it from a Secret kept outside the volume.

kwirth-zero.yaml — it does not know it is in a cluster. No ClusterRole, no binding, no ServiceAccount of its own, and the token the kubelet projects into every pod turned off, so there is no credential in the container either. Use it where the cluster is not yours to read: a shared platform, a tenant namespace, a policy that does not hand out ClusterRoles. It is the ECS deployment below, in a pod — it serves the front end, installs and runs extensions, keeps its configuration on the volume, uses the database, and federates against other Kwirths that do have access. What it loses is everything that reads the cluster it lives in.

kubectl apply -f \
  https://raw.githubusercontent.com/kwirthmagnify/kwirth/master/deploy/kubernetes/manifests/kwirth-zero.yaml

That one carries FORCE=container, and the line is not optional: the kubelet injects KUBERNETES_SERVICE_HOST into every pod, so taking the permissions away does not stop Kwirth being identified as a Kubernetes workload — and inside a cluster the API is deliberately not optional, because a failure there is an error and not a degradation. Note that container does not mean "no cluster": it means the platform is not one Kwirth recognises. Mount a kubeconfig and the same deployment reads that cluster, which is what the ECS task definition below does.

The Helm chart offers the same three as kwirth.mode: normal, readonly and zero.

Option 3 — AWS ECS (Fargate or EC2)

Kwirth runs as an ECS task with the same image, on either launch type. There is no ECS-specific build, and nothing to declare for the environment to be detected: the ECS agent injects its own metadata variable in both launch types and Kwirth reads it.

What changes is not the image, it is what the platform stops giving you. Kubernetes hands Kwirth a namespace to keep its state in and an identity; ECS hands neither, so both become configuration.

RequirementNotes
ECS clusterExisting. The template does not create one
VPC with private subnetsOne per AZ you use. The EFS mount targets live here too
Application Load BalancerExisting. The template creates the target group; you attach it to a listener
EFSCreated by the template. Without a volume nothing survives a task recycle
IAM permissionsFor the identity that deploys — see iam-deploy-policy.json
Grant the deploying identity its permissions

Attach iam-deploy-policy.json to the user or role you deploy with. The one people forget is iam:PassRole: creating the service means handing ECS the roles the task will assume, and without it the error talks about the service rather than the missing permission.

Deploy the surrounding resources

EFS with its access point, security groups, target group, IAM roles, log group and the generated MASTERKEY secret.

aws cloudformation deploy \
  --template-file deploy/ecs/cloudformation.yaml \
  --stack-name kwirth \
  --capabilities CAPABILITY_IAM \
  --parameter-overrides \
    VpcId=vpc-xxxx \
    SubnetIds=subnet-aaaa,subnet-bbbb \
    ClusterName=my-cluster \
    LoadBalancerSecurityGroupId=sg-xxxx
Attach the target group to your listener

The stack outputs TargetGroupArn. Kwirth answers /healthz in every environment, and the target group already checks that path — point it elsewhere and the task is recycled forever without saying why.

aws elbv2 create-rule \
  --listener-arn <YOUR_LISTENER_ARN> \
  --priority 10 \
  --conditions Field=path-pattern,Values='/*' \
  --actions Type=forward,TargetGroupArn=<TargetGroupArn>
Read the startup log

It is the first diagnostic for a deployment you cannot look inside. It states what Kwirth found and why.

Execution environment: 'ecs'
  Kubernetes API: no (no usable kubeconfig)
  Store: encrypted files at '/data/kwirth' (KWIRTH_STORE)

Prefer not to use CloudFormation? Register task-definition-fargate.json directly and create the service by hand — the template is then just the specification of what to create around it.

Warning: MASTERKEY derives the encryption key for secrets at rest. Changing it later makes everything already written unreadable — there is no migration. Decide it once, before the first run, and pass it through secrets[], never environment[], which is visible in the console and in describe-task-definition.
Info: What Kwirth observes on ECS is a separate question from where it runs. Mount a kubeconfig and it observes that cluster, with channels behaving exactly as they do in-cluster. Mount nothing and it observes no infrastructure — which is a complete configuration, not a half-started one: the front is served, users log in, autonomous channels run, ingestion providers receive, and you can federate against another Kwirth. Kwirth does not manage ECS tasks as if they were a cluster.

SQL persistence is optional and separate — some extensions keep their data in PostgreSQL, which on ECS means RDS or Aurora. The connection is lazy, so Kwirth starts fine without it. Details, including why the database user needs CREATEDB, in the deploy/ecs/ folder.

Option 4 — Docker Compose (any machine with Docker)

Kwirth on your own machine or a VM, without Kubernetes: persistent, with its secrets encrypted, and optionally with PostgreSQL. One script does everything — it writes the configuration, generates the master key, starts the containers, waits until Kwirth is healthy and tells you where to log in.

RequirementNotes
DockerDocker Engine or Docker Desktop, with Compose v2 (docker compose)
The deploy/compose/ folderFrom the repository: the compose files and the two install scripts
Install

From deploy/compose/. install.sh on Linux, macOS and WSL; install.ps1 on Windows.

./install.sh up                # Linux, macOS, WSL
.\install.ps1 up               # Windows PowerShell

Kwirth is up:  http://127.0.0.1:3883
First login:   admin / password  (change it right away)
Add what you need

Run up again with options at any time; they are remembered in .env.

./install.sh up --sql                      # + PostgreSQL
./install.sh up --kubeconfig ~/.kube/k3d    # observe a cluster
./install.sh up --watchtower               # update itself when the tag moves
./install.sh up --tag 0.6.57 --port 8080    # pin a version, another port
Update, stop, remove
./install.sh update     # pull the new image of the tag and recreate
./install.sh down       # stop; the data stays in its volumes
./install.sh destroy    # remove everything, data included (asks first)
Warning: the first up writes a MASTERKEY into deploy/compose/.env, and that key is the only way to read Kwirth's encrypted store. Keep a copy of .env — lose it and the data in the volume cannot be read again. It is never overwritten by later runs.
Info: the port is published on 127.0.0.1 only: nothing outside the machine reaches Kwirth until you pass --bind 0.0.0.0. "Restart Kwirth" restarts the container with the image it already has — to get a new one, use update or --watchtower. Everything else is in the deploy/compose/ folder.

First Login

On first boot, Kwirth creates a default admin user with password password. You will be prompted to change the password on first login.

Warning: Always change the default admin password before exposing Kwirth via an Ingress or public LoadBalancer.

Connect your first cluster

Kwirth can monitor any number of Kubernetes clusters. The cluster where Kwirth runs is auto-connected. To add a remote cluster:

  1. In the Kwirth UI, go to Settings → Manage clusters list
  2. Click NEW and provide the API server URL and a proper API Key
  3. Test the connection and save

Open your first channel

Use the resource selector just below the top bar. You need to specify what is your cluster and your target 'view' (the whole cluster, one or more namespaces, one or more controller, one or more pods or even a set of containers belonging to different pods). Then choose a channel type, for example:

Click the ADD button and you will get a new tab added. On the tab settinigs just select START and the magic begins.

Install Kwirth Desktop

Kwirth Magnify is available as a standalone desktop application in two distributions. Both connect to any Kwirth instance and support local kubeconfig clusters out of the box — no cluster-side Kwirth installation required for basic use.

Info: Kwirth Desktop has two connection modes: it can connect directly to any Kubernetes cluster using your local kubeconfig credentials (no Kwirth container required), or it can connect to a cluster where Kwirth is already installed to take advantage of all server-side features.

Electron build

The original desktop build, based on Electron. Available for Windows (.exe) and Linux (.AppImage).

⬇ Download Electron build from GitHub Releases

Tauri build New

A lighter, faster build powered by Tauri. Smaller binary, lower memory footprint. Available for Windows (.msi) and Linux (.AppImage).

⬇ Download Tauri build from GitHub Releases

Next steps