Skip to content

Self-hosting

vauly runs on your own Cloudflare account. A deploy creates two things:

  • vauly, a Worker that serves the web app and its API
  • vauly, a D1 database for your items, encrypted before they arrive
Your devices
The web appin your browser
The extensionfills and saves logins
vauly runfor agents and scripts

A small team fits in Cloudflare’s free plan.

Deploy to Cloudflare

  1. Click the button, sign in to Cloudflare, and connect GitHub or GitLab. Cloudflare copies vauly into a new repository of yours and builds it from there.
  2. When it asks for SETUP_CODE, choose a code only you know, for example from openssl rand -hex 16. It keeps a fresh vauly from being claimed by whoever finds it first.
  3. Deploy. When it’s done, open your vauly’s address followed by /setup?code= and your code, and create the workspace. You become its owner. Invite your team from Members; each invite link works once, for one email address.

That’s all the setup there is. The Worker applies the database migrations on its first request, and makes the secret that signs sessions on first start, keeping it in the database. Without a SETUP_CODE, whoever opens your vauly first creates the workspace, so don’t leave such a deploy unclaimed.

In your copy of vauly on GitHub, open Actions → Update vauly → Run workflow. It replaces the files with the latest vauly and pushes, and Cloudflare deploys the update. The Worker applies any new migrations on its first request. Check CHANGELOG.md before you update.

The update keeps your wrangler.jsonc, which names your Worker and its database, and the files in .github/workflows, which GitHub’s default token can’t change. To let updates replace the workflows too, add a repository secret named VAULY_UPDATE_TOKEN: a fine-grained token for that repository with read and write access to Contents and Workflows.

You need Bun 1.3 or later.

Terminal window
git clone https://github.com/jotyy/vauly.git
cd vauly
bun install
bunx wrangler login
echo "SETUP_CODE=$(openssl rand -hex 16)" > .dev.vars
bun run build
bun run deploy -- --secrets-file .dev.vars

.dev.vars keeps your setup code; git ignores it. Wrangler prints your vauly’s address, and you claim it the same way, at /setup?code= followed by the code.

To update, run git pull, bun install, bun run build and bun run deploy.

In the Cloudflare dashboard, open the vauly Worker, then Settings → Domains & Routes → Add → Custom domain. The app and the API move together, so there’s nothing else to change. The domain’s DNS has to be on Cloudflare.

Setting What it does
SETUP_CODE Secret. Creating the workspace takes this code until someone has. It no longer matters once the workspace has an owner.
BETTER_AUTH_SECRET Secret, optional. Signs sessions. Without it, vauly makes one and keeps it in the database. Changing it signs everyone out.
VITE_BRANDFETCH_CLIENT_ID Build variable, optional: for a one-click deploy, under the Worker’s Settings → Build → Variables and secrets. Where website logos come from: by default the web app and the extension load them from Brandfetch with the vauly project’s client ID. Use your own Brandfetch client ID, or off to show plain icons and never contact Brandfetch.

Add secrets in the dashboard under the Worker’s Settings → Variables and Secrets, or with bunx wrangler secret put.

  • The database. D1 keeps a point-in-time history you can restore from (Cloudflare calls it Time Travel; how far back depends on your plan). Everything sensitive in it is encrypted, so a database copy is only useful together with your team’s master passwords.
  • Decrypted backups. Any member can download every item they can open from Settings → Download a backup. The file is plain text: store it encrypted.

Delete the vauly Worker and the vauly D1 database in the Cloudflare dashboard, or run bunx wrangler delete and bunx wrangler d1 delete vauly. Deleting the database deletes every item in it, so download backups first.

If the owner is locked out of two-step login

Section titled “If the owner is locked out of two-step login”

An admin can reset two-step login for anyone except the owner. If the owner loses both their phone and their recovery codes, open the instance’s D1 database in the Cloudflare dashboard and run this in its console, with the owner’s email:

UPDATE member SET totp_secret = NULL, totp_pending = NULL, totp_step = NULL, recovery_codes = NULL
WHERE user_id = (SELECT id FROM user WHERE email = 'owner@example.com');

Their master password alone signs them in again. It changes nothing about encryption: the master password is still the only key to their items.

The repository’s development stack uses Alchemy (packages/infra/alchemy.run.ts), which can also deploy, as two Workers: one for the web app and one for the API. bun run deploy:stack -- --stage production does that. It needs BETTER_AUTH_SECRET, and CORS_ORIGIN set to the web app’s address; the one-Worker deploy above needs neither and is the simpler choice.

  • The test suite’s stacks add a route that wipes the database, guarded by E2E_RESET_TOKEN. It only exists when that variable is set; never set it for a real deploy.
  • bun run dev keeps its state on disk and never touches your Cloudflare account.