crat.ch
← All projectsRunning

crat.ch

Proven open-source building blocks — database, auth, commerce, analytics — fused into one coherent, self-hosted platform behind a single Next.js front door.

crat.ch

crat.ch is a personal online-presence platform built the hard way: proven open-source building blocks — a database, a reverse proxy, authentication, commerce, analytics, and the interface itself — assembled into one coherent, self-hosted system that runs as a single machine. No SaaS sprawl, no third-party dashboards holding the data. One box, one front door, everything under one roof.

The public face lives at crat.ch. This project is that homepage and the platform behind it.

The idea

Build from opensource. Fused to work together.

Most "self-hosted setups" are a pile of containers that happen to share a host. crat.ch is the opposite: a deliberately composed fabric where every service knows its place. Next.js is the only public front door — everything a visitor or client touches is rendered and brokered by it. The databases have no public route at all; they sit on an internal Docker network with no host port and no proxy entry. Compromising the edge does not expose the data.

What you can do on it

The app is split into three audiences behind one codebase:

  • Public site — the marketing surface: a content-first landing page, a live Projects record (this page is one of them), a Shop, and a Contact form. Showcase-style, statically generated, fast.
  • Client area — a signed-in dashboard for clients: support tickets, package tracking, and a private file vault with per-user quotas and share links.
  • Admin — a full CMS and control room: projects, users, support, embedded analytics, CRM, commerce, link management, and live container logs.

The stack, fused

ConcernPowered by
Interface / BFFNext.js 15 (App Router) + TypeScript
App databaseSurrealDB
Identity / SSOLogto (OIDC)
CommerceMedusa
CRMTwenty
AnalyticsPlausible (cookieless)
Short linksDub
Object storageMinIO (encrypted)
Shared storesPostgreSQL · Redis · ClickHouse · MySQL
LogsDozzle
Edge / TLSNginx Proxy Manager

Every service is pinned, health-checked, and started in dependency order. The browser never talks to a database directly — Next.js Route Handlers and Server Actions broker every privileged call and hold the secrets server-side.

Files that assume the worst

The file vault is the sharp end of the design. Uploads are envelope-encrypted in the app process with a per-file AES-256-GCM key, wrapped by a master key that never touches the repo — plaintext never lands on disk. MinIO re-encrypts the ciphertext at rest as a second layer. Object keys are random UUIDs decoupled from filenames, so enumerating the bucket reveals nothing. Nothing is reachable by URL without passing the authenticated access layer, and range requests decrypt only the chunks they need — so audio, video, and PDFs stream and seek without ever exposing a storage URL.

Four sharing modes, from locked-down to open: private, anyone-with-link, named users, and link-plus-access-code (codes stored only as argon2id hashes, verification rate-limited).

Design language

Content is the hero; the interface recedes. Editorial, calm, near-monochrome with a single confident accent, generous whitespace, and a pixel-precise mono display face carrying the headings. Motion guides attention rather than decorating it, and it always honors prefers-reduced-motion. Deliberately not the generic AI-template look — no gradient fades, no rounded-everything, no glassmorphism.

crat.ch mascot

Status

Live in production at crat.ch and under active development (v0.4.1). The site, auth, projects CMS, file vault, and this connector API are running; the shop catalogue is on the way.

Links