Introduction
Installation
Two installs: the CLI on your machine, and the cluster on your server.
The CLI
JEKYO is a single static binary:
curl -fsSL https://jekyo.com/install | sh
The script detects your OS and architecture (Linux/macOS, amd64/arm64) and installs the latest release. Working with an AI agent? Chain the skill install so your agent learns JEKYO in the same line:
curl -fsSL https://jekyo.com/install | sh && jekyo skill install --global
Prefer manual? Grab a binary from the releases page or go install github.com/jekyo/jekyo/cmd/jekyo@latest.
That's the only local requirement. Docker is needed only if your apps use build: (kubectl is never required; jekyo kubectl is just an optional escape hatch).
The server
You need an Ubuntu server (20.04/22.04/24.04) you can SSH into, with ports 80, 443, and 6443 reachable. Check it first without changing anything:
jekyo server preflight ubuntu@1.2.3.4
Preflight prints a PASS/WARN/FAIL table: occupied ports, other Kubernetes installs, firewall rules, clock sync, GPU quirks like Secure Boot. Fixable warnings can be remediated automatically with --fix; a detected Docker engine is only ever removed if you explicitly pass --remove-docker.
Then install:
jekyo server install ubuntu@1.2.3.4 \
--ip 1.2.3.4 \
--storage /storage \
--domain example.com \
--acme-email you@example.com
What lands on the server
k3s (pinned version), Envoy ingress (Contour), automatic TLS via ACME (kcert), a private registry, a WireGuard VPN (wg-easy), local-path persistent volumes, and, when a GPU is detected, NVIDIA drivers and the container runtime.
The install is idempotent: re-running it converges the server (repairs drift, applies new versions) and never rotates your credentials. When it finishes, your machine has a context: credentials and endpoints for that server:
jekyo context ls
jekyo context show # registry & VPN passwords live here
DNS: point your records at the server
Create an A record for every domain your apps will serve (or one wildcard record covering them all) pointing at the server's IP:
*.example.com A 1.2.3.4
example.com A 1.2.3.4
That's the only DNS work JEKYO ever asks of you. Certificates, routing, and renewal are automatic from there.
Why give the installer a domain?
--domain is optional, but it unlocks three things:
- Automatic TLS: Let's Encrypt needs a public name to issue against; without one, apps serve HTTP or self-signed only.
registry.example.com: push images over HTTPS from CI or a teammate's laptop, no SSH access needed.vpn.example.com: a stable VPN endpoint that survives server IP changes.
Without a domain everything still works: JEKYO reaches cluster-internal services over SSH instead.
Internal DNS (optional)
--internal-domain jekyo.internal sets the cluster-internal DNS suffix, so over the VPN your services resolve as db.jekyo-myapp.svc.jekyo.internal. Cosmetic but pleasant. The default (cluster.local) is the safe choice if you plan to hand-deploy third-party Kubernetes manifests, some of which hardcode it.
GPU servers
Nothing extra to do: if lspci shows an NVIDIA device, the installer takes care of drivers, the container toolkit, and the Kubernetes runtime class, and finishes with a CUDA smoke test. Preflight warns about the two classic traps (Secure Boot blocking unsigned modules, the nouveau driver being loaded) and can fix the latter.