Skip to content
Go back

Sandstorm: Self-Hosted Apps in a Sandbox, Not Just a Container

By SumGuy 11 min read
Sandstorm: Self-Hosted Apps in a Sandbox, Not Just a Container

Your Compose Stack Is Not a Security Model

Let’s be real about what most self-hosted setups look like: a docker-compose.yml, some environment variables with your passwords in plain text, a reverse proxy out front, and the quiet optimism that nothing on your LAN is malicious.

That works fine until it doesn’t. One vulnerable plugin in your wiki, one CVE in an unpatched image, and suddenly everything on that host is reachable. Containers share the kernel. Services share volumes. Your database has a bind mount into /data that three different apps can all see if you wired it wrong. The boundary is soft.

Sandstorm takes a different bet entirely. Instead of asking “how do I isolate the container?”, it asks “what is this app actually allowed to do?” That’s capability-based security, and it changes the threat model in ways that are genuinely interesting — even if Sandstorm itself is a bit of a weird project with an unusual history.

What Sandstorm Actually Is

Sandstorm.io is a self-hosted app platform built around the idea that every document, every wiki page, every Kanban board — each one gets its own grain. A grain is an isolated instance of an app. Not isolated like “it runs in a separate container,” but isolated like “it can only do what you explicitly grant it permission to do via a capability token.”

The security model is built on Linux namespaces and seccomp filtering, but the key idea is the IPC-only grain model: grains can’t reach out to the network arbitrarily. They can’t open a socket to 8.8.8.8. They can’t enumerate the filesystem outside their sandbox. If an app needs to talk to another app — say, a Nextcloud document needs to pull from an external API — that has to be explicitly wired through Sandstorm’s capability system.

In practice this means: if a vulnerability is exploited in your Etherpad grain, the blast radius is that grain. Not your whole server. Not every other app. Not your SSH keys sitting somewhere on the filesystem.

That’s a meaningfully different promise from what a Compose stack gives you.

Grains: One Instance Per Thing

The mental model you need is this: in regular self-hosting, you install Etherpad and it runs one server that hosts all pads for everyone. In Sandstorm, you install the Etherpad package and each pad — each document — is its own grain with its own isolated storage and process space.

This has interesting consequences:

It’s a different UX from what most people expect. If you’re used to “one Nextcloud for the family,” Sandstorm’s model feels weird at first. Each family member gets their own grain of each app. It’s not multi-tenancy — it’s per-user isolation by design.

Installing Sandstorm (It’s Actually Simple)

Sandstorm runs on a single Linux server. This is not a Kubernetes workload. There’s no Helm chart. The recommended install path is still the shell script installer:

Terminal window
curl https://install.sandstorm.io | bash

Or if you want to inspect it first (you should):

Terminal window
curl -fsSL https://install.sandstorm.io -o install.sh
bash install.sh

The installer walks you through a few prompts: port binding, whether to use a domain, whether to enable HTTPS via Let’s Encrypt. After that, Sandstorm is running as a systemd service.

Terminal window
sudo systemctl status sandstorm
sudo sandstorm status

Sandstorm binds to port 80/443 by default and handles its own reverse proxying. You can put Nginx or Caddy in front of it, but it’s not required — Sandstorm uses wildcard subdomains (*.yourserver.example.com) for grain isolation, which is part of how it prevents cross-grain cookie attacks.

Domain Setup Matters More Than Usual

Sandstorm leans heavily on wildcard subdomains for security. Each grain gets served on a random subdomain like random-grain-id.yourserver.example.com. This prevents a malicious grain from stealing cookies from another grain via the same-origin policy.

This means you need:

If you’re testing on a LAN and don’t want to deal with wildcard certs, sandcats.io — Sandstorm’s free dynamic DNS service — gives you a yourname.sandcats.io domain with a wildcard cert. It still works as of 2026.

Installing Apps (Packages)

Sandstorm apps are distributed as .spk files — Sandstorm Package Kit. You install them from the Sandstorm App Market or by uploading an .spk directly.

Terminal window
# From the web UI: Apps → Install from market
# Or upload an .spk file directly via the UI

Apps that still work reliably in 2026:

What you won’t find: modern, actively-maintained versions of most popular apps. The ecosystem froze when Sandstorm Inc shut down in 2017. Most packages are pinned to older versions of their upstream projects. Wekan and Etherpad get occasional updates via community contributors, but don’t expect the bleeding edge.

Creating and Sharing Grains

Once an app is installed, creating a grain is one click from the dashboard. The grain starts, gets assigned an isolated storage directory and a random subdomain, and you’re editing.

Sharing is via capability tokens:

Share → Generate link → Set permissions (viewer / editor / collaborator)

The person you share with gets access only to that grain. Not your whole Sandstorm. Not other grains. Not other apps. Just that document. This is the model Sandstorm was built around, and honestly it works elegantly.

The Fork Story: Sandstorm → Tempest

Here’s the part where you need to understand the project’s current state before committing to it.

Sandstorm Inc shut down in 2017. The project was open-sourced and handed to the community. A small group of contributors kept it alive under the sandstorm-io GitHub org. It works, but development has been slow — mostly security patches and dependency updates.

In the early 2020s, a group of developers forked Sandstorm to create Tempest. Tempest is a ground-up reimplementation of the Sandstorm concept using Cap’n Proto more aggressively and a cleaner architecture. It’s ambitious and technically interesting. It’s also not production-ready as of mid-2026 — it’s actively developed but still rough around the edges.

What this means for you in practice:

There’s no shame in that. Sandstorm is a niche, security-purist platform for people who care deeply about the capability model. It never tried to be mainstream, and the community that maintains it is small but thoughtful.

Sandstorm vs. The New Dashboards (Cosmos / CasaOS / Umbrel)

If you’ve seen our Cosmos vs. CasaOS vs. Umbrel piece, you know the modern “app store for your homelab” platforms are all about making Docker deployment easier. One-click installs, pretty dashboards, automatic reverse proxy setup.

Sandstorm is not competing with those. It’s a different philosophy:

Cosmos / CasaOS / UmbrelSandstorm
App isolationContainer boundaryCapability-gated grain
Shared kernel exploitFull host exposedBlast radius = one grain
App ecosystemHuge (any Docker image)Small (only .spk packages)
User modelShared app instancesPer-user grain instances
Setup complexityLowMedium (wildcard DNS)
ControlYou run whatever image you wantSandstorm controls the sandbox

The right framing: if you want to run 40 different Docker apps with a nice dashboard and don’t want to think much about security boundaries, use Cosmos or CasaOS. If you’re running a small group collaboration setup and you care deeply about what each app can actually do on your server — Sandstorm is worth the friction.

Sandstorm is the “security-purist homelab” choice. You’re trading ecosystem breadth and operational flexibility for a meaningfully stronger isolation model.

When NOT to Use Sandstorm

Honestly? Most of the time.

Here’s the thing: Sandstorm’s model requires that apps be specifically packaged for it. You can’t just grab a random Docker image and run it on Sandstorm. If the app you need hasn’t been packaged — and most apps haven’t been — you’re stuck.

Skip Sandstorm if:

Use Sandstorm if:

The Capability Security Deep Cut

If you want to nerd out on why this model is different, here’s the short version.

Traditional access control is ACL-based: you check a list of who’s allowed to do what. The problem is that ACLs are ambient — an app running as your user can do anything you’re allowed to do. If Nginx has a file read vulnerability and runs as www-data, and www-data has access to /var/www/html/*, that’s the blast radius.

Capability-based security says: instead of checking ambient authority, give the app tokens for exactly what it needs. The Sandstorm grain doesn’t have ambient access to the filesystem. It has a token for its own grain directory. It doesn’t have ambient network access. If it needs to talk to a webhook, you wire that capability explicitly.

This is closer to how seL4 and Fuchsia think about security, and it’s genuinely a more principled model. The reason it never went mainstream is that it requires the app to be designed (or packaged) for it — you can’t retrofit capability security onto an app that assumes ambient access.

Sandstorm did the work of making this practical for a specific set of self-hosted apps. That work is real and it shows, even if the project’s trajectory is uncertain.

Quick Start Recap

Terminal window
# Install Sandstorm
curl https://install.sandstorm.io | bash
# Check status after install
sudo sandstorm status
# Access the admin panel
# https://yourserver.example.com/admin
# Install an app from the market
# Dashboard → Apps → App Market → Install
# Create a grain
# Dashboard → New Grain → choose app

For wildcard DNS, point *.yourdomain.tld at your server IP. Sandstorm handles the rest.


Your 2 AM self might actually appreciate Sandstorm’s model the first time one of your self-hosted apps has a bad day. Instead of “oh no, everything on the server is compromised,” it’s just “one grain got hosed.” Clean up that grain, keep going.

It’s not for everyone. The ecosystem is small and the project is in a strange in-between state with the Tempest fork on the horizon. But if you’ve been running a Compose stack and secretly wondering what “actually isolated” would look like in practice — Sandstorm is worth spinning up on a spare VM to find out.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Next Post
ModSecurity vs Coraza WAF

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts