Waldi: A Multi-Tenant Blogging Platform in Go with Guaranteed Readers
Waldi is a new open-source blogging platform that tackles the distribution problem that killed blogs. Created by a developer who witnessed the decline of the Persian blogosphere, Waldi guarantees every post a floor of readers before any algorithm judges it. The platform is built in Go, uses Postgres, and is designed to be self-hosted or used via the hosted instance at waldi.blog.
Architecture: Single Binary, Multi-Tenant
Waldi's architecture is refreshingly simple. It's a single Go binary that serves all blogs simultaneously, routing requests based on the Host header. In internal/web/server.go, the ServeHTTP method checks if the host maps to a blog (via subdomain or custom domain) and serves the appropriate content. This means no per-tenant deployments—just one process and one Postgres database.
// Simplified from internal/web/server.go
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
host := r.Host
if blog, ok := s.BlogFromHost(host); ok {
// serve blog content
} else {
// serve main app
}
}
Custom domains are supported via a Postgres lookup cached in-process with positive and negative TTLs, avoiding a database hit per request. Session cookies are scoped to the main domain and carry over to username. subdomains, but not to custom domains for security.
Core Loop: Publish, Read, Reply
Waldi's design is built around a simple loop: a writer publishes, a hundred strangers read it, and a follow or a private letter comes back. There are no public like counts, no comments, no leaderboards. Replies are private letters, and every post is guaranteed a floor of readers (default 100 impressions) before any algorithm judges it. This ensures new writers never publish into silence.
The wildcard selection algorithm picks one "wildcard" post per reader each day from a pool of posts that haven't yet reached their impression floor. Currently, the pool is admin-curated via a Telegram bot, with a fallback heuristic that prioritizes posts in the reader's language, excluding the reader's own posts and already-followed authors. A planned scoring system (0.6 × follow-rate + 0.3 × completion-rate + 0.1 × letter-rate, Wilson-adjusted) will automate this as volume grows.
Tech Stack: Go, Postgres, Tiptap, and No Framework
The frontend uses server-rendered HTML templates (html/template) loaded via embed.FS for production. The editor is a Tiptap island (TypeScript), bundled by esbuild into a single editor.js. No JavaScript framework—just a single editor component. The editor's document schema is enforced server-side in internal/post/doc.go, so the server, not the client, validates documents.
// internal/post/doc.go (simplified)
type Doc struct {
Type string `json:"type" validate:"required,eq=doc"`
Content []Node `json:"content" validate:"required,dive"`
}
Postgres is the database, with migrations in migrations/00N_*.sql. Images are uploaded to S3-compatible storage (Cloudflare R2 in production), resized and converted to WebP on upload. Cloudflare edge cache serves anonymous HTML pages with Cache-Control: public, purged on publish via the Cloudflare API.
Self-Hosting and i18n
Waldi is MIT-licensed and comes with a DEPLOY.md for production setup. It uses Caddy for TLS (wildcard cert via Cloudflare DNS challenge, on-demand Let's Encrypt for custom domains). Email is handled via SMTP, with separate From addresses for transactional and bulk digest emails. Background jobs run as CLI subcommands on cron (not a queue): daily digests, wildcard selection, and weekly stats.
Internationalization is built-in. Translation strings live in flat JSON catalogs (e.g., en.json, fa.json), embedded into the binary. Templates are shared across languages; every user-facing string is looked up via T(lang, key, args...). Adding a new language requires only adding a new JSON file and updating the supported map—no template changes.
Why It Matters
For developers who miss the old blogosphere, Waldi offers a concrete alternative to social media platforms that prioritize engagement over writing. The technical design—single binary multi-tenancy, server-side validation, guaranteed distribution—is interesting in itself. It's a reminder that sometimes the best solution is a simple one: a Go binary, Postgres, and a commitment to not building certain features.
Getting Started
To run Waldi locally, clone the repo, copy .env.example, and run:
make db # start Postgres (+ MinIO) via docker compose
make migrate # run migrations
make dev # air (Go live reload) + esbuild --watch
Then visit http://localhost:8080 for the app, or http://USERNAME.localhost:8080 for a blog. Use waldi.test with /etc/hosts entries for testing cross-subdomain cookies.
Editor's Take
I've been watching the blog revival movement for a while—projects like Write.as and Bear Blog—and Waldi stands out for its technical simplicity and its strong opinion on distribution. The guaranteed-reader floor is a genuinely novel idea, and the decision to use server-rendered HTML with a single editor island is refreshing in a world of SPAs. I'm not sure the Telegram admin bot is the right choice for moderation (I'd prefer a web UI), but the architecture is clean enough that adding one wouldn't be hard. If you're a Go developer looking for a well-architected open-source project to learn from or contribute to, this is a good one.

