git push deploys for SQLite apps, on your own server.
litehouse turns a $5 VPS into a push-to-deploy host: HTTPS subdomains, nightly S3 backups, and a one-command restore onto a fresh machine. GitHub Actions does the builds. Your server just runs things.
Install on a Linux host with wildcard DNS pointed at it:
curl -fsSL https://raw.githubusercontent.com/danbruder/litehouse/main/install.sh \
| sudo sh -s -- --domain lh.example.com$ lh create myapp --repo you/myapp App 'myapp' created URL: https://myapp.lh.example.com Repo: you/myapp git push to deploy. $ git push … GitHub Actions builds the image, pushes to ghcr.io, calls your server $ lh deploys myapp --wait Deploy 1 succeeded $ curl -sI https://myapp.lh.example.com | head -1 HTTP/2 200
The whole workflow
Four commands, then just git push.
-
01
install.sh --domain lh.example.comSets up Caddy and the litehouse server container on your VPS. Prints an admin token once.
-
02
lh connect https://admin.lh.example.com --token …Points the CLI on your laptop at the server. That's all the auth setup there is.
-
03
lh create myapp --repo you/myappRegisters the app, commits a GitHub Actions workflow to your repo, and sets the deploy secret. You don't write any CI YAML.
-
04
git pushActions builds the image and pushes it to GHCR. The server pulls it, swaps the container, and your app is live at
myapp.lh.example.com.
Your repo needs a Dockerfile that listens on a port. That's the only requirement for the app itself.
What you get
The parts of a PaaS you actually use.
Push to deploy
GitHub Actions builds; the server pulls from GHCR and replaces the container. The server never runs docker build, so a 1 GB box is enough.
HTTPS subdomains
Caddy with Let's Encrypt. Every app gets {app}.{your-domain}. Add your own domains with lh domain add.
Nightly backups to S3
Consistent SQLite snapshots via VACUUM INTO, plus the server's own state. 14 days retained. Any S3-compatible bucket.
Incremental file backups
Write uploads to $LITEHOUSE_BLOB_PATH. Each file goes to S3 once and is never re-sent.
Restore onto a fresh box
Install, connect, lh restore --yes. Apps, env vars, deploy tokens, and data come back from S3 and GHCR.
Env, logs, lifecycle
lh env, lh logs -f, start / stop / restart. Health checks per app.
A small admin UI
Apps, deploy history, logs, metrics, backups. Served from the same binary, behind the same admin token.
An MCP server
lh mcp serve exposes deploys, logs, env, domains, and backups as tools for Claude Code or any MCP client.
Backups & recovery
Assume the server dies.
Nothing on the box is precious. Every night litehouse snapshots each app's SQLite data and its own state database to your S3 bucket. If the machine is gone, start a new one and run three commands.
# on a brand-new server $ lh install --domain lh.example.com \ --s3-bucket … --ghcr-token … # from your laptop $ lh connect https://admin.lh.example.com --token … $ lh restore --yes # state DB, images, volumes, blobs: back.
- A backup only counts if every app backed up. One failure and the day isn't marked good.
lh backup status --jsontells you the last good date. - The full cycle is tested. Wipe, reinstall, and restore is an automated script (
e2e/dr-drill.sh) that runs against a real droplet. - Plain files in your bucket. Backups are
tar.gzarchives of SQLite files. You can get your data back without litehouse. - A failed deploy doesn't take you down. If the new image can't be pulled, the old container keeps running.
For agents
Hand the deploy to your agent.
Claude Code, Codex, Cursor, anything that can run a shell. You do the one step that involves a secret; the agent does the rest and proves it worked.
-
01 You, once. Keeps the admin token out of the agent's transcript.
curl -fsSL https://raw.githubusercontent.com/danbruder/litehouse/main/install-cli.sh | sh lh connect https://admin.lh.example.com --token <ADMIN_TOKEN> -
02 Paste into your agent, from the app's repo.
Deploy this repo to my litehouse server. 1. Run `lh agent-guide` and follow it exactly. 2. Pick an app name (lowercase letters, digits, hyphens) and make the app deployable: a Dockerfile at the repo root, listening on 0.0.0.0 with the port EXPOSEd, and the SQLite database and any other persistent files under /data. 3. Run `lh doctor --app <name>` and fix every FAIL. If the server connection or my GitHub token is the problem, stop and tell me what to run. Don't ask me for tokens. 4. Create the app, push, and confirm with `lh deploys <name> --wait --sha HEAD`. If it fails, read the build log or `lh logs`, fix it, and push again. 5. When it's live, give me the URL. -
03 Optional: give it the MCP server too.
claude mcp add litehouse -- lh mcp serve
Cloud agents and CI: skip step 1 and set LITEHOUSE_URL and LITEHOUSE_TOKEN as secrets instead.
$ lh doctor --app myapp [ok ] server litehouse 0.3.0 at https://admin.lh.example.com/api, … [FAIL] github token for you is missing scope(s): workflow fix: `gh auth refresh -h github.com -s workflow` [ok ] git_repo origin is github.com/you/myapp [ok ] dockerfile Dockerfile at the repo root [ok ] port HTTPS traffic will go to port 8080 (lowest EXPOSEd TCP port) $ git push $ lh deploys myapp --wait --sha HEAD … GitHub Actions run for 4be91c02d1 failed (failure), so no deploy was registered. Build log: https://github.com/you/myapp/actions/runs/… $ echo $? 1
lh agent-guideThe whole contract (Dockerfile, port,/data, deploy steps, what each failure means), built into the CLI so it always matches the version installed. Also served as llms.txt and the MCPagent_guidetool.lh doctorChecks every prerequisite in one go (server, token scopes, GitHub origin, Dockerfile, port), and every failure comes with the command that fixes it.--wait --sha HEADConfirms that this commit is live, not the previous deploy. Exit 0 live, 1 failed, 2 timed out. A failed GitHub build is reported the moment it fails.- Everything is non-interactive.
--jsonon read commands, exit codes that mean something, and nothing that waits for a keypress.
Cost
The price of a VPS.
No per-app, per-seat, or per-request pricing, because there's nobody to pay. The tenth app costs the same as the first.
Fit
When not to use litehouse.
It's narrow on purpose. If any of these are true, pick something else.
- You need Postgres or MySQL.It's built around SQLite on local disk. A managed PaaS will serve you better.
- You need more than one server.Single host by design. No clustering, no horizontal scaling.
- You want scale-to-zero.Apps are always on. That means no cold starts, but also no savings when idle.
- You don't want to own a server.You'll need a VPS, a domain with wildcard DNS, an S3 bucket, and a GitHub repo.
- Deploys can't have a gap.A deploy replaces the container. Caddy retries during the swap, but it isn't blue/green.
- You don't have a Dockerfile.Framework auto-detection isn't supported yet.
Architecture
What's running, and where.
Builds happen on GitHub. Your server pulls images and runs them. Server state is itself a SQLite database, and it's backed up too. Written in Rust, shipped as one binary.
Compared
Where it sits.
| litehouse | Hosted PaaS | Self-hosted PaaS | |
|---|---|---|---|
| Examples | — | Vercel, Render, Railway | Coolify, Dokku, Kamal |
| Runs on | Your VPS | Their cloud | Your VPS |
| Pricing | Flat VPS cost | Metered usage | Flat VPS cost |
| Database | SQLite on local disk | Managed Postgres, billed separately | Bring your own |
| Backups + restore | Built in, restore tested end to end | Varies; usually database only | Plugins or DIY |
| Builds run on | GitHub Actions | Their builders | Usually your server |
| Scope | SQLite apps, one box | Almost anything | Almost anything |
If you need Postgres or several servers, Coolify and Kamal are good tools. litehouse does less, deliberately.
FAQ
Questions.
Does it work with any language?
Anything with a Dockerfile that listens on a port. Rails, Django, Go, Node, Rust, Phoenix, a static site.
Where does my SQLite file live?
In a Docker volume on the host, mounted at /data inside your container. Put your database there and it gets backed up. Put large uploads in $LITEHOUSE_BLOB_PATH for incremental backup.
What happens during a deploy?
The server pulls the new image, replaces the container, and updates Caddy. If the pull fails, the old container keeps running. Caddy retries requests during the swap, so the gap is short, but it's not a blue/green system.
Can I deploy without GitHub Actions?
Yes. lh deploy myapp --image <ref> deploys any image directly, using the same code path as the deploy hook. The generated workflow is the default, not the only way.
Private repos and images?
Yes. Give the server a GHCR read token with lh config ghcr set --token … (or pass --ghcr-token at install).
Why do my apps restart at night?
Every running app gets a fresh container once a night at 3am US Eastern: same image, clean process. Opt out per app with lh env <app> LITEHOUSE_SKIP_NIGHTLY_RESTART true.
Does it run on ARM?
Yes. x86_64 and aarch64 servers are both supported: Hetzner CAX, AWS Graviton, Oracle Ampere. lh create generates a workflow that builds your app's image for whatever CPU the server has, and a deploy refuses an image built for the wrong one instead of crashing your app.
How do I upgrade litehouse?
lh upgrade. It pulls the new binary and server image and restarts the server container. Your apps keep running.
Is it production-ready?
It runs real apps for its author, and the install and disaster-recovery flows are tested end to end against real servers. It's also young and maintained by one person. The backups are there so that mistakes (yours or ours) are recoverable.
One box. git push. Backed up every night.
curl -fsSL https://raw.githubusercontent.com/danbruder/litehouse/main/install.sh \
| sudo sh -s -- --domain lh.example.com