Almost every self-hosted deployment tool - Coolify, Portainer, Dokploy, CapRover, the list goes on - works the same way architecturally: you install a dashboard on your server, and that dashboard is how you manage the server. It's a reasonable default, and I don't think the people who built those tools made a mistake. But there's a structural problem with it that only shows up at exactly the moment you need the tool most.
The failure mode this creates
Your server is having a bad day - disk filling up, a runaway process eating memory, network flaking. This is precisely when you want to open your dashboard, check logs, and figure out what's wrong. And it's precisely when a dashboard running on that same struggling server is least likely to respond quickly, or at all.
I don't think this is a hypothetical edge case. It's the single most common moment anyone actually needs a deployment tool for real - not the happy path of "click deploy, it works," but "something's wrong, help me see why." An on-server dashboard is structurally weakest exactly when it's needed most.
Why "just add more resources" doesn't fully fix it
You can over-provision to make this less likely. But the dashboard is still consuming CPU and memory 24/7, on every server, whether anything's wrong or not - it has to, since it's a persistent service listening for webhooks and keeping its own state current. That's resource spent on infrastructure management instead of on the apps you're actually trying to run, on every single box, all the time.
And there's a second cost that's easy to miss: the dashboard is now part of your server's attack surface, permanently. Whatever process is listening for inbound requests to that dashboard is a thing that has to be patched, secured, and kept running correctly, forever, on every server you manage. More surface area, indefinitely.
The alternative: the control plane runs somewhere else
DeployOS's answer is to not put the dashboard on the server at all. It's a native app on your Mac or PC that talks to your servers over plain SSH when you ask it to do something, and closes the connection when it's done. Your server runs your apps and a reverse proxy. Nothing else.
The direct consequence: when a server is struggling, the tool I use to diagnose it isn't struggling with it. App Doctor - the 9-step diagnostic DeployOS runs when something's wrong - executes from my laptop, over SSH, and doesn't care whether the server has spare resources to spend on a dashboard, because there isn't one there to spend them on.
The honest tradeoff
This isn't free. A local control plane means:
- No inbound webhooks. GitHub can't push a "deploy now" signal to a server with nothing listening. DeployOS polls instead, on an interval, and only while the app is open.
- The app has to be running for auto-deploy to fire. Close your laptop, auto-deploy pauses. A server-resident dashboard doesn't have this limitation - it's always there.
- You're trusting a desktop app with your credentials instead of a server-side one. They're stored differently (OS keychain vs. wherever the dashboard keeps them), but it's still a real design choice, not a strictly-better one.
I think that trade is worth making for most people running their own infrastructure, especially once AI assistants are in the loop and you want every action logged and confirmed from somewhere that isn't the thing being acted on. But it is a trade, not a free upgrade, and anyone telling you otherwise about their own architecture is skipping the part of the conversation that actually matters.