Self-hosted deploys
Ship,
done.
Build on your computer. Run that exact image on your VPS.
VPS deployment only (for now).
curl -fsSL https://server.shibumistack.dev/install | bashVPS deployment only
A small Linux server will do.
Connect over SSH. Caddy handles public traffic while each app listens on loopback.
| Workload | Current | With rollback | Image contents |
|---|---|---|---|
| Static site | ~6.2 MB | ~12.4 MB | BusyBox and built site files. About 3 MB compressed. |
| Small Bun service | ~80–150 MB | ~160–300 MB | Bun Alpine, production packages, and app source. |
| Full-stack app | ~200–350 MB | ~400–700 MB | Runtime, packages, built assets, and migrations. |
Estimates include the current image and one similar rollback image. Shared layers may use less space. Leave room for the operating system, logs, databases, uploads, and the 4 GiB deployment floor.
Compare starter VPS optionsPrices vary by region, tax, and architecture
| Provider | Starter plan | vCPU | RAM | Disk | From / month |
|---|---|---|---|---|---|
| HetznerRecommendedEurope first | CX23 | 2 | 4 GB | 40 GB | €3.49 |
| netcupGermany | VPS nano G11s | 2 | 2 GB | 60 GB | €3.08 |
| OVHcloudFrance + global | VPS-1 | 2 | 4 GB | 40 GB | $4.54 |
| ScalewayFrance | DEV1-S | 2 | 2 GB | 20 GB | €6.34 |
| VultrGlobal | Cloud Compute | 1 | 1 GB | 25 GB | $5 |
| Akamai LinodeGlobal | Nanode | 1 | 1 GB | 25 GB | $5 |
| DigitalOceanGlobal | Basic Droplet | 1 | 1 GiB | 25 GiB | $6 |
| IONOSEurope + US | VPS XS | 1 | 1 GB | 10 GB | $2 |
| one.comEurope · intro price | Cloud server S | 2 | 4 GB | 100 GB | $4.99 |
Hetzner's entry plan has room for several small apps. A 1 GB server can run a light prebuilt service, but check its memory use first. Prices vary by location, tax, processor, and billing. Check the final price before ordering.
How it works
A deploy, from start to finish.
You work on your app, and when you're ready, you commit. That's it. bun ship takes it from there.
The first run sets itself up. It asks for user@server-ip (have your public key on the server, and sudo rights to reload Caddy), suggests where the app should live, registers the domain and branch, and writes any deploy files your repo is missing.
From then on, bun ship runs your tests, builds the container on your own machine, and sends it over. The server checks the image against the commit you pushed, plus config and health, before it replaces the running container. A static site image is about 3 MB, so the whole thing takes seconds.
Anything wrong? bun ship --rollback. The previous image sticks around for 12 hours.
More technical detailsWhat happens during replacement, and what lives on disk
What it assumes. Your public key is already in ~/.ssh/authorized_keys on the server, and your user can sudo. Nothing else is required. Shibumi rides the SSH access you already have and never asks for, stores, or transmits a password or private key. The installer checks for Bun, Git, rootless Podman, Caddy, and systemd, and offers to install whatever is missing.
There is no registry. The image never touches Docker Hub or GHCR. bun ship streams it over the same SSH connection you already trust, tagged with the commit it was built from. The upload happens before the Git push, so the server can compare the two and refuse a mismatch.
What runs on the box. Rootless Podman runs the containers, systemd keeps them alive across reboots, and Caddy terminates TLS and proxies each domain to an app that listens on loopback only. From the internet, the machine exposes Caddy and SSH. That's the whole surface.
The cutover, in order. Fail any step and the deploy stops with the old container still serving.
- Free disk and memory floors: 4 GiB and 512 MiB.
- Image labels checked against the registered repository, branch, and pushed commit.
- Compose config validated.
- Optional app tests run inside the image.
- The health endpoint has to answer.
During the swap. Caddy retries the loopback upstream for up to 20 seconds while containers trade places. If the new one starts fast, nobody notices. If startup or health fails, the previous image comes back automatically.
Rollback mechanics. Two tags per app: runtime/<app>:current and one rollback that survives service restarts and expires after 12 hours. bun ship --rollback swaps back without fetching or rebuilding anything.
What lives where. Your SSH target sits in ~/.config/shibumi/config.json, mode 0600, on your machine. Webhook secrets and filesystem paths stay on the server. The only deploy file in your repo is shibumi-server.json, and everything in it is safe to publish.
{
"version": 1,
"provider": "shibumi-server",
"server": { "hostname": "example-vps.com" },
"domain": "myapp.com",
"appId": "myapp-com",
"repository": "github:you/myapp",
"branch": "main",
"webhookUrl": "https://myapp.com/hooks/github/myapp-com",
"service": "app",
"port": 9001,
"healthPath": "/healthz",
"deploymentMode": "prebuilt",
"platform": "linux/arm64",
"cutoverRequired": false,
"trigger": "ship"
}
Linux server
Install shis*.
* shis = shibumi-server.
You need Bun, Git, rootless Podman, Caddy, and systemd. The installer checks each one and helps with anything missing. Updates keep your settings and secrets.
curl -fsSL https://server.shibumistack.dev/install | bash
Next, connect a project with Shibumi Ship. Server operators can register one directly with shis add example.com.
