Self-Hosting
Deploy Alphorn on your own infrastructure.
Alphorn is fully open source (AGPL-3.0-or-later) and designed to be self-hosted. You need a PostgreSQL database — that's the only external dependency.
Docker Compose (recommended)
The fastest way to get Alphorn running. The repository includes a ready-to-use docker-compose.yml — refer to it for the latest configuration.
Here's a minimal example:
services:
alphorn:
image: ghcr.io/alphorn-dev/alphorn:latest
ports:
- "3000:3000"
environment:
# PostgreSQL connection string
DATABASE_URL: postgres://alphorn:secret@db:5432/alphorn
# Generate with: openssl rand -base64 32
BETTER_AUTH_SECRET: your-secret-key
# Public URL where Alphorn will be accessible
BETTER_AUTH_URL: http://localhost:3000
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
environment:
POSTGRES_USER: alphorn
POSTGRES_PASSWORD: secret
POSTGRES_DB: alphorn
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U alphorn"]
volumes:
pgdata:docker compose up -dAlphorn is available at http://localhost:3000.
Podman
Podman is a drop-in replacement for Docker that runs rootless by default. The same compose file works with podman-compose or Podman's built-in podman compose:
podman compose up -dOr run the containers individually:
# Create a pod so containers can communicate
podman pod create --name alphorn -p 3000:3000
# Start PostgreSQL
podman run -d --pod alphorn --name alphorn-db \
-e POSTGRES_USER=alphorn \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=alphorn \
-v pgdata:/var/lib/postgresql/data \
postgres:18
# Start Alphorn
podman run -d --pod alphorn --name alphorn-app \
-e DATABASE_URL=postgres://alphorn:secret@localhost:5432/alphorn \
-e BETTER_AUTH_SECRET=your-secret-key \
-e BETTER_AUTH_URL=http://localhost:3000 \
ghcr.io/alphorn-dev/alphorn:latestAlphorn is available at http://localhost:3000.
Running from Source
Clone the repository and run directly:
git clone https://github.com/alphorn-dev/alphorn.git
cd alphorn/app
pnpm install
pnpm build
pnpm startMake sure you have a PostgreSQL instance running and set the required environment variables listed below.
Environment Variables
For the full list of environment variables, see the .env.example in the repository.
Required
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
BETTER_AUTH_SECRET | Secret key for session signing — generate with openssl rand -base64 32 |
BETTER_AUTH_URL | Public URL of your Alphorn instance |
SSO / OAuth (optional)
Alphorn supports social login and enterprise SSO. Set the relevant environment variables to enable a provider — if the variables are absent, the provider is simply not shown on the login page.
GitHub
| Variable | Description |
|---|---|
GITHUB_CLIENT_ID | OAuth App Client ID |
GITHUB_CLIENT_SECRET | OAuth App Client Secret |
Create an OAuth App at GitHub → Settings → Developer settings → OAuth Apps. Set the callback URL to {BETTER_AUTH_URL}/api/auth/callback/github.
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID | OAuth Client ID |
GOOGLE_CLIENT_SECRET | OAuth Client Secret |
Create credentials at Google Cloud Console → APIs & Services → Credentials → OAuth client ID (Web application). Add {BETTER_AUTH_URL}/api/auth/callback/google as an authorized redirect URI.
Microsoft
| Variable | Description |
|---|---|
MICROSOFT_CLIENT_ID | Application (client) ID |
MICROSOFT_CLIENT_SECRET | Client secret value |
MICROSOFT_TENANT_ID | Tenant ID — use common for any Microsoft account, organizations for work/school only, consumers for personal only, or a specific tenant GUID (default: common) |
Register an app in Azure Portal → App registrations. Under Redirect URIs, add a Web URI: {BETTER_AUTH_URL}/api/auth/oauth2/callback/microsoft-entra-id.
Generic OIDC (Keycloak, Okta, Azure AD, etc.)
Connect any OIDC-compliant identity provider.
| Variable | Required | Description |
|---|---|---|
OIDC_CLIENT_ID | Yes | OIDC Client ID (enables the provider) |
OIDC_CLIENT_SECRET | Yes | OIDC Client Secret |
OIDC_DISCOVERY_URL | Recommended | OIDC discovery endpoint (auto-configures URLs below) |
OIDC_AUTHORIZATION_URL | No | Manual authorization endpoint (if not using discovery) |
OIDC_TOKEN_URL | No | Manual token endpoint (if not using discovery) |
OIDC_USERINFO_URL | No | Manual userinfo endpoint (if not using discovery) |
OIDC_PROVIDER_ID | No | Custom provider identifier (default: custom-oidc) |
OIDC_PROVIDER_NAME | No | Display name on the login page (default: SSO) |
OIDC_SCOPES | No | Space-separated scopes (default: openid profile email) |
OIDC_PKCE | No | Enable PKCE (default: false) |
Architecture
Alphorn runs as a single process with two roles:
- Web — Serves the dashboard and API
- Worker — Processes notification delivery queue
Both run in the same container/process by default. For high-throughput deployments, you can scale them independently behind a load balancer.
Database
Alphorn uses PostgreSQL exclusively — no Redis, no MongoDB, no additional infrastructure. Database migrations run automatically on startup. All configuration and message history lives in the database — back it up regularly.
Supported versions
- PostgreSQL 14+
Updating
Pull the latest image and restart:
# Docker
docker compose pull
docker compose up -d
# Podman
podman compose pull
podman compose up -dDatabase migrations apply automatically.