Most of what people call “moving to the cloud” is really “moving to someone else’s convenience layer,” and the pattern repeats across every category of software you touch daily: the terminal session lives on a hosted dev box you rent by the hour, the inbox lives in a web UI where the provider reads the same screen you do, and in both cases the trade was never negotiated, it just happened one default at a time, because the alternative used to mean running your own server and that phrase has been scaring people off since the first shared hosting ad. The strange part, the part worth writing about, is that the server work stopped being the hard part years ago, and what actually keeps people on the hosted version now is a pile of small papercuts, the missing right-click, the awkward mobile client, the one feature the local tool never quite had, so the way you take a piece of your digital life back is not a migration plan, it is finding those papercuts and deleting them one at a time.
The terminal was already self-hosted; it just needed a door
We wrote the full Tailshell story back in July, so the short version here: screen has kept terminal sessions alive across disconnects since 1987, tmux has done the same job since 2007, ttyd serves one over a WebSocket with a proper xterm.js front end, and the only thing missing between “a terminal on my own hardware” and “a terminal I can open from a phone at the airport” was a front door with real authentication, so Tailshell wraps the pair with JWT sessions, TOTP for admins, workspaces that keep the build box and the media server in separate rooms, and a home on a Tailscale tailnet where strangers’ packets never get an answer at all. The point that belongs in this post rather than that one is what the design says about self-hosting in general: nothing in that stack was invented, it was assembled from a terminal multiplexer with nearly two decades behind it and a WebSocket bridge with one of its own, and the new code is a thin, auditable layer that decides who gets a shell, which is exactly the shape a self-hosted tool should have when the alternative is renting the same capability from someone whose business model is watching what you type.
The papercut it removed, the one that actually changed behavior, was quick prompts, because the honest reason long-running builds got checked “when I get home” instead of from the couch was that nobody wants to type a forty-character incantation on a touchscreen, and one saved button per recurring command turned the whole setup from a principled stance into the path of least resistance, which is the only kind of self-hosting that survives contact with a tired Tuesday.
The inbox’s papercut was a right-click
Email is the category where self-hosting got an undeserved reputation, because running a mail server genuinely is a knife fight with spam reputation and deliverability, but reading your mail in a local client against any IMAP provider is the opposite of hard, it is how everyone did it for twenty years, and the thing that quietly pushes people back to the web UI is not protocol difficulty, it is that the local client is missing two or three small comforts the web version trained them to expect. Mailspring is our pick for the local client, a desktop mail app that keeps its working set in a local database on your machine rather than in a tab that phones home on every keystroke, and when we daily-drove it, the papercut we hit within the first week was embarrassingly small: Edit > Mark All as Read exists, but it only touches the unread threads loaded in the visible list, so an inbox with a few hundred unread items past the scroll window stays unread forever, and the workaround of scrolling to load more and repeating the menu item is the kind of friction that ends with someone opening the webmail tab “just this once” and never coming back.
So we wrote the fix, a tiny Mailspring plugin that adds Mark All as Read to the right-click menu of any inbox in the account sidebar, including the unified inbox and the per-account ones nested under it, and the interesting part for a post about self-hosting is how small the whole thing is: no npm dependencies, no build step, one DOM-level hook on the sidebar tree that only intercepts recognized inbox rows and leaves every other menu alone, with the actual work delegated to Mailspring’s own ChangeUnreadTask so read state flows back to the server through the client’s normal sync path rather than through anything we invented. It lives at visorcraft/mailspring_inbox_rightclick, it is tested against Mailspring 1.21.0, and installing it is copying one folder into Mailspring’s packages directory and restarting the app:
Linux: ~/.config/Mailspring/packages/inbox-mark-all-read-context-menu
macOS: ~/Library/Application Support/Mailspring/packages/inbox-mark-all-read-context-menu
One folder, one restart, and the local client now does the thing the web UI did, which is the entire pattern in miniature: the gap between hosted and self-hosted is almost never a capability, it is an accumulation of unpatched smallness, and smallness is cheap to fix once you notice it.
Why two unrelated tools are one argument
A web terminal and a mail plugin do not share a codebase, a language, or a user story, and yet they are the same move, because both take a daily workflow that defaulted to someone else’s server and bring it back to hardware you control without asking you to give up the convenience that made the hosted version sticky in the first place. Tailshell keeps the terminal on your machine and makes reaching it from anywhere a solved problem rather than a port-forwarding prayer; the Mailspring plugin keeps mail in a local database and removes the one missing gesture that made webmail feel inevitable, and in both cases the work was a thin layer over mature primitives, tmux and ttyd in one case, IMAP and Mailspring’s own task system in the other, because mature primitives are what make the self-hosted version cheaper to own than the subscription.
The honest tradeoff is the one we keep stating because it never changes: nobody is going to push a fix to your tools at 2 a.m., the tailnet is yours to maintain, the plugin is yours to reinstall when Mailspring updates, and the bill for owning your workflows is paid in occasional maintenance rather than in monthly rent and ambient surveillance. We ran our own mail servers in 2003 because keeping your own data on your own box was ordinary practice rather than a political position, and the modern equivalent is gentler, one container behind Tailscale, one local mail client with a right-click menu that finally works, and the discovery that the cloud’s real lock-in was never the technology, it was a hundred papercuts nobody had bothered to bandage, and bandaging them turns out to be a pleasant way to spend a weekend.
