Installation & First Run
Step-by-step guide to deploy Sorcha using Docker Compose.
Production Pre-Flight Checklist
The default compose is a development deployment. Every item below is a known gap between the shipped configuration and a production-ready installation. These are tracked for the v1 hardening milestone. Do not skip them.
| # | Risk | What the default does | What to do for production |
|---|---|---|---|
| 1 | Shared JWT signing key | .env.example ships a concrete Base64 key (c29yY2hh...). Any deployment that copies .env.example without replacing this value shares the same secret as every other default deployment. | Generate a unique 256-bit key per deployment (see Step 2). See JWT & Authentication. |
| 2 | Development database passwords | .env.example uses sorcha_dev_password for both PostgreSQL and MongoDB. | Replace POSTGRES_PASSWORD and MONGO_INITDB_ROOT_PASSWORD in .env before first start. See Databases. |
| 3 | ASPNETCORE_ENVIRONMENT per-service override required | Seven services hardcode ASPNETCORE_ENVIRONMENT: Development directly in the compose service blocks. Setting ASPNETCORE_ENVIRONMENT once in .env does not override these per-service values — each service block must be individually overridden in a production compose override file. Affected services: blueprint-service, register-service, tenant-service, peer-service, validator-service, sorcha-ui-web, api-gateway. (wallet-service and haip-service ship as Docker, not Development.) | Create a compose override file (e.g. docker-compose.prod.yml) and add ASPNETCORE_ENVIRONMENT: Production under each affected service's environment block. See Scaling & High Availability for overlay patterns. |
| 4 | Redis has no password | Redis is started without --requirepass. Setting REDIS_PASSWORD in .env is not sufficient — the compose does not pass --requirepass to the redis-server command. | Override the Redis command in a production compose overlay to add --requirepass ${REDIS_PASSWORD} and add REDIS_PASSWORD to all service connection strings. See Redis. |
| 5 | gRPC peer TLS disabled | PeerService__EnableTls: "false" is set on peer-service. The API gateway also serves HTTP on port 80 by default (TLS termination is expected to be handled by an upstream reverse proxy such as Caddy). | For internet-exposed peer nodes, configure TLS at the reverse-proxy layer (see docker-compose.n1.yml / docker-compose.ports.yml for the Caddy-with-port-offset pattern). |
| 6 | Admin-verified user creation is enabled | Platform__AllowAdminVerifiedUserCreation: "true" is set on tenant-service. This allows a SystemAdmin to provision pre-verified org-scoped users, bypassing email verification. It is intentionally on for local dev and walkthroughs. | Remove or set to "false" in your production override. This is a correctness gate — leaving it enabled in production undermines the verification audit trail. |
These six items are the minimum pre-flight for a production or publicly accessible deployment. Detailed remediation for each is in Configuration Reference.
Installation Flow
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
│ Clone & │────>│ Configure │────>│ docker │
│ Install │ │ .env │ │ compose up │
└─────────────┘ └─────────────┘ └──────┬───────┘
│
┌──────v───────┐
│ Bootstrap │
│ & Verify │
└──────────────┘Step 1: Clone the Repository
git clone https://github.com/your-org/sorcha.git
cd sorchaStep 2: Configure Environment
Copy the example environment file and customize it:
cp .env.example .envEdit .env with your preferred editor. Key variables to set:
| Variable | Purpose | Action |
|---|---|---|
INSTALLATION_NAME | JWT issuer identity | Set to your domain (e.g., sorcha.example.com) |
JWT_SIGNING_KEY | Token signing key | Generate a new 256-bit key (see below) |
POSTGRES_PASSWORD | PostgreSQL password | Change from default |
MONGO_PASSWORD | MongoDB password | Change from default |
OPENAPI_REQUIRE_AUTH | Lock down API docs | Set true for production |
Generate a JWT Signing Key
The JWT signing key must be a Base64-encoded 256-bit (32-byte) value:
# Linux/macOS
openssl rand -base64 32
# PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }) -as [byte[]])Copy the output into JWT_SIGNING_KEY in your .env file.
Important: All services must share the same JWT_SIGNING_KEY and INSTALLATION_NAME. These are distributed automatically via the x-jwt-env anchor in docker-compose.yml.
Step 3: Start Services
docker-compose up -dExpected startup sequence (services start in dependency order):
- Infrastructure (Redis, PostgreSQL, MongoDB, Aspire Dashboard) -- ~10s
- Wallet Service -- depends on Redis, PostgreSQL
- Tenant Service -- depends on Redis, PostgreSQL, Wallet
- Register Service -- depends on Redis, MongoDB, Wallet, Tenant
- Validator Service -- depends on Redis, MongoDB, Wallet, Tenant
- Peer Service -- depends on Redis, MongoDB
- Blueprint Service -- depends on all core services
- UI Web -- depends on Aspire Dashboard
- API Gateway -- depends on all services (starts last)
Full startup typically takes 60-90 seconds. Monitor progress:
# Watch container status
docker-compose ps
# Follow startup logs
docker-compose logs -f
# Watch a specific service
docker-compose logs -f api-gatewayStep 4: Verify Health Checks
Wait for all services to report healthy, then verify:
# API Gateway health
curl http://localhost/health
# Individual service health (via gateway)
curl http://localhost/blueprint/health
curl http://localhost/tenant/health
curl http://localhost/register/health
curl http://localhost/wallet/health
curl http://localhost/validator/health
curl http://localhost/peer/healthEach endpoint should return HTTP 200 with status Healthy.
Check All Containers
docker-compose psAll containers should show Up with (healthy) status. If any container is in a restart loop, check its logs:
docker-compose logs <service-name>Step 5: Bootstrap -- First Admin Account
On first startup, the Tenant Service automatically creates:
- A default organization: Sorcha Local (
sorcha-local) - A default admin user:
admin@sorcha.local/Dev_Pass_2025! - Service principal accounts for inter-service authentication
Log In
curl -X POST http://localhost/tenant/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@sorcha.local",
"password": "Dev_Pass_2025!"
}'The response includes a JWT access_token. Save this for subsequent API calls.
Change the Default Password
Important: Change the default admin password immediately after first login.
Password rotation is a step-up operation (Feature 116): you must complete a fresh re-authentication challenge and present the resulting one-shot token in the X-Auth-Challenge header. The change request body carries only the new password (current-password proof happens in the challenge, not the body).
# 1. Begin a challenge for the ChangePassword operation
curl -X POST http://localhost/api/auth/challenge/initiate \
-H "Content-Type: application/json" -H "Authorization: Bearer <your-token>" \
-d '{ "operation": "ChangePassword" }'
# 2. Verify it (prove the current password) — returns a one-shot challenge token
curl -X POST http://localhost/api/auth/challenge/verify \
-H "Content-Type: application/json" -H "Authorization: Bearer <your-token>" \
-d '{ "challengeId": "<from step 1>", "password": "Dev_Pass_2025!" }'
# 3. Rotate the password (204 No Content on success)
curl -X POST http://localhost/api/auth/password/change \
-H "Content-Type: application/json" -H "Authorization: Bearer <your-token>" \
-H "X-Auth-Challenge: <token from step 2>" \
-d '{ "password": "YourSecurePassword123!" }'See Authentication Setup for the full challenge flow.
Step 6: Fix Wallet Encryption Permissions
On fresh installations, the wallet encryption key volume may have incorrect ownership. Fix this before creating wallets:
# Linux/macOS
./scripts/fix-wallet-encryption-permissions.sh
# Windows (PowerShell)
./scripts/fix-wallet-encryption-permissions.ps1
# Or manually
docker run --rm -v sorcha_wallet-encryption-keys:/data alpine chown -R 1654:1654 /dataStep 7: Verification Checklist
Confirm the installation is working:
- [ ] All containers are running and healthy:
docker-compose ps - [ ] API Gateway responds:
curl http://localhost/health - [ ] OpenAPI documentation loads: open
http://localhost/openapiin a browser - [ ] Admin login succeeds (see Step 5)
- [ ] Aspire Dashboard is accessible:
http://localhost:18888 - [ ] UI loads:
http://localhost/app
System Register
The System Register provides a shared ledger for platform-level governance data (blueprints, policies). It bootstraps automatically on first startup -- no environment variable is needed. The register service creates the well-known system register and seeds default blueprints idempotently.
To verify bootstrap succeeded, check the register service logs or query:
curl http://localhost:5380/api/system-registerOptional: Aspire AppHost Mode (Development)
For local development with full debugging support, you can run services directly via .NET Aspire instead of Docker:
# Requires .NET 10 SDK
dotnet run --project src/Apps/Sorcha.AppHostThis starts all services on HTTPS ports (7000-7290) with the Aspire Dashboard at http://localhost:18888. See Port Configuration for the full port mapping.
Next Steps
- Configuration Reference -- Tune environment variables
- Monitoring & Observability -- Set up dashboards and alerts
- Administration -- Create organizations and users
- Security Hardening -- Production security steps