---
title: "Deploy Pocket ID — Passkey-Only OIDC Provider"
description: "Self-host Pocket ID — passwordless passkey SSO for your apps"
category: "Authentication"
url: https://railway.com/deploy/pocket-id-passkey-oidc
---

# Deploy Pocket ID — Passkey-Only OIDC Provider

Self-host Pocket ID — passwordless passkey SSO for your apps

**[Deploy Pocket ID — Passkey-Only OIDC Provider on Railway](https://railway.com/template/pocket-id-passkey-oidc)**

- **Creator:** SilverBanana
- **Category:** Authentication

## Template content

### Pocket ID https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/pocket-id.png

- **Image:** ghcr.io/pocket-id/pocket-id
- **Public domain:** Yes

## Documentation

# Deploy and Host Pocket ID on Railway

Pocket ID is a simple, self-hosted OIDC provider built entirely around passkeys — no passwords, no TOTP codes, no external dependencies. Add single sign-on to your self-hosted services and sign in everywhere with a WebAuthn passkey or a hardware key like a YubiKey. It's the lightweight, passwordless alternative to heavier identity providers like Keycloak and Authentik, designed for people who want one modern login across their apps without running a complex platform. This template deploys it as a single container with the WebAuthn-critical settings handled.

---

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| **Pocket ID** | The passkey-based OIDC provider, admin UI, and API on port `1411` |

A single, lightweight Go container backed by SQLite — no external database to manage. Everything (the database, uploads, and GeoLite2 IP data) lives under one `/app/data` volume, so the whole identity provider is one service with one volume.

---

## About Hosting

Pocket ID is genuinely simple to run, but passkeys make one setting unusually strict — get it right and there's almost nothing else to configure.

**`APP_URL` must exactly match your browser-facing URL — passkeys depend on it.** Pocket ID puts `APP_URL` in three places: the OIDC issuer, the cookie domain, and — critically — the WebAuthn relying-party ID. Passkeys are cryptographically bound to that relying-party domain, so if `APP_URL` doesn't exactly match the URL users visit, **passkeys won't register or verify at all**, and because there are no passwords, there's no fallback. Set it to your exact Railway public domain before you run the first-time setup, and don't change it afterward.

**`TRUST_PROXY=true` is required on Railway, and HTTPS is mandatory.** WebAuthn only works in a secure (HTTPS) context, which Railway provides automatically. But Pocket ID runs behind Railway's proxy, so `TRUST_PROXY=true` must be set or it misreads the request protocol and origin, and passkey checks fail. This template sets it.

**Claim your admin passkey immediately — the setup page is first-come.** On first deploy, visit `/setup` and register your admin passkey right away. Whoever reaches `/setup` first becomes the administrator, so do this the moment the service is live, before the URL is exposed to anyone else.

**`ENCRYPTION_KEY` protects sensitive data — pin it.** Generate it with `openssl rand -base64 32` (at least 16 bytes), set it once, and keep it stable. Combined with the `/app/data` volume, that keeps your identity provider intact across redeploys.

Typical cost: **~$5/month** on Railway for the single lightweight container. Pocket ID is open source and free, and OpenID Connect Certified.

---

## How It Compares

| | Pocket ID (passkey-only) | Authentik / Keycloak | Auth0 / Okta | Password + TOTP apps |
| --- | --- | --- | --- | --- |
| Authentication | Passkeys only (WebAuthn) | Many methods | Many methods | Password + 2FA |
| Complexity | Very low | High | Managed | Varies |
| Passwordless | Fully | Optional | Optional | No |
| Dependencies | SQLite only | Postgres (+Redis) | Vendor | Varies |
| Best for | Homelab / simple SSO | Enterprise IdP | Managed SSO | Legacy auth |
| Self-hostable | Yes | Yes | No | Varies |

Authentik and Keycloak are powerful but heavy for a handful of services. Auth0 and Okta are managed and per-user priced. Pocket ID's niche is deliberate simplicity: a single-container, passkey-only OIDC provider that gives your self-hosted apps modern passwordless SSO without the operational weight — ideal for homelabs and small teams that just want one secure login.

---

## Deploy in Under 5 Minutes

1. Click **Deploy on Railway** — Pocket ID builds automatically (~2 minutes)
2. Set `APP_URL` to your exact Railway public domain (this is critical for passkeys)
3. Confirm `TRUST_PROXY=true`, `ENCRYPTION_KEY` is set, and the `/app/data` volume is mounted
4. Immediately visit `/setup` and register your admin passkey before anyone else can
5. In the admin UI, add OIDC clients for your services and point each app at Pocket ID's discovery URL

Each connected app gets an OIDC client with callback URLs; your users then sign in with a passkey.

---

## Common Use Cases

- **Unified homelab SSO** — one passkey login across Grafana, Immich, Nextcloud, Gitea, Proxmox, and other OIDC apps
- **Passwordless authentication** — eliminate passwords entirely using WebAuthn passkeys and hardware keys
- **YubiKey / hardware-key login** — sign in to all your services with a physical security key
- **Simple SSO without the weight** — get single sign-on without running Keycloak or a multi-service identity platform
- **Protect apps with no native auth** — pair with a proxy like OAuth2-Proxy to gate services that lack OIDC support

---

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `APP_URL` | Required | Your exact Railway public domain — used for OIDC issuer, cookies, and the WebAuthn relying party |
| `ENCRYPTION_KEY` | Required | Encrypts sensitive data — `openssl rand -base64 32` (≥16 bytes), keep stable |
| `TRUST_PROXY` | Required | `true` — required behind Railway's HTTPS proxy for correct origin handling |
| `MAXMIND_LICENSE_KEY` | Optional | For GeoLite2 IP data used in login location display |
| `PUID` / `PGID` | Optional | User/group IDs for the data volume if running non-root |

> **`APP_URL` must match exactly, or passkeys break.** It's baked into the WebAuthn relying-party ID, so a mismatch means passkeys won't register or verify — with no password fallback. Set it to your real Railway domain before first setup and keep it fixed.

> **Set `TRUST_PROXY=true` and claim `/setup` first.** WebAuthn needs the correct HTTPS origin, which requires trusting Railway's proxy. And whoever visits `/setup` first becomes admin — register your admin passkey the moment the service is live.

---

## Dependencies for Pocket ID Hosting

- Railway account — Hobby plan (~$5/month) runs the single container
- A persistent Railway volume mounted at `/app/data` (included)
- A passkey-capable device or hardware key (YubiKey, phone, laptop biometrics)
- OIDC-compatible apps to connect (most self-hosted services support OIDC)

### Deployment Dependencies

- [Pocket ID GitHub Repository](https://github.com/pocket-id/pocket-id)
- [Pocket ID Documentation](https://pocket-id.org/docs/)
- [Environment Variables Reference](https://pocket-id.org/docs/configuration/environment-variables)
- [Railway Volumes Documentation](https://docs.railway.com/volumes)

### Implementation Details

The template runs `ghcr.io/pocket-id/pocket-id` on port `1411` with a persistent volume at `/app/data`, which holds the SQLite database, uploads, and the GeoLite2 IP database — no external database is required. The app is a single Go binary, and Railway provides the automatic HTTPS that WebAuthn mandates.

`APP_URL` is the linchpin: Pocket ID writes it into the OIDC issuer identifier, the cookie domain, and the WebAuthn relying-party ID. Because passkeys are bound to the relying-party domain, `APP_URL` must exactly match the URL users load, or registration and verification fail with no password fallback. `TRUST_PROXY=true` is set so Pocket ID correctly derives the external HTTPS origin from Railway's proxy headers, and `ENCRYPTION_KEY` encrypts sensitive stored data and must remain stable across redeploys.

Administration is passkey-secured from the start: the first visitor to `/setup` registers the admin passkey and claims the instance, after which OIDC clients are added through the admin UI — each with a launch URL and callback URLs — and connected services authenticate against Pocket ID's OIDC discovery endpoint.

---

## Frequently Asked Questions

**Why must `APP_URL` be exact?** It's used as the WebAuthn relying-party ID, and passkeys are cryptographically bound to that domain. If `APP_URL` doesn't match the URL users visit, passkeys won't register or verify — and since there are no passwords, there's no way in. Set it correctly before first setup.

**What if I lose access to my passkey?** Register more than one passkey (e.g. a hardware key plus a device) so you have a backup. Since Pocket ID is passwordless, keeping a second passkey enrolled is the recovery path.

**Do I need a database?** No external one. Pocket ID uses SQLite stored on the `/app/data` volume, so it's a single container with a single volume — part of what makes it so simple.

**Why `TRUST_PROXY=true`?** Railway terminates HTTPS with a proxy in front of Pocket ID. WebAuthn needs the correct secure origin, so Pocket ID must trust the proxy's forwarded headers, or passkey checks fail.

**How do I connect my apps?** In the admin UI, add an OIDC client for each app with its callback URLs, then point the app at Pocket ID's OIDC discovery URL. Most self-hosted services (Grafana, Immich, Nextcloud, and more) support OIDC.

**Can I protect apps that don't support OIDC?** Yes, by pairing Pocket ID with an auth proxy like OAuth2-Proxy, which authenticates against Pocket ID and gates services that have no native OIDC support.

**Is it really passwordless?** Completely. Pocket ID supports only passkeys — WebAuthn/FIDO2 — so there are no passwords to store, phish, or leak. That's the entire point.

---

## Why Deploy Pocket ID on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Pocket ID on Railway you get modern passwordless SSO with the tricky parts solved — `APP_URL` and `TRUST_PROXY` set for WebAuthn, the `/app/data` volume for persistence, and automatic HTTPS. One passkey login across all your self-hosted services, on infrastructure you own.

## Similar templates

- [Keycloak](https://railway.com/deploy/mSwigX) — Keycloak template with keywind theme + apple and discord providers
- [lua-protector](https://railway.com/deploy/lua-protector) — Test deployed my project first
- [bknd](https://railway.com/deploy/p4nTYL) — Feature-rich yet lightweight backend

Open this page in a browser: https://railway.com/deploy/pocket-id-passkey-oidc
