BlogGuides

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.

On this page

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.
The Kellnr home page, a private Rust crate registry
The Kellnr home page, a private Rust crate registry
The Kellnr home page signed in as admin
The Kellnr home page signed in as admin
The Kellnr Authentication Tokens settings with the token verify-ci-token, its value not shown
The Kellnr Authentication Tokens settings with the token verify-ci-token, its value not shown

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:

Shell
ox new <you>/kellnr
ox review kellnr --from-file kellnr.env --wait

The 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

TOML
# 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.

  • start runs the binary the build leaves at target/release/kellnr. Kellnr listens on every address at port 8000 and ignores PORT, so the line sets KELLNR_LOCAL__IP to the loopback address, where only Caddy reaches it, and KELLNR_LOCAL__PORT to the $PORT ox gives each release, so old and new copies can overlap during a deploy. exec lets ox's stop signal reach Kellnr itself.

  • health is Kellnr's own route, which answers OK. ox sends traffic to a new release only after it answers.

  • install runs npm ci in ui, which installs the web page's packages from its lockfile.

  • The build commands run in order. Vite builds the web page into ui/dist. The copy puts it in crates/embedded-resources/static, which Kellnr's Rust code embeds at compile time, so it must exist before Cargo starts. Then cargo build --release --locked builds the registry from the versions in Cargo.lock.

  • There is no migrate line, 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.

Shell
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__PWD

KELLNR_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.

Keep reading

Deploy to a server you own

ox sets up systemd, Caddy and PostgreSQL on your Ubuntu server and deploys on every push. Free for your first project.

Sign up with GitHub Read the docs