Self-Hosting
Source:
en/guide/self-hosting.md· Live: https://docs.1pass.dev/en/guide/self-hosting LLM-sanitized: internal links absolutized, VitePress containers → admonitions, line numbers in the Jump-to Index reference this rendered file (1-indexed).
📍 Jump-to Index
- L28-L36: ## When you need self-hosting
- L37-L100: ## Requirements
- L101-L117: ## Setup
- L118-L183: ## Registering your first OAuth app (local)
- L122-L131: ### 1) Create a developer account and sign in
- L132-L146: ### 2) Issue a Personal API Key
- L147-L166: ### 3) Register the OAuth app
- L167-L183: ### 4) Sign up a test end user
- L184-L192: ## Operational considerations
- L193-L196: ## When you need help
Self-Hosting
This guide is for anyone running the logi server themselves. If you only want to integrate OAuth, the managed IdP (https://1pass.dev) path in the Quickstart is much faster.
⚠️ Warning: Alpha · partners only Self-hosting is currently alpha-stage and gated to partners/contributors. Source access is provided during onboarding or partnership (contact
support@1pass.dev). Public self-service deployment packages are not available yet, and container images / Helm charts are not packaged yet. See Setup below.
When you need self-hosting
- Contributor: you modify or contribute to the logi server code.
- Enterprise: you need to run an IdP in isolation, serving only your internal users.
- Compliance: user data must not leave your own infrastructure (for example, a domestic data center or on-prem).
- Local integration testing: reproducible scenarios that the managed IdP's sandbox alone can't cover (for example, time manipulation or direct DB inspection).
For most RP integrations, the sandbox tier of the managed IdP is enough.
Requirements
| Component | Version |
|---|---|
| Ruby | 3.3+ |
| Rails | 8.0+ |
| PostgreSQL | 16+ |
| Redis | 7+ (for the SolidQueue / rate-limit backend) |
| Node.js | 20+ (for building JS assets) |
Required environment variables:
SECRET_KEY_BASE=<output of rails secret>
DATABASE_URL=postgres://localhost/logi_development
RAILS_ENV=development
# OAuth provider (Sign in with Apple / Google) — optional; without it, email login only
APPLE_TEAM_ID=...
APPLE_KEY_ID=...
APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
APPLE_DEFAULT_CLIENT_ID=com.example.app
GOOGLE_OAUTH_CLIENT_ID=...
GOOGLE_OAUTH_CLIENT_SECRET=...
# APNs (mobile push approval — optional)
APNS_KEY_ID=...
APNS_TEAM_ID=...
APNS_KEY_PATH=/path/to/AuthKey_XXXXX.p8
APNS_TOPIC=com.example.app
APNS_TOPIC_MACOS=com.example.app.mac # if the macOS app is a separate bundle
APNS_ENV=development
# OIDC discovery (the self-hosted issuer URL in production)
OIDC_ISSUER=https://idp.example.com
APP_HOST=idp.example.com # :host for Rails default_url_options
LOGI_API_HOST=api.example.com # when splitting hosts — the quickstart/registering-apps host gate
LOGI_ADMIN_API_HOST=admin.example.com # admin route gate (optional)
# WebAuthn (Passkey)
WEBAUTHN_ORIGIN=https://idp.example.com
WEBAUTHN_RP_ID=example.com
# Android App Links (assetlinks.json) — when running a mobile app
ANDROID_APP_CERT_SHA256=AB:CD:...
# Operational toggles (recommended in production)
ENFORCE_CANONICAL_RESOLUTION=true # enforce canonical_sub after a merge (see the account-merge guide for details)
SOLID_QUEUE_IN_PUMA=true # run SolidQueue inside puma without a separate worker process
JOB_CONCURRENCY=1 # SolidQueue concurrency
LOGI_BETA_AUTO_APPROVE=false # public-client beta auto-approval (beta period only)
# External SaaS — optional, depending on the features you use
RESEND_API_KEY=re_... # email delivery
TELEGRAM_ADMIN_BOT_TOKEN=... # production-promotion alerts
TELEGRAM_ADMIN_CHAT_ID=...
FCM_PROJECT_ID=... # Android push
FCM_SERVICE_ACCOUNT_JSON_PATH=/path/to/sa.json⚠️ Warning: Production host separation The managed IdP (
https://1pass.dev) splits the OAuth/OIDC endpoints ontoapi.1pass.devand the console / developer portal ontostart.1pass.dev. If you want the same host separation in your self-hosted production, set upLOGI_API_HOSTplus the console host environment variables separately; if you'd rather run everything on a single host, point them all at the same domain and the host_constraint simply passes through (in development/test environments, it automatically runs on a single host).
Setup
Source access is provided during onboarding/partnership — contact
support@1pass.dev. Replace<your-logi-repo>below with the repository URL you receive.
git clone <your-logi-repo>
cd logi
bundle install
bin/rails db:setup
bin/rails serverThe server runs at http://localhost:3000. A separate worker process isn't needed in development, since SolidQueue runs inside puma.
💡 Tip: Containers / Helm The repository includes
server/Dockerfilefor production builds, so you can build and operate your own image. Official distribution through a container image registry, docker-compose, and Helm charts is not packaged yet. During the alpha period, use the directbundle install+bin/railsflow above or a Docker image you build yourself.
Registering your first OAuth app (local)
In a self-hosted environment, every quickstart command works against $LOGI=http://localhost:3000.
1) Create a developer account and sign in
export LOGI="http://localhost:3000"
curl -s -c /tmp/cookies.txt -X POST "$LOGI/developer/signup" \
-H 'Content-Type: application/json' \
-d '{"user": {"email_address": "dev@example.com", "password": "correctHorseBatteryStaple"}}'2) Issue a Personal API Key
/api/v1/applications uses PAK (Personal API Key) Bearer authentication. Issue a PAK once using the session cookie:
curl -s -b /tmp/cookies.txt -X POST "$LOGI/api/v1/me/api_keys" \
-H 'Content-Type: application/json' \
-d '{
"name": "Quickstart CLI",
"scopes": ["apps:manage", "apps:read"]
}' | tee /tmp/pak.json
PAK=$(python3 -c 'import json; print(json.load(open("/tmp/pak.json"))["plaintext"])')3) Register the OAuth app
curl -s -X POST "$LOGI/api/v1/applications" \
-H "Authorization: Bearer $PAK" \
-H 'Content-Type: application/json' \
-d '{
"application": {
"name": "My Local App",
"redirect_uris": ["http://localhost:4000/auth/callback"],
"allowed_scopes": ["profile:basic", "email"]
}
}' | tee /tmp/app.json
CLIENT_ID=$(python3 -c 'import json; print(json.load(open("/tmp/app.json"))["client_id"])')
CLIENT_SECRET=$(python3 -c 'import json; print(json.load(open("/tmp/app.json"))["client_secret"])')You can also create it with a form on the web portal (http://localhost:3000/developer/applications/new).
4) Sign up a test end user
curl -s -c /tmp/user-cookies.txt -X POST "$LOGI/signup" \
-H 'Content-Type: application/json' \
-d '{"user": {"email_address": "user@example.com", "password": "correctHorseBatteryStaple", "device_uuid": "demo-device-1"}}'From here, follow steps 4–7 of the Quickstart (PKCE → authorize → token → userinfo) as-is, but adjust the environment variables to your self-hosted values:
export LOGI="http://localhost:3000"
export CLIENT_ID="logi_..." # the value from step 3) above
export CLIENT_SECRET="..." # the value from step 3) above
export REDIRECT="http://localhost:4000/auth/callback"Operational considerations
Additional items to review when you self-operate:
- Webhook signing key rotation — key expiry and rotation cadence
- Threat Model — Account Merge — the merge attack surface
- Rate Limits — the Redis-based limiting policy
- Refresh Token policy — handling Apple/Google rotation
When you need help
For installation issues, use GitHub Issues; for operational discussions, please contact us through the admin contact channel (FAB).