---
title: "Deploy Pocket ID"
description: "Pocket ID 2.16 passkey-only OIDC provider for single sign-on."
category: "Authentication"
url: https://railway.com/deploy/pocket-id-4
---

# Deploy Pocket ID

Pocket ID 2.16 passkey-only OIDC provider for single sign-on.

**[Deploy Pocket ID on Railway](https://railway.com/template/pocket-id-4)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/pocket-id-4/manifest.json

- **Creator:** Agaz Self-Host
- **Category:** Authentication

## Template content

### pocketid https://raw.githubusercontent.com/pocket-id/pocket-id/v2.16.0/frontend/static/img/static-logo-512.png

- **Image:** ghcr.io/pocket-id/pocket-id:v2.16.0
- **Start command:** `sh -c '/app/docker/entrypoint.sh /app/pocket-id & pid=$!; trap "kill -TERM $pid; wait $pid; exit 0" TERM INT; W="busybox wget -q"; A=http://127.0.0.1:${PORT}/api; H="X-API-Key: $STATIC_API_KEY"; J="Content-Type: application/json"; ID=00000000-0000-4000-8000-00000000ad01; until $W -O /dev/null http://127.0.0.1:${PORT}/healthz 2>/dev/null; do kill -0 $pid 2>/dev/null || exit 1; sleep 2; done; if ! $W -O /dev/null --header "$H" $A/users/$ID 2>/dev/null; then $W -O /dev/null --header "$H" --header "$J" --post-data "{\"id\":\"$ID\",\"username\":\"$POCKET_ID_ADMIN_USERNAME\",\"email\":\"$POCKET_ID_ADMIN_EMAIL\",\"emailVerified\":true,\"firstName\":\"Admin\",\"displayName\":\"Admin\",\"isAdmin\":true}" $A/users && echo "pocket-id: admin $POCKET_ID_ADMIN_USERNAME created, initial setup closed"; fi; if [ "$($W -O- --header "$H" $A/users/$ID/webauthn-credentials 2>/dev/null)" = "[]" ]; then T=$($W -O- --header "$H" --header "$J" --post-data "{}" $A/users/$ID/one-time-access-token 2>/dev/null | sed -n "s/.*\"token\":\"\([^\"]*\)\".*/\1/p"); [ -n "$T" ] && echo "pocket-id: admin has no passkey yet; open within 1 hour to sign in once and add one: $APP_URL/lc/$T"; fi; wait $pid'`
- **Health check:** /healthz
- **Public domain:** Yes

## Documentation

# Deploy and Host Pocket ID on Railway

Pocket ID is a simple OpenID Connect provider that signs users in with passkeys instead of passwords. Apps that support OIDC, such as Grafana, Nextcloud, Immich, Portainer, Proxmox and your own services, delegate login to it, and users authenticate with Face ID, Windows Hello, a phone or a hardware security key.

## About Hosting Pocket ID

This template deploys Pocket ID v2.16.0 from the official image with SQLite on a Railway volume. Instead of leaving the initial setup page open to the first visitor, the start command creates the admin account through the API with a generated static API key. While the admin has no passkey, every start prints a one-time sign-in link, valid for one hour, to the deployment logs. Open it, add your passkey, then create OIDC clients for your apps. Pocket ID trusts Railway's proxy headers and fits the Hobby plan. Users sign in with passkeys only, so there are no passwords to leak or reset.

## Common Use Cases

- Passwordless single sign-on for self-hosted apps and internal tools
- An OIDC provider for your own applications and APIs
- Replacing shared passwords with passkeys for a small team

## Dependencies for Pocket ID Hosting

- `ghcr.io/pocket-id/pocket-id:v2.16.0` (official image)
- A Railway volume at `/app/data` for the database and uploads

### Deployment Dependencies

- [Pocket ID documentation](https://pocket-id.org/docs)
- [Pocket ID v2.16.0 release](https://github.com/pocket-id/pocket-id/releases/tag/v2.16.0)
- [Client examples](https://pocket-id.org/docs/client-examples)
- [Railway volumes](https://docs.railway.com/reference/volumes)

### Implementation Details

| Service | Image | Networking | Storage |
| --- | --- | --- | --- |
| pocketid | `ghcr.io/pocket-id/pocket-id:v2.16.0` | public domain on 1411 | volume at `/app/data` |

After deploying, open the deployment logs and look for:

```text
pocket-id: admin has no passkey yet; open within 1 hour to sign in once and add one: https:///lc/<code>
```

| Variable | Default | Purpose |
| --- | --- | --- |
| `POCKET_ID_ADMIN_USERNAME` / `POCKET_ID_ADMIN_EMAIL` | `admin` / `admin@example.com` | Admin account created on first start |
| `STATIC_API_KEY` | generated | Admin API key (header `X-API-Key`), also used by the bootstrap |
| `ENCRYPTION_KEY` | generated | Encrypts stored secrets; never change it |
| `APP_URL` | `https://` | Public URL and OIDC issuer |

Notes:

- If the link expired, redeploy to print a new one; the link stops appearing once a passkey exists.
- The static API key has admin rights; remove it after setup if you don't use the API.

This is a community-maintained deployment package and does not imply affiliation with or endorsement by the Pocket ID project or its maintainers.

## 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 are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
</code>

## 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-4
