[Blog](https://deploywithox.com/blog) [Guides](https://deploywithox.com/blog#c-guides) # How to self-host Kaneo on your own VPS without Docker Run Kaneo v2.41.1, the open-source project board, on your own Ubuntu server with ox: a Postgres database, a pnpm build, and the config that ran. Saurav Sharma Oct 17, 2026 9 min read On this page - [What you need](https://deploywithox.com/blog/self-host-kaneo#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-kaneo#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-kaneo#config) - [Updates and backups](https://deploywithox.com/blog/self-host-kaneo#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-kaneo#faq) To self-host Kaneo you need an Ubuntu server, a fork of the Kaneo repo with one `ox.toml` file added, and 21 variable names, of which three hold a value and the rest are saved empty. In our run the first deploy took about 4 minutes, and ox set up Postgres for it. **How we tested** On Oct 17, 2026, ox deployed Kaneo v2.41.1 from commit [`44327a80`](https://github.com/usekaneo/kaneo/commit/44327a803196511e4361a098314e62d5ed9191ac) 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, made a workspace and a project, added a task, and saw it on the board after a reload, and checked the app's services and its backup. [Kaneo](https://github.com/usekaneo/kaneo) is an open-source project management tool under the MIT license. You make a workspace, add projects, and plan the work on a board, a list, a calendar or a Gantt chart. The repo is a pnpm workspace, and the app has two parts: a Hono API on Node.js that keeps its data in Postgres, and a React client built with Vite. ox deployed Kaneo v2.41.1 (commit 44327a80) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 4 minutes and a redeploy took 2 minutes. - **First deploy:** 4 minutes, from adding the project until the app passed the run's first checks. - **Redeploy of the same commit:** 2 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:** 834 MB of 15986 MB, for the whole server: Ubuntu, the app, 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/usekaneo/kaneo](https://github.com/usekaneo/kaneo) at v2.41.1, commit [`44327a80`](https://github.com/usekaneo/kaneo/commit/44327a803196511e4361a098314e62d5ed9191ac). The Kaneo sign-in page The Kaneo Launch Board of the workspace Verify Team after signing in The Kaneo Launch Board with six tasks in To Do after a task was added ## What you need - An Ubuntu LTS server. The run used the size in the facts above, with Kaneo alone on it. ox reads Node 24.19.0 from Kaneo's Dockerfile and pnpm 10.32.1 from `package.json`. - A GitHub account to fork `usekaneo/kaneo`, and an ox account, which you open by signing in with GitHub. - No outside account. Kaneo's docs describe optional ones: SMTP for email, a GitHub OAuth App for GitHub sign-in, an S3-compatible bucket for uploads, and Redis for several API processes. None was set up, so none was tested. ## The steps Press Add a server in the ox dashboard and paste the command it shows into a root shell on the VPS. It installs the ox agent and Caddy only. Fork `usekaneo/kaneo` and check out the tag `v2.41.1`, the release the run deployed. Put the `ox.toml` shown below at the repo's root, then commit and push. Write `kaneo.env` on your laptop with one line for each of the 21 names in the variables list. The run gave `KANEO_CLIENT_URL`, `KANEO_API_URL` and `AUTH_SECRET` a value and left the other 18 empty, written as `NAME=`. With the [ox CLI](https://deploywithox.com/docs/cli) signed in, run: Shell ```bash ox new /kaneo ox review kaneo --from-file kaneo.env --wait ``` The project takes the repo's name, so it is `kaneo`. The review saves the values and starts the first deploy, and `--wait` prints the run until it ends. The browser route is New project and the review screen, as the [quickstart](https://deploywithox.com/docs/quickstart) shows. When the run is green, open the project's address. Sign-up is open on a new Kaneo, and its docs say the first account becomes the instance administrator, so create yours first. 1. Click "Create an account" under the sign-in form and give a name, an email and a password. 2. Kaneo asks you to name a workspace and a first project. The test agent named them Verify Team and Launch Board. The new board holds a few starter tasks. 3. Click the + beside a column title and add a task. After a reload, the task is still on the board. The test agent also typed a wrong password at the sign-in form, and Kaneo refused it. Everything above used Kaneo's preview address, so a domain of your own was not tested. The [domains page](https://deploywithox.com/docs/operate/domains) covers how ox adds one. ## The ox.toml, line by line TOML ```toml # Kaneo: a Hono API (apps/api, bundled by esbuild, applies its own # migrations at start) and a Vite client (apps/web) in a pnpm workspace. The # root has no start script and its build also builds the docs and the # marketing site, so the operator names the two parts: Caddy serves the # client and sends the API's paths to the API, as nginx.kaneo.conf does in # the image (Dockerfile.kaneo). [app] start = "cd apps/api && node dist/index.js" health = "/api/health" # The API listens on 1337 and never reads PORT. port = 1337 [static] dir = "apps/web/dist" spa = true # The image's nginx sends /api and the two MCP OAuth discovery paths to the # API. api = [ "/api", "/.well-known/oauth-protected-resource/api/mcp", "/.well-known/oauth-authorization-server/api", ] [build] commands = [ # "..." builds each app's workspace packages first. "pnpm --filter '@kaneo/api...' run build", "pnpm --filter '@kaneo/web...' run build", # The client is built with placeholders (apps/web/.env.production: # KANEO_API_URL, KANEO_CLIENT_URL, KANEO_TURNSTILE_SITE_KEY), and the # image's env.sh writes the real values over them at start with # apps/web/env.awk. The build here has the variables, so the same awk runs # once on the built files; with no KANEO_TURNSTILE_SITE_KEY the sign-in # pages show no captcha. The image deletes the source maps too. "find apps/web/dist -type f -name '*.map' -delete", "find apps/web/dist -type f -name '*.js' -exec sh -euc 'for f do LC_ALL=C awk -v mode=bundle -f apps/web/env.awk \"$f\" >\"$f.ox\"; mv \"$f.ox\" \"$f\"; done' sh {} +", ] # The API migrates as it starts, with its own fixes before and after # Drizzle's migrations (runStartupTasks in apps/api/src/index.ts), as the # image's entrypoint does; a bare drizzle-kit migrate would skip those fixes. migrate = "" [services] # Redis is optional: one API process fans WebSocket events out in memory. postgres = {} ``` Kaneo's root has no start script, and its root build also builds the docs and marketing sites. Without this file, `ox check` stops with "nothing to run", so the config names the API and the client. - `[app]` runs the API's bundle from `apps/api`. The API listens on port 1337 and never reads `PORT`, so the config pins that port. Its `health` path answers `{"status":"ok"}`, and a new release gets traffic only after it does. - `[static]` serves the client's built files. With `spa = true`, a path with no file gets `index.html`, because the client routes its pages in the browser. The `api` list sends three paths to the API instead: `/api`, and two `/.well-known` paths its MCP endpoint uses for OAuth discovery. They match the routes in the nginx file of Kaneo's image. - The first two build commands build the API and the client with the workspace packages they need, which the `...` in each filter asks for. - The last two give the client its addresses. Kaneo builds the client with placeholder text where its two addresses and an optional captcha key go, and in Docker a script swaps in real values at every container start with Kaneo's own `env.awk`. Under ox the build runs that same awk over the built scripts, with the variables ox sets during a build, after deleting the source maps as the image does. `KANEO_TURNSTILE_SITE_KEY` is unset, so the sign-in pages show no captcha. A new address therefore needs a new build. - `migrate = ""` runs no migration step. Without it, ox finds Kaneo's Drizzle config and would run a bare `drizzle-kit migrate`. The API migrates its own database as it starts, with fixes of its own before and after Drizzle's migrations, as Kaneo's image does. - `[services]` asks for Postgres, which ox hands over as `DATABASE_URL`. Kaneo reads that name ahead of any `POSTGRES_*` name. Redis is left out, and Kaneo then passes live updates in memory. The config declares no workers or scheduled jobs. The test agent found one Kaneo unit on the server, `ox-kaneo-app-a`, active with no restarts. Shell ```bash KANEO_CLIENT_URL KANEO_API_URL AUTH_SECRET POSTGRES_DB POSTGRES_USER POSTGRES_PASSWORD GITHUB_OAUTH_CLIENT_ID GITHUB_OAUTH_CLIENT_SECRET GITHUB_CLIENT_ID GITHUB_CLIENT_SECRET GITHUB_APP_ID GITHUB_WEBHOOK_SECRET GITHUB_PRIVATE_KEY GITHUB_APP_NAME SMTP_HOST SMTP_PORT SMTP_SECURE SMTP_USER SMTP_PASSWORD SMTP_FROM SMTP_REQUIRE_TLS ``` - `KANEO_CLIENT_URL` is `${PUBLIC_URL}` and `KANEO_API_URL` is `${PUBLIC_URL}/api`. These references take the project's address, and the build writes them into the client. Kaneo's image derives the second from the first; here both are set. [Variables](https://deploywithox.com/docs/operate/variables) explains references. - `AUTH_SECRET` is a random value of 64 hex characters. Kaneo's docs ask for at least 32 characters, make theirs with `openssl rand -hex 32`, and say to keep it in your config backup, so keep a copy of `kaneo.env`. - `POSTGRES_DB`, `POSTGRES_USER` and `POSTGRES_PASSWORD` are settings of Kaneo's Compose file. They are empty because `DATABASE_URL` wins over them. - The `GITHUB_OAUTH_*` and `GITHUB_CLIENT_*` keys turn on Sign in with GitHub. The other four GitHub names (app id, webhook secret, private key, app name) belong to Kaneo's GitHub App, which syncs repositories. Empty keeps both off, and neither was tested. - The `SMTP_*` keys set up email, which Kaneo sends only when `SMTP_HOST` and `SMTP_FROM` are both set. Empty means no email, and sign-in takes an email and a password. ## Updates and backups For a newer release, merge its tag into your fork and push, or run `ox deploy kaneo --wait`. The API applies its migrations when it starts. Kaneo's upgrade notes say to read the release notes and back up first, since an upgrade can change the database as well as the app. The run redeployed the same commit. A newer Kaneo release was not tested. Postgres was backed up with Back up now, and the test agent found the dump on the server and checked that it was not empty. `ox backups kaneo` and the Backups tab list it. Kaneo's backup notes count uploaded files as part of a full backup, and none were stored. A restore was not tested. The [backups page](https://deploywithox.com/docs/operate/backups) covers the daily schedule and your own S3 bucket. ## Frequently asked questions ### Do I need Docker to self-host Kaneo? No. Kaneo's install guide and compose file use Docker images, but the app is a Node.js API and a static client. ox builds both from your fork on the server, runs the API as a system service beside Postgres, and lets Caddy serve the client. There is no image to pull, and an update is a push. ### How do I create the first Kaneo account? No variable sets it. Open the project's address, click Create an account, and give a name, an email and a password. Kaneo's docs say the first account on a new instance becomes an instance administrator. Sign-up is open by default, so make yours first. The docs describe DISABLE_REGISTRATION to close it, which the run did not use. ### How much memory does Kaneo use? After the reboot, the whole server used the memory the facts above show. That counts Kaneo, Postgres, Caddy and the ox agent. The build runs on the server too, as a pnpm install and two builds. ox takes any server from 1 GB up and says so when memory is why an app stopped. ### Does Kaneo need Redis or email? Only Postgres is required. Redis matters only when you run several API processes, since Kaneo otherwise passes live updates in memory. Email is optional too: with no SMTP settings, people sign in with an email and a password. Neither Redis nor email was set up, so neither was tested. ### Is Kaneo free to self-host? Yes. Kaneo's README says it is open source under the MIT license, and the repo's LICENSE file is the MIT text. The project also runs a hosted Kaneo Cloud, but the run needed no account there. See [self-hosting](https://deploywithox.com/self-hosting) for what ox runs on your own server. New to running apps on your own server? [How ox self-hosts your apps](https://deploywithox.com/self-hosting) shows what ox sets up on your server. On this page - [What you need](https://deploywithox.com/blog/self-host-kaneo#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-kaneo#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-kaneo#config) - [Updates and backups](https://deploywithox.com/blog/self-host-kaneo#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-kaneo#faq) - [Do I need Docker to self-host Kaneo?](https://deploywithox.com/blog/self-host-kaneo#faq-docker) - [How do I create the first Kaneo account?](https://deploywithox.com/blog/self-host-kaneo#faq-account) - [How much memory does Kaneo use?](https://deploywithox.com/blog/self-host-kaneo#faq-memory) - [Does Kaneo need Redis or email?](https://deploywithox.com/blog/self-host-kaneo#faq-services) - [Is Kaneo free to self-host?](https://deploywithox.com/blog/self-host-kaneo#faq-license) Written by Saurav Sharma Builds ox. Writes about running apps on servers you own, without Docker and without a platform bill. [Older post How to self-host Karakeep (bookmarks) on your own VPS](https://deploywithox.com/blog/self-host-karakeep) [Newer post How to self-host Joplin Server without Docker on a VPS](https://deploywithox.com/blog/self-host-joplin) ## Keep reading - Guides [Self-Hosted Open-Source Apps Deployed with ox: All 85](https://deploywithox.com/blog/self-hosted-open-source-apps-deployed-with-ox) ox deployed 85 open-source apps from pinned commits on fresh servers, with no Docker. The stacks, services, deploy times and a table of every app. Saurav Sharma Oct 17, 2026 16 min read - Guides [How to self-host AFFiNE on your own VPS without Docker](https://deploywithox.com/blog/self-host-affine) Run AFFiNE v0.27.4 on your own Ubuntu server with ox: Postgres with pgvector, Redis, a Rust and Node build, and an admin made from two variables. Saurav Sharma Oct 17, 2026 12 min read - Guides [How to self-host Akaunting on your own VPS without Docker](https://deploywithox.com/blog/self-host-akaunting) Run Akaunting 3.2.4 on your own Ubuntu server with ox: PHP, MariaDB, a scheduler and the first company and admin made on deploy, from the config that ran. Saurav Sharma Oct 17, 2026 10 min read ## 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](https://deploywithox.com/login/github) [Read the docs](https://deploywithox.com/docs)