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
- Open your domain in a browser and sign in — the first user account is created automatically via email OTP.
- Create an organization from the Account tab.
- Generate an API key from the Organization tab — you'll need this for the CLI.
- 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.