# Installation
Requires Node.js 22+ (24.7+ for post-quantum SSH key exchange) and `git` on the `PATH`.
```bash
bun install # also downloads the PocketBase server into bin/
bun dev
```
Open http://localhost:3000, sign up, and create a repository.
The data lives in [PocketBase](https://pocketbase.io). Vectrum starts `bin/pocketbase` itself on `127.0.0.1:8090`, with its data in `data/pb_data` and the schema from `pb_migrations/`; its superuser login is generated into `data/pocketbase-superuser.json` (also good for the PocketBase dashboard at http://127.0.0.1:8090/_/). Run `bun run pocketbase:install` if the binary is missing. To use a PocketBase server of your own instead, set `PB_URL` and the superuser credentials; it needs the migrations in `pb_migrations/` (`pocketbase serve --migrationsDir pb_migrations`).
## Running with Docker
```bash
docker compose up -d --build
```
The image runs the web UI on port 3000 and the SSH server on port 2222, with all data in the `vectrum-data` volume (mounted at `/data`). Settings go under `environment:` in `docker-compose.yml` (see [Configuration](#configuration)). To close registration, set `SIGNUPS_DISABLED: "1"` before you deploy, and create accounts from the command line instead:
```bash
docker compose exec -it vectrum node scripts/create-user.mjs <username> <email> [name]
```
It asks for the password (or reads `VECTRUM_PASSWORD`). Outside Docker, run `node scripts/create-user.mjs` the same way while Vectrum runs. Clone URLs show `SSH_PORT`, so publish SSH on the same port on the host, and set `SSH_HOST` to your domain. Put a TLS reverse proxy in front of port 3000 if the server is reachable from the internet, and set `PUBLIC_URL` to its address.
## Configuration
| Variable | Default | Purpose |
| ----------------- | ----------- | --------------------------------------------------------- |
| `PUBLIC_URL` | request host | Canonical address, e.g. `https://vectrum.cc`. Used for clone URLs; `https` also makes session cookies `Secure`. Set it in production |
| `SECURE_COOKIES` | — | Set to `1` to mark session cookies `Secure` without `PUBLIC_URL` |
| `DATA_ROOT` | `./data` | Where repositories, the database and the SSH host key live |
| `PB_PORT` | `8090` | Port of the PocketBase server Vectrum runs |
| `PB_URL` | — | Use this PocketBase server instead of running one |
| `PB_SUPERUSER_EMAIL`, `PB_SUPERUSER_PASSWORD` | generated | Superuser login; required with `PB_URL` |
| `PB_BINARY` | `bin/pocketbase` | PocketBase executable to run |
| `SSH_PORT` | `2222` | Port of the built-in SSH server |
| `SSH_LISTEN_HOST` | `0.0.0.0` | Interface the SSH server binds to |
| `SSH_HOST` | request host | Host name shown in SSH clone URLs, e.g. `vectrum.cc` |
| `SSH_DISABLED` | — | Set to `1` to not start the SSH server |
| `SIGNUPS_DISABLED` | — | Set to `1` to close registration (add users with `scripts/create-user.mjs`) |
| `WEBHOOKS_ALLOW_PRIVATE` | — | Set to `1` to let webhooks reach private and local addresses (a trusted, single-team server) |
Data layout:
```
data/
pb_data/ PocketBase: users, keys, tokens, repos, issues, releases, workflow runs and logs
pocketbase-superuser.json the generated PocketBase superuser login
ssh_host_ed25519_key generated on first start
hooks/ server-side git hooks for every push, rewritten on start, and the socket they ask the server on
repos/<owner>/<repo>.git bare git repositories
wikis/<repo>.git each repository's wiki, named by its record id
registry.db container image manifests, tags and blob records (SQLite)
registry/blobs/sha256/… container image layers, shared by all repositories
registry/uploads/ image uploads in progress
releases/<repo>/<release>/… release files, named by their record id
```
The registry keeps its records in SQLite rather than PocketBase so that storing a
blob and pruning unused ones never interleave. A blob is deleted once no
manifest of any repository references it (blobs pushed in the last 24 hours are
kept so pushes in progress don't lose their layers).