kitshn
Free plan

Install kitshn

kitshn runs on your own Cloudflare account, on the free plan. You set it up once, then every repo deploys with a push.

Before you start

What you need

Set up

Set up kitshn

  1. Make a Cloudflare API token

    Open the token page with the permissions filled in, then create the token. When a permission is missing later, the setup names it and prints this link.

  2. Turn on Zero Trust

    kitshn uses Cloudflare Access for every login. Open Zero Trust in the Cloudflare dashboard once and pick the free plan. The setup stops with the link when this step is missing.

  3. Run the setup

    Pick the admin address, for example kit.example.com on your domain:

    curl -fsSL https://kit.yarden-zamir.com/install | \
      CLOUDFLARE_API_TOKEN=... \
      KITSHN_HOST=kit.example.com \
      KITSHN_OWNER_EMAILS=you@example.com \
      KITSHN_DEPLOY_OWNERS=your-github-name sh

    It makes the Worker, its database, the R2 bucket, the Access applications and the Owner circle. Run it again at any time: it changes only what is not right, and prints each change.

  4. Add your passkey and open the map

    At the end, the setup prints the admin address and a link to register your passkey. Register it, then open https://kit.example.com. You log in with an email code and the passkey.

Deploy

Deploy your first app

  1. Add a recipe

    Put kitshn.config.ts at the root of the repo. A static site:

    import { defineApp } from "kitshn";
    
    export default defineApp({
      static: { build: "npm ci && npm run build", output: "dist" },
      deploy: [
        { on: "push", branch: "main", name: "prod", startsIn: "Everyone" },
        { on: "pull_request", name: "pr-{pr}", ephemeral: true },
      ],
    });

    Use compose: { runsOn: ["docker"] } for a Compose app, or worker: { ... } for a Worker app. kitshn reads the recipe as data and never runs it, so it holds no loops and no function calls.

  2. Add the workflow

    Put this in .github/workflows/kitshn.yml. It is the same for every app:

    on:
      push:
      pull_request:
        types: [opened, synchronize, reopened, closed]
      workflow_dispatch:
    permissions:
      contents: read
      id-token: write
    jobs:
      kitshn:
        uses: Yarden-zamir/kitshn/.github/workflows/kitshn2-deploy.yml@main
        with:
          server: https://kit.example.com
        secrets: inherit

    The repo needs no secret. GitHub signs each run, and kitshn checks the signature.

  3. Push, then Allow

    The first push of a new repo waits. The map shows "1 repo waiting": click Allow, and the deploy starts. Every later push deploys at once.

  4. Share it

    The new card starts in the startsIn circle, or in the tray, private. Drag it into a circle to share it. Its address is <repo>.<your domain>.

Machines

Add a machine

  1. Get a join command

    On the map, click +, then Add a machine. kitshn shows a command with a one-time code that ends after 10 minutes.

  2. Run it on the machine

    curl -fsSL https://kit.example.com/join | sh -s -- <code> https://kit.example.com

    It installs the daemon and its tunnel as services of your user. The machine needs no Node.js and opens no port.

  3. Give it labels

    In the machine panel, add the label deploy so that apps may run there, and labels such as docker that recipes ask for in runsOn.

Previews

Pull request previews

A pull_request entry gives each pull request its own address, <repo>-pr-<n>.<your domain>. It starts private, and goes away when the pull request closes.

Secrets

Values and secrets

A GitHub secret or variable named KITSHN_<NAME> reaches the app as <NAME>. A secret only for production goes in the GitHub Environment prod.

Domains

More addresses

A push entry can list up to 5 addresses. The first one is under your kitshn domain. Others may use further domains that you add with KITSHN_ZONES in the setup.

Live

Share a dev server

kitshn expose 5173 --name demo --dev shares a dev server of a machine at demo.<your domain>, behind its circles. When the machine is off, visitors get the offline page.

KitSHn 1

Move an app from KitSHn 1

KitSHn 1 deployed over SSH to one VPS with Caddy. kitshn replaces it. To move an app, replace .kitshn.yaml with kitshn.config.ts, and point the workflow at kitshn2-deploy.yml. A compose.yml of KitSHn 1 keeps working, within the safety checks that kitshn runs on Compose files.

The first deploy on the same machine takes over the KitSHn 1 data once, and keeps the old copy for a rollback. Then move the DNS record of the address to kitshn. The migration notes have the details.