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:

  1. Automatic TLS: Let's Encrypt needs a public name to issue against; without one, apps serve HTTP or self-signed only.
  2. registry.example.com: push images over HTTPS from CI or a teammate's laptop, no SSH access needed.
  3. 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.

Previous
Getting started