Skip to content

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.

#RiskWhat the default doesWhat to do for production
1Shared 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.
2Development 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.
3ASPNETCORE_ENVIRONMENT per-service override requiredSeven 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.
4Redis has no passwordRedis 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.
5gRPC peer TLS disabledPeerService__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).
6Admin-verified user creation is enabledPlatform__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

bash
git clone https://github.com/your-org/sorcha.git
cd sorcha

Step 2: Configure Environment

Copy the example environment file and customize it:

bash
cp .env.example .env

Edit .env with your preferred editor. Key variables to set:

VariablePurposeAction
INSTALLATION_NAMEJWT issuer identitySet to your domain (e.g., sorcha.example.com)
JWT_SIGNING_KEYToken signing keyGenerate a new 256-bit key (see below)
POSTGRES_PASSWORDPostgreSQL passwordChange from default
MONGO_PASSWORDMongoDB passwordChange from default
OPENAPI_REQUIRE_AUTHLock down API docsSet true for production

Generate a JWT Signing Key

The JWT signing key must be a Base64-encoded 256-bit (32-byte) value:

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

bash
docker-compose up -d

Expected startup sequence (services start in dependency order):

  1. Infrastructure (Redis, PostgreSQL, MongoDB, Aspire Dashboard) -- ~10s
  2. Wallet Service -- depends on Redis, PostgreSQL
  3. Tenant Service -- depends on Redis, PostgreSQL, Wallet
  4. Register Service -- depends on Redis, MongoDB, Wallet, Tenant
  5. Validator Service -- depends on Redis, MongoDB, Wallet, Tenant
  6. Peer Service -- depends on Redis, MongoDB
  7. Blueprint Service -- depends on all core services
  8. UI Web -- depends on Aspire Dashboard
  9. API Gateway -- depends on all services (starts last)

Full startup typically takes 60-90 seconds. Monitor progress:

bash
# Watch container status
docker-compose ps

# Follow startup logs
docker-compose logs -f

# Watch a specific service
docker-compose logs -f api-gateway

Step 4: Verify Health Checks

Wait for all services to report healthy, then verify:

bash
# 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/health

Each endpoint should return HTTP 200 with status Healthy.

Check All Containers

bash
docker-compose ps

All containers should show Up with (healthy) status. If any container is in a restart loop, check its logs:

bash
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

bash
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).

bash
# 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:

bash
# 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 /data

Step 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/openapi in 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:

bash
curl http://localhost:5380/api/system-register

Optional: Aspire AppHost Mode (Development)

For local development with full debugging support, you can run services directly via .NET Aspire instead of Docker:

bash
# Requires .NET 10 SDK
dotnet run --project src/Apps/Sorcha.AppHost

This 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

Released under the MIT License.