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 | bash
Read source
›
渋み  ship
1 commit ready to push
test passed
check passed
Built and uploaded a1b2c3d (3 MiB, 9f2c41ab08e3)
Deployment complete
Shipped in 11 seconds (--rollback if needed)https://example.com

VPS deployment only

A small Linux server will do.

Connect over SSH. Caddy handles public traffic while each app listens on loopback.

2 imagesmaximum per app
12 hoursrollback retention
4 GiBdefault free-space floor
Example image storage by workload
WorkloadCurrentWith rollbackImage contents
Static site~6.2 MB~12.4 MBBusyBox and built site files. About 3 MB compressed.
Small Bun service~80–150 MB~160–300 MBBun Alpine, production packages, and app source.
Full-stack app~200–350 MB~400–700 MBRuntime, 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
Starter VPS comparison
ProviderStarter planvCPURAMDiskFrom / month
netcupGermanyVPS nano G11s22 GB60 GB€3.08
OVHcloudFrance + globalVPS-124 GB40 GB$4.54
ScalewayFranceDEV1-S22 GB20 GB€6.34
VultrGlobalCloud Compute11 GB25 GB$5
Akamai LinodeGlobalNanode11 GB25 GB$5
DigitalOceanGlobalBasic Droplet11 GiB25 GiB$6
IONOSEurope + USVPS XS11 GB10 GB$2
one.comEurope · intro priceCloud server S24 GB100 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.

›
渋み  ship
SSH target (user@server or alias) [email protected]
Save [email protected] locally and connect? Yes
Saved in ~/.config/shibumi on this computer · never committed
App domain myapp.com
Continue through SSH? Yes
Where should the app live? /home/user/shibumi/myapp.com
Found myapp.com on example-vps.com
Wrote shibumi-server.json
Committed Shibumi deployment setup
Next: bun ship
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.

  1. Free disk and memory floors: 4 GiB and 512 MiB.
  2. Image labels checked against the registered repository, branch, and pushed commit.
  3. Compose config validated.
  4. Optional app tests run inside the image.
  5. 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.