yeke.io · docs
Installation
YEKE is a single container. It installs on one machine with one command; the first block below is copy-paste-and-run. A second command below shows every setting; sections on upgrades and Kubernetes follow after that.
Requirements
Three things. A Kubernetes cluster is not one of them — you connect that afterwards.
- A machine with Docker. Docker Compose is not required; use it if you'd like (further down).
openssl— or anything else that can produce 32 random bytes.- Access to Docker Hub — the
nairotech/yekeimage is public and multi-arch (amd64 + arm64).
There's no separate web container and no reverse proxy in
front of it anymore. The UI, the API, and the agent tunnel all come from the same process, the
same port — this image is the only thing you install.
One command
Copy it, paste it. No separate config file, no repo to clone.
docker run -d --name yeke --restart unless-stopped -p 8080:8080 \ -v yeke-data:/var/lib/yeke \ -e YEKE_SNAPSHOT_KEY="$(openssl rand -hex 32)" \ nairotech/yeke:0.7.3
Pin the version tag — don't write latest: core's version also determines
the tag of the agent image that gets installed in your cluster. If the tag drifts, the agent
ends up with a protocol mismatch. Released tags are on
Docker Hub.
Wait for it to come up
/healthz doesn't require auth and doesn't touch the database; it's the cheapest
signal that things are ready. Takes a few seconds:
until curl -sf http://localhost:8080/healthz; do sleep 1; done
This command prints {"status":"ok"} and exits. The container has
no built-in healthcheck, so docker ps never shows (healthy)
— that's expected, not a sign something went wrong.
Create the first administrator
On first boot there are no users at all; core generates a setup token and prints it to the log:
docker logs yeke 2>&1 | grep -A1 SETUP
Open http://localhost:8080/, paste the token, and pick a username and password.
The token is valid for 60 minutes and can be used once; if it expires,
docker restart yeke issues a new one.
Save the key somewhere now
YEKE_SNAPSHOT_KEY encrypts rollback snapshots and direct-mode kubeconfigs. In
the command above, the key lives only in the container's configuration — the moment
you remove and recreate the container (an upgrade requires exactly that), your only copy is
gone.
Losing it fails quietly enough to mislead you: core started with the wrong key does
not crash, /healthz still returns 200, and the setup screen doesn't
reopen either — the only symptom is that login fails, forever. Measured on 2026-08-10. Read
the key out and put it in your password vault:
docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' yeke | grep YEKE_SNAPSHOT_KEYFor anything permanent, keeping the key in a file rather than on the command line is better — the next section does exactly that.
Every setting, out in the open
The permanent version of the same install: key in a file, public address declared, license attached. Delete whichever line you don't need.
First generate the key once and write it to a file. If the file already exists this leaves it alone — re-running this line does not rotate your key:
install -d -m 700 /etc/yeke [ -f /etc/yeke/snapshot.key ] || openssl rand -hex 32 > /etc/yeke/snapshot.key chmod 600 /etc/yeke/snapshot.key
docker run -d --name yeke --restart unless-stopped \ -p 8080:8080 \ -v yeke-data:/var/lib/yeke \ -v /etc/yeke/license.txt:/etc/yeke/license.txt:ro \ -e YEKE_SNAPSHOT_KEY="$(cat /etc/yeke/snapshot.key)" \ -e YEKE_PUBLIC_URL="https://yeke.ornek.com" \ -e YEKE_ALLOWED_ORIGINS="https://yeke.ornek.com" \ -e YEKE_LICENSE_PATH="/etc/yeke/license.txt" \ nairotech/yeke:0.7.3
The last three lines are optional. If you don't have a license, or you'd rather
upload it from the UI, remove the YEKE_LICENSE_PATH line and its mount line
together. Removing just one of them creates a quiet mess: Docker, trying to mount a file
that doesn't exist, creates an empty directory at that path instead; core can't read a
directory, rejects the license, and keeps running as Community — the install looks fine, but it
catches up with you later when you try to copy your actual license file to that path.
| Variable | Required | What it does · what happens if left empty |
|---|---|---|
YEKE_SNAPSHOT_KEY | Required | The 32-byte key (64 hex characters or base64) that encrypts snapshots and direct-mode credentials. Without it core doesn't start at all — it explains why and exits. |
YEKE_PUBLIC_URL | If you'll add a cluster | The absolute address at which core is reached from the outside; the agent
install manifest uses this address. Left empty, core boots fine and login works — only
adding a cluster in agent mode stops, with PUBLIC_URL_NOT_CONFIGURED. Core
does not guess this address: most installs listen on 0.0.0.0:8080, and
that address is not reachable from inside the cluster. |
YEKE_ALLOWED_ORIGINS | No | Extra origins accepted by the CSRF/Origin check (comma-separated). Needed only when
you put a reverse proxy (Cloudflare, nginx, Traefik) in front of core and that
layer presents an external address different from the Host core sees. |
YEKE_LICENSE_PATH | No | Path to the Enterprise license file. Left empty, the install runs as Community: a cap of 3 clusters / 5 users, every core capability unlocked, never expires. Set, it becomes that boot's only license source and the license can no longer be uploaded from the UI. |
YEKE_BOOTSTRAP_TOKEN | No | A fixed setup token for the first administrator — saves you from reading the log if you're scripting the install. Left empty, core generates one at random and logs it. |
You don't need to define any YEKE_* variable that isn't in this
table. Three of them — YEKE_ALLOW_HEADER_IDENTITY, YEKE_DEV_USER,
YEKE_DEV_GROUPS — were removed, and if defined core doesn't start at all:
authentication exists precisely because those three were shut off, and silently ignoring them
would let you believe it "still works the old way."
What comes next
YEKE is running, but it cannot see a single cluster yet.
- Connect a cluster — agent mode or direct kubeconfig.
- Set up permissions — which Kubernetes identity each person writes under.
Upgrades and backups
An upgrade recreates the container. Data and key live on disk, so they don't change — if you kept the key on the command line, read it out first.
docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' yeke | grep YEKE_SNAPSHOT_KEY
docker pull nairotech/yeke:<new-version>
docker rm -f yeke
# then the same run command: new tag, SAME key- An upgrade is an outage, every single one. The database is single-writer SQLite: the new core can't start until the old one has stopped. The measured window in production is about 60 seconds. Even a release that changes one line of UI text is subject to this outage — the UI ships inside core's image.
- Migrations run at startup and core prints a
schema vNline to its log; confirm success from that line, not by guessing. - Backup — the
yeke-datavolume plus the/etc/yekedirectory. Together they're the entire install; a data backup without the key is useless.
Compose and Kubernetes
The single command is enough for most installs. If you want the service definition to be declarative, there are two more paths; both run the same image.
Docker Compose
No need to clone a repo — this is the whole file:
services:
core:
image: nairotech/yeke:0.7.3
ports:
- "8080:8080"
environment:
YEKE_SNAPSHOT_KEY: ${YEKE_SNAPSHOT_KEY:?key is required}
YEKE_PUBLIC_URL: ${YEKE_PUBLIC_URL:-}
volumes:
- core-data:/var/lib/yeke
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8080/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
restart: unless-stopped
volumes:
core-data:Put the key in a .env file next to it and run docker compose up -d.
The :? mark is deliberate: if the key is missing, up never starts.
On this path docker ps does show (healthy) — the healthcheck
is part of this file, not the image.
Kubernetes
Running core inside a cluster is supported and a manifest set is ready: namespace,
ReadWriteOnce PVC, a single Deployment (strategy: Recreate), Service,
and a standard Ingress. The key is not in the manifests — you create the Secret by
hand. The set is short but has a few fields you'll need to adapt to your setup (hostname,
StorageClass, Ingress class);
ask and we'll send
them.
You don't have to install inside the cluster it manages, and usually you don't want to: when the cluster YEKE manages goes down, the UI that would fix it needs to still be up.
Stuck on a step? Write to us.
Every command on this page was actually run while it was written. If a step still does not go as expected, reach out directly.