Skip to content
MorganKryzePublic

About

The directory page for the people you host services for: no account, multilingual, live status, one tiny container.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

88 stars

Watchers

1 watching

Forks

cairn

The directory page for the people you host services for.

Build Security Tests Coverage Release License: GPL-3.0

Image Docker pulls Go Helm Docker Compose Kubernetes Context7

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.

Features

What your visitors get

  • 👋 A welcome note in your words: who hosts this, for whom, how to reach you. Dismissable, remembered for a year.
  • 🗂️ Tools grouped by need, one plain sentence each, with a "Learn more" page for the curious.
  • 🚦 Live status pills fed by the monitor you already run. Your server does the polling, never the visitor's browser.
  • 🏷️ A word for where a service stands: coming soon, beta, new, deprecated, no longer available. The last two stop being links.
  • 🌍 Their language: the server reads it from the browser, a switcher pins it. cairn ships ten, your own text goes inline.
  • 🔒 A lock on what needs an account, right after the name, and a note on its page saying whom to ask for one.
  • 🔍 Search from anywhere: start typing, or ⌘K, and Tab through what it finds. A name finds that one service, not everything that mentions it.
  • 📱 At home on a phone: one-handed layout, and a header that steps aside as you scroll and returns the moment you head back up.
  • ♿ Built to stay readable: WCAG AA contrast in both themes, a skip link, named landmarks, announced results, right-to-left the right way round.
  • 🌗 Calm typography, light and dark, and every feature still works with JavaScript off.

CI measures the contrast in a real browser on every pull request. No audit has covered cairn as a whole, and no screen reader user has tried it yet. If you use one, tell us what breaks.

Left: a service detail page, with the name beside its icon and a button opening the tool at the far end of the same row, then a live status pill, a paragraph explaining what the tool is for, and a screenshot with its caption. Right: the same directory on a phone, a row of category chips then cards each showing an icon, a sentence, a self-hosted flag and a status pill

Behind a card when a visitor wants more than one sentence, and the same page in a hand.

What you get as the operator

  • 📦 One static binary, no database, in an image of about 5 MB to pull.
  • 📝 YAML mounted read-only, and cairn picks up an edit within seconds. A bad one names the file, the line and the shape it wanted, instead of taking the site down.
  • 📜 Legal pages served by cairn itself, in ordinary markdown: the notice and privacy pages self-hosters never have anywhere to put.
  • 🌐 A domain, a subdomain, or a sub-path of one you already use. cairn handles the prefix, so your proxy needs no rewriting rule.
  • 🗃️ Or no server at all: cairn -export site.zip writes the site as static files for Cloudflare Pages, Netlify or an Apache host. The status pills are the one thing that stays behind.

Status monitoring

Whatever already tells you it is up. cairn does not ask you to change monitors. It reads the one you run, and the pills come from your server, never from the visitor's browser.

Self-hosted Gatus · Uptime Kuma · Cachet · Statping-ng · Upptime
Hosted Atlassian Statuspage · Instatus · UptimeRobot · Better Stack · StatusCake

Every one was read from a live instance, not from a manual. Anything else publishing a list of names and states takes six lines of config, and which monitors cairn reads also says what cannot be read, and why.

Gatus

Gatus gets the warmest handshake, and has earned it. It is the only one cairn integrates with both ways, since cairn -emit-gatus writes its endpoint config out of your services, and the only one whose pills link to a page per service rather than to one page for everything. If you have no monitor yet, start there.

Security

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.

  • 🪨 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 work out of the box. Hardened compose.
  • 🧱 A strict Content-Security-Policy (default-src 'none', inline fragments pinned by hash), with no third-party script or font to trust.
  • 🔌 No outbound requests of its own, so it is air-gap friendly. The demo runs on a network with no route out and still makes no third-party request.
  • 🔬 A watched supply chain: govulncheck, a Trivy image scan and CodeQL on every pull request and weekly on a schedule, and every action pinned to a commit rather than a movable tag.
  • 🧪 More test than product, and every check has to fail before it earns trust: patch the fix out, read the red. The badges above carry the live count.
  • ✍️ Artifacts you can check: cosign signature, SLSA provenance and an SBOM on the image, an attestation on the binaries. Two lines to verify.

Quickstart

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

docker run --rm -p 8080:8080 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: morgankryze/cairn:latest
    ports:
      - 8080:8080
    volumes:
      - ./config:/config:ro
docker compose up -d

Open http://localhost:8080: that is a finished page.

No server to keep running? Add url: https://tools.example.org to a config/site.yaml, and the same config exports as static files for Cloudflare Pages, Netlify or any Apache host, OVH shared hosting included:

docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/work" \
  morgankryze/cairn:stable -config /work/config -export /work/site.zip

The status pills stay behind, since nothing polls. The rest, and a pipeline that exports on every push, is in Static hosting.

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/. Each page teaches the why before the how. Start anywhere.

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 · Static hosting · Reverse proxies
Recipes Status page · Icons · Multiple files · Migration
Look up Reference · FAQ · Comparison

For your AI assistant

Those pages are indexed on Context7, so an assistant with the Context7 MCP server can pull cairn's real documentation instead of inventing config keys that never existed. Ask it for morgankryze/cairn by name.

Scope

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.

Contributing

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

Contributors

Following the all-contributors convention, which counts every kind of contribution rather than only the commits: an issue that names a real problem, a bug report with the screenshot that cracks it, and a translation are all work.


MorganKryze

💻 📖 🎨 🤔 🚧

AntonPalmqvist

🐛 🤔 🌍

rbourgeat

💻 🤔

💻 code · 📖 documentation · 🌍 translation · 🎨 design · 🤔 ideas · 🐛 bug reports · 🚧 maintenance

The avatars come from GitHub itself rather than from a third-party image service, for the reason the coverage badge is self-hosted: nothing about this repository should depend on somebody else's uptime to render. Adding yourself here is part of a pull request, not an afterthought.

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.

About

The directory page for the people you host services for: no account, multilingual, live status, one tiny container.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

88 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages