Self-hosting

OtaKit is fully open source and can run on your own infrastructure. You'll need PostgreSQL and any S3-compatible object storage (AWS S3, Cloudflare R2, MinIO).

Requirements

  • Node.js 18+
  • PostgreSQL 14+
  • S3-compatible storage (R2, MinIO, AWS S3)

Environment variables

# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/otakit

# Auth
BETTER_AUTH_SECRET=your-random-secret    # openssl rand -hex 32
BETTER_AUTH_URL=https://your-domain.com

# S3-compatible storage
R2_BUCKET=otakit-bundles
R2_ACCESS_KEY=...
R2_SECRET_KEY=...
R2_ENDPOINT=https://....r2.cloudflarestorage.com

# Optional: upload size limit (bytes, default 200MB)
MAX_BUNDLE_SIZE=209715200

# Optional: manifest signing (ES256)
# Generate with: otakit generate-signing-key
MANIFEST_SIGNING_KID=key-2026-01
MANIFEST_SIGNING_KEY=-----BEGIN EC PRIVATE KEY-----...

# Optional: global admin key for tenant management
ADMIN_API_KEY=your-admin-key

Deploy

git clone https://github.com/nicepkg/otakit
cd otakit

# Install dependencies
pnpm install

# Run database migrations
cd packages/web
npx prisma migrate deploy

# Build and start
pnpm build
pnpm start

The server runs on port 3000 by default. Point your reverse proxy (nginx, Caddy) to it and ensure HTTPS is configured.

Docker

docker run -d \
  -p 3000:3000 \
  -e DATABASE_URL=postgresql://... \
  -e BETTER_AUTH_SECRET=... \
  -e BETTER_AUTH_URL=https://your-domain.com \
  -e R2_BUCKET=otakit-bundles \
  -e R2_ACCESS_KEY=... \
  -e R2_SECRET_KEY=... \
  -e R2_ENDPOINT=https://... \
  ghcr.io/nicepkg/otakit:latest

Initial setup

  1. Open your domain in a browser and sign in — the first user account is created automatically via email OTP.
  2. Create an organization from the Account tab.
  3. Generate an API key from the Organization tab — you'll need this for the CLI.
  4. Point the CLI to your server:
export OTAKIT_SERVER_URL=https://your-domain.com
export OTAKIT_SECRET_KEY=otakit_sk_...

Manifest signing

For end-to-end integrity, enable ES256 manifest signing. Generate a key pair:

otakit generate-signing-key

This outputs the server environment variables (MANIFEST_SIGNING_KID, MANIFEST_SIGNING_KEY) and the plugin config (manifestPublicKeys). Add them to your server and Capacitor config respectively.

Connecting CLI and plugin

Point the CLI to your server with OTAKIT_SERVER_URL:

export OTAKIT_SERVER_URL=https://your-domain.com
export OTAKIT_SECRET_KEY=otakit_sk_...

In your Capacitor plugin config, set updateUrl to your server:

plugins: {
  Updater: {
    updateUrl: "https://your-domain.com/api/v1",
    appId: "YOUR_APP_ID",
    publicKey: "YOUR_PUBLIC_KEY",
    // ...
  }
}

The updateUrl is only needed for self-hosting — it defaults to https://updatekit.vercel.app/api/v1 when omitted. Follow the standard setup guide for the rest of the plugin and CLI configuration.