Skip to main content

AWS / GCP / Azure

The auth backend is a stateless HTTP service. Any container hosting service runs it.

AWS Fargate

Dockerfile is included in the repo. Push to ECR:

aws ecr create-repository --repository-name auth-backend
docker build -t auth-backend .
docker tag auth-backend:latest <acct>.dkr.ecr.<region>.amazonaws.com/auth-backend:latest
docker push <acct>.dkr.ecr.<region>.amazonaws.com/auth-backend:latest

Task definition essentials:

{
"family": "auth-backend",
"networkMode": "awsvpc",
"containerDefinitions": [{
"name": "auth",
"image": "<acct>.dkr.ecr.<region>.amazonaws.com/auth-backend:latest",
"portMappings": [{ "containerPort": 4000 }],
"secrets": [
{ "name": "IDENTSPHERE_JWT_SECRET", "valueFrom": "arn:aws:secretsmanager:..." },
{ "name": "DATABASE_URL", "valueFrom": "arn:aws:secretsmanager:..." }
],
"environment": [
{ "name": "IDENTSPHERE_PUBLIC_BASE_URL", "value": "https://auth.example.com" },
{ "name": "IDENTSPHERE_COOKIES_SECURE", "value": "true" }
],
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:4000/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3
}
}]
}

Front with an ALB; terminate TLS at the ALB. RDS Postgres for the DB.

GCP Cloud Run

gcloud run deploy auth-backend \
--image gcr.io/<project>/auth-backend:latest \
--port 4000 \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars IDENTSPHERE_PUBLIC_BASE_URL=https://auth.example.com,IDENTSPHERE_COOKIES_SECURE=true \
--set-secrets IDENTSPHERE_JWT_SECRET=jwt-secret:latest,DATABASE_URL=db-url:latest \
--min-instances 1

--min-instances 1 avoids cold-start latency on first request. Cloud SQL Postgres for the DB.

Azure Container Apps

az containerapp create \
--name auth-backend \
--resource-group auth \
--image <registry>.azurecr.io/auth-backend:latest \
--target-port 4000 \
--ingress external \
--secrets jwt-secret=$(openssl rand -hex 32) db-url="..." \
--env-vars IDENTSPHERE_PUBLIC_BASE_URL=https://auth.example.com IDENTSPHERE_COOKIES_SECURE=true \
IDENTSPHERE_JWT_SECRET=secretref:jwt-secret DATABASE_URL=secretref:db-url

Azure Database for PostgreSQL Flexible Server for the DB.

Fly.io

fly.toml:

app = "auth-backend"
primary_region = "ord"

[build]
dockerfile = "Dockerfile"

[http_service]
internal_port = 4000
force_https = true
auto_stop_machines = false
min_machines_running = 1

[env]
IDENTSPHERE_PUBLIC_BASE_URL = "https://auth-backend.fly.dev"
IDENTSPHERE_COOKIES_SECURE = "true"

Set secrets:

fly secrets set IDENTSPHERE_JWT_SECRET=$(openssl rand -hex 32)
fly secrets set DATABASE_URL="postgres://..."
fly deploy

Fly Postgres or any external Postgres.

Railway

Add a Postgres plugin, then deploy from GitHub:

railway up
railway variables set IDENTSPHERE_JWT_SECRET=$(openssl rand -hex 32)
railway variables set IDENTSPHERE_COOKIES_SECURE=true
railway variables set IDENTSPHERE_PUBLIC_BASE_URL=https://your-app.up.railway.app

DATABASE_URL is auto-injected from the Postgres plugin.

Render

render.yaml:

services:
- type: web
name: auth-backend
runtime: docker
plan: starter
healthCheckPath: /health
envVars:
- key: IDENTSPHERE_PUBLIC_BASE_URL
value: https://auth-backend.onrender.com
- key: IDENTSPHERE_COOKIES_SECURE
value: 'true'
- key: IDENTSPHERE_JWT_SECRET
generateValue: true
- fromDatabase:
name: auth-db
property: connectionString
key: DATABASE_URL

databases:
- name: auth-db
plan: starter
postgresMajorVersion: 16

Sizing

TiervCPUMemoryPostgresConcurrent users
Dev0.25256 MiBShared~50
Small11 GiB1 vCPU / 4 GiB~5,000
Medium24 GiB2 vCPU / 8 GiB~50,000
Large48 GiB4 vCPU / 16 GiB + replicas~500,000

Argon2id is CPU-hungry on login; size your auth backend for password-hash throughput rather than QPS.

Next steps