How to self-host Kellnr, a Rust registry, on your own VPS
Run Kellnr v6.9.0, the private Rust crate registry, on your Ubuntu server with ox and no Docker: a Rust build and Postgres, from the config that ran.
To self-host Kellnr you need an Ubuntu server, a fork of the Kellnr repo with one ox.toml file added, and ten variables. In our run the first deploy took about 10 minutes, which covers building the web page and compiling the Rust code, and ox set up the Postgres database where Kellnr keeps its records.
How we tested On Oct 17, 2026, ox deployed Kellnr v6.9.0 from commit 4c946274 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory. The run then redeployed it, backed it up and rebooted the server. Then a separate test agent, one that did not write the config, signed in, created an access token and saw it listed after a reload, and checked the app's services and its backup.
Kellnr is an open-source registry for Rust crates, which its README likens to crates.io on your own hardware. You publish private crates to it with cargo and your other projects fetch them from it. A web page browses and searches them and manages tokens, users and groups. Rustdoc hosting and a crates.io cache exist and are off by default. Kellnr is written in Rust, its Vue web page is embedded in the one binary, and the license is MIT or Apache 2.0, at your choice.
ox deployed Kellnr v6.9.0 (commit 4c946274) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 10 minutes and a redeploy took 9 minutes.
- First deploy: 10 minutes, from adding the project until the app passed the run's first checks.
- Redeploy of the same commit: 9 minutes, until the app passed the checks again.
- Server: DigitalOcean, 8 vCPUs and 16 GB of memory (
s-8vcpu-16gb), with this app alone on it. Every one of the 85 apps we deployed ran on this one size, so it was not picked for this app. - Memory in use after the reboot: 620 MB of 15986 MB, for the whole server: Ubuntu, the app and its staging copy, its services, Caddy and the ox agent. On a server with no apps, ox's tests on real servers hold the agent to 40 MB or less and Caddy to 50 MB or less.
- Services ox runs for it:
postgres. - Source: github.com/kellnr/kellnr at v6.9.0, commit
4c946274.



What you need
An Ubuntu LTS server. The run used the size in the facts above and measured the memory there. The server builds Kellnr itself, so it reaches npm and crates.io.
A GitHub account to fork
kellnr/kellnr, and an ox account, which you open by signing in with GitHub.No outside account. The run kept crate files in a data folder on the server's disk and records in Postgres. Storage on S3 or Google Cloud, the crates.io cache, rustdoc hosting and OAuth2 sign-in were not tested.
The steps to install Kellnr on Ubuntu
In the ox dashboard press Add a server and run the install command it shows, as root, on your Ubuntu machine. It installs the ox agent and Caddy.
Fork kellnr/kellnr and start from commit 4c946274, titled chore: release v6.9.0, the one the run deployed. Add the ox.toml shown below at the top of the repo, then commit and push. No other file is added. Write kellnr.env on your laptop with the ten keys listed under the variables, set as that section says. With the ox CLI signed in, run:
ox new <you>/kellnr
ox review kellnr --from-file kellnr.env --waitThe project takes the repo's name. The review saves the values and starts the first deploy, and --wait prints the run until it ends. The quickstart shows the same two steps in the browser.
When the deploy is green, open the address ox shows. The home page says Welcome to Kellnr, with crate, version and download counts of zero on a new registry. The run used this preview address, and a domain of your own was not part of it. The domains page covers adding one.
Press Log in at the top right and sign in as admin. Kellnr has no sign-up page. The run left KELLNR_SETUP__ADMIN_PWD unset, so the password is Kellnr's default, admin. A wrong password gets Wrong user or password, and the right one puts the admin menu in the header. That default is in Kellnr's source, so anyone who finds the address can try it. Settings has a Change Password page, which the run did not use.
Then open Settings, the Auth. Tokens page, type a name and press Create Token. Kellnr shows the token once, with a Copy button, and after a reload it is listed under Active Tokens. Kellnr says tokens let you publish crates with cargo without your password. Publishing or fetching a crate with cargo was not tested.
The ox.toml, line by line
# Kellnr 6.9.0 (Rust, a private crate registry with a Vue UI) on ox's
# postgres, as its operator would write it: the UI is built with npm and
# copied into the embedded-resources crate (the justfile's npm-build
# steps), then the registry is built.
[tools]
# The UI pins no node; its vite build needs 22 or newer.
node = "24"
[app]
# Kellnr binds its own address and port (not PORT); the port is per
# release, and its data is files in the data folder.
start = "KELLNR_LOCAL__IP=127.0.0.1 KELLNR_LOCAL__PORT=$PORT exec target/release/kellnr start"
health = "/api/v1/health"
[build]
install = "cd ui && npm ci"
commands = [
"cd ui && npm run build",
"mkdir -p crates/embedded-resources/static && cp -r ui/dist/* crates/embedded-resources/static/",
"cargo build --release --locked",
]
[services]
postgres = {}The file follows the repo's justfile: web page first, registry second.
[tools]asks for Node 24, since the web page's folder pins none and its build tool, Vite 8.3, asks for Node 20.19, or 22.12 and newer. No Rust line is needed. The repo pins no version, so ox's default, the stable release, builds the registry, and ox adds the C compilers, pkg-config and OpenSSL headers itself.startruns the binary the build leaves attarget/release/kellnr. Kellnr listens on every address at port 8000 and ignoresPORT, so the line setsKELLNR_LOCAL__IPto the loopback address, where only Caddy reaches it, andKELLNR_LOCAL__PORTto the$PORTox gives each release, so old and new copies can overlap during a deploy.execlets ox's stop signal reach Kellnr itself.healthis Kellnr's own route, which answers OK. ox sends traffic to a new release only after it answers.installrunsnpm ciinui, which installs the web page's packages from its lockfile.The build
commandsrun in order. Vite builds the web page intoui/dist. The copy puts it incrates/embedded-resources/static, which Kellnr's Rust code embeds at compile time, so it must exist before Cargo starts. Thencargo build --release --lockedbuilds the registry from the versions inCargo.lock.There is no
migrateline, because Kellnr creates and updates its own tables at start.[services]asks for Postgres. Without it Kellnr would use SQLite.
There is no [storage] section: Kellnr's data folder is $OX_DATA_DIR, which ox keeps across releases. The test agent found no worker, scheduler or timer.
KELLNR_REGISTRY__DATA_DIR
KELLNR_ORIGIN__HOSTNAME
KELLNR_ORIGIN__PROTOCOL
KELLNR_ORIGIN__PORT
KELLNR_POSTGRESQL__ENABLED
KELLNR_POSTGRESQL__ADDRESS
KELLNR_POSTGRESQL__PORT
KELLNR_POSTGRESQL__DB
KELLNR_POSTGRESQL__USER
KELLNR_POSTGRESQL__PWDKELLNR_REGISTRY__DATA_DIR is ${OX_DATA_DIR}. Kellnr stops at start without a data folder, and it keeps the crates and the index there.
KELLNR_ORIGIN__HOSTNAME, KELLNR_ORIGIN__PROTOCOL and KELLNR_ORIGIN__PORT are the address people use to reach Kellnr, which it builds its links from. They are ${PUBLIC_HOST}, ${PUBLIC_SCHEME} and ${PUBLIC_PORT}, filled in by ox. Kellnr marks its session cookie Secure when the protocol is https, and a browser drops that cookie on an http page, so a fixed https would break sign-in on an http address. The port is the public one, 443 or 80, which Kellnr leaves out of its links.
KELLNR_POSTGRESQL__ENABLED is true, which switches Kellnr from SQLite to Postgres. Kellnr takes the database in five parts: KELLNR_POSTGRESQL__ADDRESS, __PORT, __DB, __USER and __PWD are ${postgres.host}, ${postgres.port}, ${postgres.database}, ${postgres.user} and ${postgres.password}, the details of the Postgres ox set up. See variables for how references work.
KELLNR_SETUP__ADMIN_PWD is not in the list. It sets the first admin password, which defaults to admin, and it counts only when Kellnr finds no users, so changing it later leaves the password as it was.
Postgres and the data folder
ox's Postgres is shared with the server's other projects and gives Kellnr its own database and a role that alone may connect to it. The staging copy the run deployed beside production has a database of its own, and the memory figure above counts both. Postgres holds users, tokens and crate records. Kellnr's help text says the data folder holds the crates and the index.
Updates and backups
To update, merge a newer release into your fork, push, and run ox deploy kellnr --wait. ox builds the new release beside the running one and switches when the health path answers. The run redeployed the same commit, so a jump between Kellnr versions was not tested. The release notes on Kellnr's GitHub page list what each version changed.
Backups need no setup. The run's backups held a Postgres dump, the daily one and the one from Back up now, and nothing else: no copy of the data folder, where Kellnr keeps the files of published crates, and the run published no crate. List them with ox backups kellnr. A restore was not tested. The backups page covers keeping copies in an S3 bucket.
Frequently asked questions
Do I need Docker to self-host Kellnr?
No. Kellnr's README starts with a Docker image and also lists binary releases and a Kubernetes chart. ox builds Kellnr from your fork on the server and runs it as a system service, with Postgres beside it. There is no image to pull, and an update is a push and one deploy command.
Does Kellnr need Postgres?
No. Kellnr uses SQLite unless KELLNR_POSTGRESQL__ENABLED is true, and it supports both. The run used Postgres, which ox installed and wired in through five variables. Crate files stay in the data folder on disk either way, unless you point Kellnr at S3 or Google Cloud storage, which was not tested.
What is the first Kellnr login?
The user is admin, and the password is the value of KELLNR_SETUP__ADMIN_PWD, or Kellnr's default, admin, when it is unset, as in the run. Kellnr creates the user on its first start with no users and has no sign-up page. Settings has a User Management page for more users, which the run did not use.
How much memory does self-hosted Kellnr use?
After the run's reboot the whole server used the memory the facts show, counting Kellnr, its staging copy, Postgres, Caddy and the ox agent. Memory during the build, which compiles Rust and runs Vite on the server, was not measured. ox takes any server from 1 GB up and says so when memory is why an app stopped.
New to running apps on your own server? How ox self-hosts your apps shows what ox sets up on your server.
