ONCE by 37signals: Self-Hosting Without the DevOps Tax

ONCE by 37signals: Self-Hosting Without the DevOps Tax

Every month, the SaaS invoice pile grows a little taller. Slack, Notion, Linear, Loom — individually reasonable, collectively brutal. At some point the math flips: you're paying recurring fees for tools your team could run on a $10 VPS with a bit of infrastructure elbow grease.

37signals — the company behind Basecamp, HEY, and Ruby on Rails itself — has been making this argument for years. Their latest move is ONCE: a self-hosting platform launched on April 17th, built around a single Go binary that turns any Linux or macOS machine into a Docker application host. No Kubernetes. No Helm charts. No three-day onboarding into your own infrastructure.

This article breaks down how ONCE works, where it fits architecturally, and whether it's worth your attention as a senior engineer.


What ONCE Actually Is

At its core, ONCE is a CLI + TUI tool written in Go that orchestrates Docker-based web applications. It ships under the MIT license and handles the full lifecycle: installation, configuration, updates, backups, and monitoring.

Install is a one-liner:

curl https://get.once.com | sh

The script detects your platform, installs Docker if absent, drops the binary, registers a background service, and launches an interactive TUI that walks you through your first app install. For scripted environments:

curl https://get.once.com | ONCE_INTERACTIVE=false sh

Under the hood, ONCE delegates HTTP routing and zero-downtime deploys to Kamal Proxy — 37signals' own reverse proxy, already battle-tested in their Kamal deployment toolchain. That's a meaningful architectural choice: ONCE isn't reinventing the proxy layer, it's composing known pieces.

Three apps ship built-in: Campfire (team chat, open-sourced in August 2024), Writebook (docs/ebooks), and Fizzy (kanban, under the custom "O'Saasy" license which prohibits SaaS competition but is otherwise open). Enough to replace Slack, Notion, and Trello for a small team — if that's the goal.


The App Contract

ONCE imposes a minimal but strict contract for compatible applications. Your Docker image must:

  • Serve HTTP on port 80
  • Expose a healthcheck at /up returning 2xx
  • Store all persistent data under /storage

ONCE mounts a persistent volume at /storage (and also at /rails/storage for standard Rails apps — a thoughtful nod to the default Rails Dockerfile). That volume is what gets backed up. Clean, predictable, no surprises.

Beyond the minimum, ONCE supports two optional hook scripts:

/hooks/pre-backup    # called before backup starts
/hooks/post-restore  # called after restore, before boot

pre-backup is particularly well-designed. If the script exists and exits 0, ONCE considers the data safe to copy and proceeds without pausing the container. If it's absent or fails, ONCE pauses the container during the copy — guaranteed consistency either way, but the hook gives you a path to avoid request latency spikes during backup windows.

For a SQLite-backed Rails app, you'd use this to trigger SQLite's online backup API and produce a consistent snapshot without downtime:

#!/bin/bash
# /hooks/pre-backup
sqlite3 /storage/production.sqlite3 ".backup '/storage/backup/production.sqlite3'"

That's a clean, explicit extension point. I prefer this kind of hook-based design over ambient magic.


Environment Variables and Integration Surface

ONCE injects a set of environment variables into running containers. The notable ones:

Variable Purpose
SECRET_KEY_BASE Stable identifier for Rails crypto signing
DISABLE_SSL Set to true when running without TLS
SMTP_* / MAILER_FROM_ADDRESS Populated from the email settings screen
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY Auto-generated for WebPush apps
NUM_CPUS Reflects any CPU quota, useful for worker pool sizing

NUM_CPUS is the one I'd pay most attention to if you're building a compatible app. Sizing Puma workers or Sidekiq concurrency relative to an injected CPU count is exactly the kind of thing that goes wrong when you ignore it and then wonder why your $5 VPS is swapping.


Where ONCE Fits — and Where It Doesn't

ONCE is positioned explicitly against complexity. One binary. One TUI. Three apps. That's a coherent product philosophy, not an oversight.

It makes sense for:
- A solo engineer or small team wanting to repatriate 2–3 SaaS tools
- A homelab setup (VPS, Raspberry Pi, old laptop)
- Standard Rails apps that already follow the Docker + /storage convention

It doesn't make sense for:
- Windows environments (not supported)
- Multi-service Kubernetes setups — the operational model is fundamentally different
- Teams that need granular RBAC, audit logs, or enterprise SSO on the platform layer itself

The honest comparison is against tools like Dokploy or Coolify, which target similar use cases but lean toward broader compatibility and more configuration surface. ONCE trades that breadth for radical simplicity. If the 37signals app ecosystem covers your needs, that trade is worth it. If you need to run 15 heterogeneous services, look elsewhere.

One practical gotcha worth flagging: if you're behind Cloudflare Proxy, set SSL mode to Strict (full) before you start. The default proxied mode will cause redirect loops that are genuinely confusing to debug until you know what you're looking for.


Conclusion

ONCE is a focused tool solving a real problem: the operational overhead of self-hosting is often high enough that teams default to SaaS even when self-hosting would be cheaper and simpler. By collapsing installation, updates, and backups into a single binary with a sensible app contract, ONCE removes most of that friction.

The architecture is sound — Kamal Proxy for routing, hook scripts for backup safety, explicit environment variable injection, Rails-compatible storage paths out of the box. Nothing revolutionary, but everything deliberate.

My take: if you're running Rails apps and have been eyeing self-hosting for the usual tools (chat, docs, light project management), ONCE is worth an afternoon on a spare VPS. The contract it imposes on compatible apps is clean enough that adapting an existing Rails app is minimal work. Keep an eye on the third-party app ecosystem — that's where the platform's long-term value will be determined.

Credits

  • Photo by Ana Benet via Pexels
0
Did you enjoy this article? Give it a like.

Comments (0)

Leave a comment

Your comment will appear after review.

Your name and email are collected solely to identify your comment. Your email is never displayed publicly. Privacy policy.

Related articles