Roman 打造類似 tmux、可由 AI Agent 操作的自託管部署工具 deploy.me
I built a self-hosted deploy tool that looks like tmux (and can be driven by an AI agent)
Roman 打造並以 MIT 授權發布自託管部署工具 deploy.me,讓用戶在本機透過 SSH、rsync 和 Docker Compose 部署伺服器上的項目。
I deploy a handful of projects to a handful of my own servers. Not enough to justify Kubernetes, too many to keep doing ssh, git pull, docker compose up -d and hoping. I didn't want a PaaS, a cloud control plane, or an agent running on every server.
So I built deploy.me: a local, Dockerized admin app. You run it on your own laptop (macOS, Linux, or Windows with WSL2) at https://deployme.localhost. It reads your servers from ~/.ssh/config, imports your projects from GitHub or a local folder, and deploys with nothing on the other end but ssh, rsync and docker compose.
It's MIT licensed, and I built it together with Claude. Here's what I think is worth telling about.
What a deploy does
A deploy is a pipeline of recorded steps, each with its own log:
- Pre-flight: is the server reachable, is the folder locked by another run, is another Compose project already running from it?
- Deliver: an ordered list of strategies (GHCR image for the commit, push an archive, rsync, or let the server fetch from git). The first one that applies wins, and the trace tells you why.
-
Release:
releases/<timestamp>hard-linked against the live one, shared folders and env files symlinked in, then an atomic switch ofcurrent. -
Docker Compose:
compose configfirst, so a broken file stops the deploy before anything is built. Then build or pull,pg_dump, migrations in a one-off container, andup -d. - Health gate: the services are healthy, the health URL answers, and your own command succeeds.
If the gate fails after the switch, it switches back by itself. With blue/green on, the edge-facing services start beside the running ones, and the old ones are removed only once the new colour is healthy, so a bad deploy costs no downtime.
The UI is a tmux session
Early on I asked for a redesign, and ended up with something more committed than a dark mode: the whole app can be a tmux session. Panes you split with Ctrl+b % and Ctrl+b ", a status bar with windows 0:ops 1:runs 2:servers…, F1–F6 to jump between them, and a shell pane where the real work happens:
deploy@local:~$ status
TARGET LIVE HEALTH LAST RUN
● atelier@edge-fra 94115db ||||XX||||||||| #19 ✓
● warehouse@edge-fra 9fabf06 |||||||||||||||| #20 ✓
4 targets · 0 running · 0 failing
deploy@local:~$ deploy warehouse edge-fra
deploy is a small wizard: pick the commit, see the plan (what changes, which strategy and why, whether a commit brings a migration), then it asks y/N. A flag is never taken as the yes. It's a theme, not a fork: the same Livewire components sit behind a Classic UI with cards and tables, and you switch in Settings.
The first page loads the frame and the shell immediately; the panes that need data (tail, htop, git) load right after, each in its own request.
Letting an AI agent in, carefully
php artisan deployme:mcp is an MCP server over stdio. Point Claude, Cursor or VS Code at it and the agent can look around, explain why a run failed, and plan a deploy. It's read-only by default. The tools that change anything (deploy, roll back, cancel) appear only with --allow-deploys, and your MCP client asks you before each call. Answers never carry a token, an env file's contents, or the APP_KEY.
Security decisions I'd make again
- Secrets never go in argv or logs. Remote scripts get them over stdin, and every log line is redacted before it is stored or broadcast.
- Passkey or password sign-in, one account. Revealing an env file, trusting a new host key, or changing where alerts go asks for a fresh confirmation.
- Host keys are trusted on first use and then pinned.
-
An append-only audit log. A database trigger refuses
UPDATE, andDELETEonly inside the nightly prune. Every remote command is in it. - A server you can't reach directly goes through a jump host, a SOCKS5/HTTP proxy or your VPN, and that route is checked before every probe and deploy.
Building it with an agent
A good part of this was written with Claude Code, and the most useful thing I did was not asking for features. I pointed an agent at the codebase with one rule: every suspected bug needs a failing test before it gets a fix. It came back with dozens of fixed bugs, each one proven: a deploy that could run in two workers at once, secrets leaking into a failed step's error text, a health alert that fired on every check instead of on change. A rule that makes the agent show its work turned out to matter more than which model was running.
Try it
curl -fsSL https://raw.githubusercontent.com/KielD-01/deploy.me/main/install.sh | bash
That clones the repo, configures it for your OS, builds, and prints a one-time link to set up a passkey or password. The PHP base image is prebuilt for amd64 and arm64 on Docker Hub, so the first build takes minutes, not a coffee break. bin/update keeps it current (backup, rebuild, doctor, and back out if it fails), and can do the patch releases by itself at night if you switch that on.
- Repo: https://github.com/KielD-01/deploy.me
- Screenshots: https://github.com/KielD-01/deploy.me/blob/main/docs/gallery.md
- MCP guide: https://github.com/KielD-01/deploy.me/blob/main/docs/mcp.md
I'd like to hear what's missing for the way you deploy. Issues and PRs are welcome.
來源:DEV Community · dev.to

