Skip to main content

Deployment

Deploying the Identivia stack using Docker Compose is straightforward. This guide assumes you have Docker and Docker Compose installed on your system.

Prerequisites

Docker Compose Configuration

Create a docker-compose.yml file with the following content:

services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
command:
- --api.dashboard=true
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN}`)
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=letsencrypt

pocketbase:
image: ghcr.io/muchobien/pocketbase
container_name: pocketbase
restart: unless-stopped
command:
- --encryptionEnv
- PB_ENCRYPTION_KEY
environment:
- PB_ENCRYPTION_KEY=${PB_ENCRYPTION_KEY}
- POCKETBASE_ADMIN_EMAIL=${POCKETBASE_ADMIN_EMAIL}
- POCKETBASE_ADMIN_PASSWORD=${POCKETBASE_ADMIN_PASSWORD}
volumes:
- ./pb_data:/pb_data
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:8090/api/health || exit 1
interval: 5s
timeout: 5s
retries: 5
labels:
- traefik.enable=true
- traefik.http.routers.pocketbase.rule=Host(`pocketbase.${DOMAIN}`)
- traefik.http.routers.pocketbase.entrypoints=websecure
- traefik.http.routers.pocketbase.tls.certresolver=letsencrypt
- traefik.http.services.pocketbase.loadbalancer.server.port=8090

admin-portal:
image: ghcr.io/identivia/admin-portal:latest
container_name: admin-portal
restart: unless-stopped
environment:
- POCKETBASE_PROXY_URL=${POCKETBASE_PUBLIC_URL}
depends_on:
pocketbase:
condition: service_healthy
labels:
- traefik.enable=true
- traefik.http.routers.admin-portal.rule=Host(`admin.${DOMAIN}`)
- traefik.http.routers.admin-portal.entrypoints=websecure
- traefik.http.routers.admin-portal.tls.certresolver=letsencrypt
- traefik.http.services.admin-portal.loadbalancer.server.port=80

web-app:
image: ghcr.io/identivia/web-app:latest
container_name: web-app
restart: unless-stopped
environment:
- VITE_FINGERPRINT_PUBLIC_KEY=${VITE_FINGERPRINT_PUBLIC_KEY}
- VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL}
- VITE_DOMAIN_URL=${VITE_DOMAIN_URL}
depends_on:
pocketbase:
condition: service_healthy
backend-api:
condition: service_started
labels:
- traefik.enable=true
- traefik.http.routers.web-app.rule=Host(`app.${DOMAIN}`)
- traefik.http.routers.web-app.entrypoints=websecure
- traefik.http.routers.web-app.tls.certresolver=letsencrypt
- traefik.http.services.web-app.loadbalancer.server.port=80

backend-api:
image: ghcr.io/identivia/backend-api:latest
container_name: backend-api
restart: unless-stopped
environment:
- POCKETBASE_URL=${POCKETBASE_INTERNAL_URL}
- PB_USER_EMAIL=${POCKETBASE_ADMIN_EMAIL}
- PB_USER_PASSWORD=${POCKETBASE_ADMIN_PASSWORD}
- AWS_REGION=${AWS_REGION}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- FACE_LIVENESS_THRESHOLD=${FACE_LIVENESS_THRESHOLD}
- OPENAI_MODEL=${OPENAI_MODEL}
- OPENAI_API_KEY=${OPENAI_API_KEY}
- FINGERPRINT_SECRET_KEY=${FINGERPRINT_SECRET_KEY}
- CLIENT_URL=${CLIENT_URL}
depends_on:
pocketbase:
condition: service_healthy
labels:
- traefik.enable=true
- traefik.http.routers.backend-api.rule=Host(`api.${DOMAIN}`)
- traefik.http.routers.backend-api.entrypoints=websecure
- traefik.http.routers.backend-api.tls.certresolver=letsencrypt
- traefik.http.services.backend-api.loadbalancer.server.port=3000

Configuration

Create a .env file in the same directory as your docker-compose.yml and add your environment variables:

# Traefik
DOMAIN=identivia.com
ACME_EMAIL=admin@identivia.com

# PocketBase
PB_ENCRYPTION_KEY=your_secret_encryption_key
POCKETBASE_ADMIN_EMAIL=admin@example.com
POCKETBASE_ADMIN_PASSWORD=changeme

# Admin Portal
POCKETBASE_PUBLIC_URL=https://pocketbase.identivia.com

# Web App
VITE_FINGERPRINT_PUBLIC_KEY=your_fingerprint_public_key
VITE_BACKEND_API_URL=https://api.identivia.com
VITE_DOMAIN_URL=identivia.com

# Backend API
POCKETBASE_INTERNAL_URL=http://pocketbase:8090
JWT_SECRET=replace_with_a_long_random_secret
JWT_ISSUER=identivia-backend
JWT_AUDIENCE=identivia-api
JWT_TTL_SECONDS=3600
FLOW_TOKEN_TTL_SECONDS=1800
JWT_CLIENTS_JSON=[{"client_id":"partner-backend","client_secret":"replace-me","partner_id":"partner-backend","scopes":["profiles:write","profiles:read","health:read"]}]
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
FACE_LIVENESS_THRESHOLD=75
OPENAI_MODEL=o4-mini
OPENAI_API_KEY=your_openai_api_key
FINGERPRINT_SECRET_KEY=your_fingerprint_secret_key
CLIENT_URL=https://app.identivia.com

Service Details

  • Traefik: Modern reverse proxy and load balancer with automatic SSL via Let's Encrypt. Dashboard accessible at port 8080.
  • PocketBase: The backend database and authentication provider.
  • Admin Portal: Interface for managing the Identivia system. Uses an nginx reverse proxy to forward PocketBase API requests via POCKETBASE_PROXY_URL.
  • Web App: The main user-facing application. It uses a short-lived profile-scoped flow token embedded in the verification URL instead of a shared API secret.
  • Backend API: Internal API service for handling business logic, including AWS Rekognition face liveness, OpenAI document analysis, and Fingerprint device identification.

PocketBase Superuser

Once PocketBase is running, the default superuser credentials are:

FieldDefault Value
Emailadmin@identivia.com
Passwordadmin1234

You can access the PocketBase admin dashboard at https://pocketbase.${DOMAIN}/_/ to manage collections, users, and settings.

warning

Change the default superuser credentials immediately after your first login. Update POCKETBASE_ADMIN_EMAIL and POCKETBASE_ADMIN_PASSWORD in your .env file and restart the stack.

Authenticating to the Container registry

note

GitHub Packages only supports authentication using a personal access token (classic). For more information, see Managing your personal access tokens.

You need an access token to publish, install, and delete private, internal, and public packages.

You can use a personal access token (classic) to authenticate to GitHub Packages or the GitHub API. When you create a personal access token (classic), you can assign the token different scopes depending on your needs. For more information about packages-related scopes for a personal access token (classic), see About permissions for GitHub Packages.

To authenticate to a GitHub Packages registry within a GitHub Actions workflow, you can use:

  • GITHUB_TOKEN to publish packages associated with the workflow repository.
  • A personal access token (classic) with at least read:packages scope to install packages associated with other private repositories (GITHUB_TOKEN can be used if the repository is granted read access to the package. See Configuring a package's access control and visibility).

For more information, see Authenticating to the Container registry.

Running the Stack

To start all services, run:

docker-compose up -d

Check the logs to ensure everything started correctly:

docker-compose logs -f

Configuring Traefik

Unlike traditional reverse proxies, Traefik uses Docker labels for automatic service discovery and routing. The configuration is already defined in the docker-compose.yml file through labels on each service.

How Traefik Works

Traefik automatically detects services through Docker labels:

  • traefik.enable=true - Enables Traefik for this service
  • traefik.http.routers.<name>.rule=Host(...) - Defines the domain routing rule
  • traefik.http.routers.<name>.entrypoints=websecure - Uses HTTPS entrypoint
  • traefik.http.routers.<name>.tls.certresolver=letsencrypt - Enables automatic SSL
  • traefik.http.services.<name>.loadbalancer.server.port=<port> - Specifies the container port

Accessing the Dashboard

  1. Access the Traefik Dashboard: Open your browser and navigate to http://localhost:8080.
  2. The dashboard shows all detected services, routers, and their health status.
  3. No additional configuration is needed - services are automatically registered.

Default Routes

With the provided configuration, the following routes are automatically configured:

ServiceDomainDescription
PocketBasepocketbase.${DOMAIN}Backend database and auth
Admin Portaladmin.${DOMAIN}Admin interface
Web Appapp.${DOMAIN}Main user application
Backend APIapi.${DOMAIN}API service
Traefik Dashboardtraefik.${DOMAIN}Traefik admin dashboard

SSL Certificates

Traefik automatically obtains and renews SSL certificates from Let's Encrypt. Certificates are stored in ./letsencrypt/acme.json.

Note: Replace ${DOMAIN} with your actual domain (e.g., identivia.com) in the .env file. Ensure your DNS records point to your server.