Quickstart
One path, no choices: a fresh Ubuntu or Debian server, the installer, the setup interview, and the owner-claim token. Everything else is a decision you can make later.
Before you start, read Requirements and sizing — the floor is 4 vCPU and 8 GB of RAM, and the reason is transcoding, not web serving.
docker-compose.prod.yml uses the !reset / !override merge tags to close the
Postgres, Redis and search port publishes. On an older Compose those tags are
silently ignored and your database is published to the internet while the
deploy reports success. deploy.sh, rollback.sh and restore.sh each parse
docker compose version --short and refuse to run below 2.24. The installer
installs a current Compose for you; verify with nmap from another host anyway.
Do not use a 2 GB droplet. ffmpeg runs inside the api container, so one
TargetAll job on a 1080p source is twelve full-source encode passes. Postgres,
api, frontend, search, Caddy and one transcode need roughly 4 GB before ClamAV.
Step 1 — run the installer
On the server, as a user who can sudo:
curl -fsSL https://raw.githubusercontent.com/yegamble/vidra/main/install.sh | sh
It detects the platform, installs Docker Engine and the Compose v2 plugin from
Docker's own apt repository if they are missing, downloads vidra-core's latest
release bundle, verifies it against the release's SHA256SUMS, unpacks it into
/opt/vidra, installs the checksum-verified vidra CLI into
/usr/local/bin, and then hands the terminal to vidra setup.
Everything it would change sits behind one confirmation, read from
/dev/tty because under curl … | sh stdin is the script itself. Pass --yes
where there is no terminal to ask on.
You should now see the installer's summary of what it found and what it installed, followed immediately by the first question of the setup interview. Nothing is running yet: the installer starts no containers and opens no ports.
Step 2 — set up, prepare the host, deploy
The interview writes env/production.env (mode 0600) and renders
deploy/Caddyfile.local from the deployment template. It asks for your domain
and TLS mode, media storage, which optional components you want, and mints every
secret the template leaves blank.
vidra setup --template env/production.env.example --yes # if you need to re-run it
vidra setup --template env/production.env.example --web # same questions, in a browser
Re-running is safe. The file being written is always read back first and every
value it already sets is preserved; a secret is only ever replaced when
--rotate names it. In a terminal, re-running over an existing env file needs
--yes (without it, setup refuses and changes nothing); the browser form asks in
its Review step instead. The installer never passes --yes, so an existing env
file is never silently rewritten.
Then prepare the host. The installer does not do this for you, and it is the
step the first deploy assumes: swap, the vidra service user, ownership of
/opt/vidra, the Docker log cap, unattended security upgrades and the nightly
backup timer.
cd /opt/vidra
sudo ./deploy/provision.sh
It opens no ports and does not touch sshd; it prints what your cloud firewall must allow. It is idempotent, so re-running it is safe. Details are in the one-line installer.
From here on, run vidra as the vidra user. Provisioning hands
/opt/vidra to it, env/production.env is readable by it alone, and it is the
user in the docker group. Run as your own login, the commands below fail with
a permission error.
Then bring the stack up:
cd /opt/vidra
sudo -u vidra vidra deploy
You should now see vidra deploy walk its gated pipeline — pre-deploy dump,
pull, the two migrators, up -d --no-build, health probes — and finish with
/readyz answering 200. Confirm it yourself:
curl -fsS http://127.0.0.1:8080/readyz
Step 3 — claim the owner account
The first admin is claimed, not registered. While the instance is unclaimed
— empty users table, unredeemed token — every signup path answers
403 owner_claim_required. The only way in is a one-time token the api mints at
boot and prints to its own log. vidra claim finds it for you.
In an SSH terminal on the server, from the deployment directory:
cd /opt/vidra
sudo -u vidra vidra claim
It prints one link, https://<your domain>/setup/claim#token=<token>. Open it
in your browser: the form is already filled in with the token, and the page
removes the token from the address bar. Choose your username, email and
password. vidra claim prints only to an interactive terminal (a pipe or a log
file never receives the token), and if it finds no token, the owner is probably
already claimed.
vidra claim needs a newer CLI than v0.7.5The command is merged but is not in v0.7.5 or earlier. It is available from the
release after v0.7.5. If vidra claim answers unknown command, use the log
fallback below, which works on every release.
Fallback: read the token from the api log. Run this on the server, as the
vidra user, because compose.sh reads the 0600 env file that only that user
can open:
cd /opt/vidra
sudo -u vidra ./deploy/compose.sh logs api | grep -E 'FIRST-RUN SETUP REQUIRED|OWNER STILL UNCLAIMED'
A fresh instance logs FIRST-RUN SETUP REQUIRED; an instance that has users but
whose owner was never claimed logs OWNER STILL UNCLAIMED. Both carry the token.
Use compose.sh, never a bare docker compose logs api — on a deployment host
the bare form auto-loads docker-compose.override.yml and addresses a different
project than the deploy scripts do. Take the newest line: every api restart
mints a fresh token and invalidates the previous one, and that includes the link
vidra claim printed.
Redeem the token at https://<your domain>/setup/claim in the browser (paste it
into the form), or directly:
curl -X POST https://example.com/api/v1/setup/claim-owner \
-H 'Content-Type: application/json' \
-d '{"token":"<the token>","username":"...","email":"...","password":"..."}'
Only the token's hash is stored, so a lost token is re-minted by restarting the api — never recovered.
You should now see your instance's home page at your domain, and be able to
sign in as the owner. Verify you actually got admin before you trust it:
GET /api/v1/admin/system with your access token must return 200, and /admin
in the UI must render.
Next steps
- Lock the box down. Production deployment
covers the firewall, the swapfile, the backup timer and the
nmapcheck that proves your database is not on the internet. - Decide your registration policy. Closed registration is the right default for a private launch. Change it in Admin → Configuration → General; see Moderation and instance settings.
- Prove your backups work. Run
sudo -u vidra ./deploy/backup.shonce by hand, then restore it into a scratch stack, never the live one. See Operator CLI. - Coming from PeerTube? Migrate from PeerTube.
- Just want to develop against it? Development setup.