Skip to content

cairn

The directory page for the people you host services for.

Build Security Coverage Release License: GPL-3.0 Go Image Self-hosted

A cairn is a small stack of stones left by hikers who walked the trail before you, so you find your way without digging.


Your family, your clients, your friends: they don't want a dashboard, they want to know what this place is, what each tool does, and whether it works right now. cairn is that page. Written in their language, readable without an account or a manual, and boring for you to operate.

What your visitors get

  • A welcome note in your words: who hosts this, for whom, how to reach you. Dismissable, remembered for a year (a plain cookie, no tracking).
  • Tools grouped by need, one plain sentence each, with optional "Learn more" pages for the curious.
  • Live status pills fed by your Gatus, each linking to its own endpoint page. Your server does the polling, never the visitor's browser.
  • Their language: the server picks it from the browser, a switcher pins it. One config file, translations inline.
  • Search from anywhere: just start typing, or ⌘K. A name finds that one service, not everything that mentions it; keyword search still reaches descriptions and hidden tags, accent-insensitive.
  • At home on a phone: the layout reflows to one hand, the header steps aside as you scroll and returns the moment you head back up, and a burger keeps search within thumb's reach.
  • Built to stay readable: text contrast measured against WCAG AA in both themes, a skip link, named landmarks, search results announced through a live region, a theme toggle that says which way it is set, and right-to-left languages laid out the right way round. The controls a visitor can operate, the search box and the phone's jump-to select, carry a boundary that clears 3:1, remeasured in a real browser on every pull request. Tested with a browser, never audited as a whole, and not yet with a real screen reader: if you use one, tell us what breaks.
  • Calm typography, light and dark, keyboard-friendly, and every feature degrades gracefully without JavaScript.

What you get as the operator

  • One static binary, about 10 MB, zero runtime dependencies, no database. The image around it is 4.3 MB to pull, since that binary compresses well.
  • YAML mounted read-only; edits apply live within seconds, and a config error names the file, the line and the expected shape instead of taking the site down.
  • Legal pages served by cairn itself (legal notice, privacy…): the pages self-hosters never have anywhere to put. Written in ordinary markdown, headings and lists and tables, with raw HTML left as text so a config file can never reach the page as markup.
  • Wherever your domain has room: a domain, a subdomain, or a sub-path of one you already use (example.org/cairn/, one flag). cairn handles the prefix itself, so the proxy needs no rewriting rule.

Secure by subtraction

The safest surface is the one that isn't there: cairn stores nothing, signs no one in, and takes no input it has to trust. What little runs is kept deliberately tight, from the image down to the wire.

  • FROM scratch, non-root: no shell, no package manager, no libc in the image, so a compromised process has nothing to pivot into.
  • Runs locked down: read_only, cap_drop: ALL and a self-probing healthcheck all work out of the box. See the hardened compose.
  • A strict Content-Security-Policy (default-src 'none', inline fragments pinned by hash) and the hardening headers, with no third-party script or font to trust.
  • No outbound requests of its own: air-gap friendly, its only companions optional and yours, a self-hosted Gatus for status and icons you can serve yourself. The demo runs on a network with no route out and serves its own icons, so the page it shows you makes no third-party request at all.
  • A watched supply chain: every pull request runs govulncheck, a Trivy image scan and CodeQL, and they run again on the pushes that change code and weekly on a schedule. Dependabot follows the dependencies, and every CI action is pinned to a commit rather than a movable tag.
  • Artifacts you can check: the image is signed with cosign and ships SLSA provenance and an SBOM; the release binaries carry their own attestation. The verification commands are two lines.

Quickstart

Nothing to write, nothing to mount, just look at it:

docker run --rm -p 8080:8080 ghcr.io/morgankryze/cairn:stable

That is a running cairn on http://localhost:8080, telling you what to feed it. When you are ready to feed it, two files and one command:

# config/services.yaml
- id: pdf
  url: https://pdf.example.org
  icon: stirling-pdf
  name: PDF toolbox
  desc: Merge, split, compress your PDFs.

(Want two languages? name: { fr: Boîte à outils PDF, en: PDF toolbox }; every text key works both ways. See Languages.)

# compose.yaml
services:
  cairn:
    image: ghcr.io/morgankryze/cairn:latest
    ports:
      - 8080:8080
    volumes:
      - ./config:/config:ro
docker compose up -d

Open http://localhost:8080: that is a finished page. Everything else (title, languages, categories, status, theming) is one optional key at a time, at your pace: follow Getting started.

Prefer to see it live first? A public instance runs at https://cairn.libresoftware.cloud, and the demo stack spins up your own copy, with a real Gatus and a handful of sample services, one intentionally dead, in one command:

git clone https://github.com/MorganKryze/cairn.git && cd cairn/demo
docker compose up -d --build

Documentation

Everything lives in docs/, and it is written to be read, not just grepped: each page teaches the why before the how, in plain prose a developer can enjoy rather than a reference dump to endure. If you like understanding how a thing works, start anywhere below.

Start Getting started, the five-minute path · Upgrading, what a new version can refuse and how to fix it
Configure Services · Site · Text · Theming · Languages
Deploy Docker Compose · Podman · Bare binary · Kubernetes · Helm · Air-gapped · Reverse proxies
Recipes Status page with Gatus · Icons · Multiple files · Migration
Look up Reference · FAQ · Comparison

Not a dashboard, on purpose

cairn is a directory, not a control panel: no auth, no widgets, no Docker socket, no admin UI. If the audience is you, the admin, Homepage or Homer will make you happier; the comparison is honest about it.

Ideas, contributions, support

cairn is young and opinionated, and other people's eyes make it better. Ideas and bug reports are welcome in the issues, code and docs through contributing, always within the scope above. And if cairn serves your people well, a coffee keeps its maintainer walking the trail.

Colophon

A colophon tells how the book was made, so here is mine: Go, plain YAML, Fraunces for the headings, and Claude Code drafting at my side, never on autopilot. The taste, the reviews and the final word stay mine; the tests, the CI and the public history keep me honest.

License

Free software under GPL-3.0: use it, modify it, share it. What you redistribute stays under the same license, source included. Hosting your own instance is not distribution and asks nothing of you.

Releases

Sponsor this project

Packages

Used by

Contributors

Languages