Staging and branch preview deployments on a VPS
Turn on a preview deployment per branch and a staging copy, each with its own database, on your own server. Limits, passwords and promote to production.
Last updated 2026-10-08
To get a preview deployment for every branch, turn on Branch previews in the project's Settings or run ox previews <project> on; each push then deploys that branch to its own address. Staging is one copy of your app where you try changes before you promote them to production. Each copy has its own database and its own variables, on the same server as production.
Turn on branch preview deployments
Previews are off until you turn them on. In the dashboard, open the project's Settings tab and press Turn on in the Branch previews card. From a terminal:
ox previews shop onAfter that, every branch you push gets its own copy, and each push updates it. Production's branch and staging's branch never get one.
Which branches
By default it is All branches except bots, so dependabot/*, renovate/* and branches a bot account pushed are skipped. Pick Only branches matching to list patterns instead. In a pattern, * matches anything, slashes too, and ? matches one character. You can list up to 20.
ox previews shop --branches feature/*
ox previews shop --branches all
ox previews shop start fix/login
ox previews shop remove fix/loginPreview limits and cleanup
- 3 at once by default. You can pick 1 to 10 in Settings or with
ox previews shop --at-once 5. Each one is a full copy of your app, so your server's memory still has to hold it (see Not enough memory). - When the limit is reached, a new branch waits in line, and
ox environments shopshows its place, such aswaiting: 2nd. - 7 days without a deploy, and the preview is deleted. A push or a deploy by hand resets the clock. It comes back on the next push.
- A preview is also deleted when its pull request is merged, its branch is deleted, or your branch list no longer matches it.
To keep a preview past the 7 days, press Keep on it, or run:
ox keep shop --env fix/login onHTTPS preview URLs on your own domain
Without a preview domain, each copy gets a free address like http://shop-fix-login.203-0-113-7.sslip.io, made from its name and your server's IP. It is plain HTTP, with no certificate.
For HTTPS addresses under your own domain, set a preview domain in the account's Settings, under Preview domain, or run:
ox settings preview-domain preview.example.comThen create one DNS record at your DNS provider: *.preview.example.com, type A, pointing at your server's IP. A preview of fix/login is then at https://shop-fix-login.preview.example.com.
Make a staging environment
Production must have deployed once. On the project's Settings tab, fill in a branch and a domain if you want them, and press Create staging. From a terminal:
ox staging shop --branch develop --waitThe copy is named shop-staging. It starts at production's live commit, or follows the branch you name. Your variables are copied once, when it is made; after that the two are set apart. Data is never copied: staging starts with an empty database. Without --domain, it gets an address under your preview domain, or the free sslip.io one.
Password-protect copies
This is off by default. Turn it on for every staging and preview copy in the account's Settings, under Password-protect staging and previews. The site then asks for the username ox and a password. Copy the password when it is shown: ox keeps only a hash and cannot show it again. One copy can differ from the account's choice:
ox protect --account on
ox protect shop --env staging offPromote staging to production
Promote deploys production at the commit staging runs. On the staging copy's page, press Review in Promote to production. It shows the commits production would get, and nothing happens until you press Promote to production. From a terminal:
ox promote shop --waitYou can name production or its staging copy. It lists the commits and asks Promote to production? [y/N]. Add --yes where no one can answer, like in CI. If the promote pauses deploy on push for production, it says so first, with the command that turns it back on.
Only the code moves. Production keeps its own variables, data, domains, password setting and previews. If the new code needs a new variable, set it on production first. The migrations run against production's database. A preview cannot be promoted: merge its branch, or promote staging.
If a preview does not work
3 previews already run, the most this project runs at once; remove one first, or raise the number in Settings: remove a preview, or raise the number.- A branch got no preview: check that previews are on and that your branch list matches it. A preview removed after 7 days comes back only on a new push.
a preview cannot be promoted; promote staging, or merge the branch: run promote on the staging copy.- A preview address does not load over HTTPS: without a preview domain the address is HTTP only. With one, check the
*.record points at your server. See Domains.