Deploy Node apps to your own server.
No dependencies.
Set up a server once. Then launch each app with one command, and every push that passes CI deploys it.
npm install -g modest-deploy
$ modest-deploy launch blog blog.example.org --server myserver
Made the repository example/blog.
Added blog on myserver.
Gave GitHub the read-only deploy key, and the webhook.
$ git push
blog: running 3f2a9c1
Signed · main · CI passed · answered
- 0runtime dependencies
- ~2,450lines of source
- 1command per app
- 7nights of database copies
Approach
No server key in GitHub
Deploying from CI usually means the workflow signs in to the server over SSH, so the key is stored in GitHub. With modest-deploy, GitHub only sends a signed message when CI passes. The server checks it, then fetches and builds the code itself.
Deploying over SSH from CI
- A key to the server is stored in GitHub
- The workflow runs commands on the server
- Often a container registry as well
modest-deploy
- No key to the server is stored in GitHub
- The server decides what runs
- Uses Node, git, systemd, and Caddy
Deploying
What happens when you push
When CI passes on main:
- GitHub sends a signed messageSigned with a secret that only the server and GitHub have.
- The server checks itIt has to be signed, from the app's own repository, for a CI run on main that passed. Anything else is ignored.
- It fetches and buildsOnly the newest commit on main, with the app's own read-only key. Dependencies come from the lockfile, with install scripts off.
- It switches overIf the new version doesn't respond, the previous one is restored.
Features
What it does
One command to launch
Creates the GitHub repository, sets the app up on the server with its domain and HTTPS certificate, and connects the two.
Signed deploys
Only the newest commit on main is deployed, so an old message sent again can't roll an app back.
A user per app
Each app runs as its own user in a systemd sandbox. It can read its own code and write only to its own data folder.
Rollback
If a new version doesn't respond, the previous one is restored.
Nightly backups
Each app's SQLite databases are copied every night with SQLite's backup API, and kept for 7 nights.
Server checks
Before installing, it checks the SSH settings, automatic updates, and open ports, and tells you what to change.
$ sh test/e2e/run.sh
== a stand-in GitHub that isn't GitHub is refused
ok: nothing deployed: GitHub's real host keys are pinned
== a signed message for a passed CI run deploys
ok: club v1 is running, with modest-auth installed from npm
== each app is sandboxed
ok: it can write its own data, and nothing else
== a version that doesn't start is switched back
ok: v2 is running again
End to end: every step passed.
Compatibility
Runs on Ubuntu with systemd and Caddy
Node 26 (24 or later works).
- Ubuntu 26.04 LTS
- systemd
- Caddy
- Node 26
- GitHub
Getting started
npm install -g modest-deploy
This is an early release, and it hasn't had an independent security review yet.