./quickstart.sh --prodThis auto-generates all secrets, writes them to .env.production, starts in production mode, and prints a one-time admin password. Save the admin password — it won't be shown again.
1. Create environment file:
cp .env.production.example .env.production2. Generate secrets:
# JWT secret (64 characters)
python3 -c "import secrets; print(secrets.token_urlsafe(48))"
# Database / Redis / ClickHouse / Neo4j passwords
openssl rand -base64 32
# Gateway sensor token
openssl rand -base64 48
# JWT RS256 key pair (required in production — HS256 is rejected)
openssl genrsa -out jwt-private.pem 2048
openssl rsa -in jwt-private.pem -pubout -o jwt-public.pem3. Edit .env.production:
PHANTEX_ENVIRONMENT=production
PHANTEX_DEBUG=false
PHANTEX_JWT_SECRET=<generated-jwt-secret>
PHANTEX_JWT_ALGORITHM=RS256
PHANTEX_JWT_PRIVATE_KEY_FILE=/etc/phantex/jwt-private.pem
PHANTEX_JWT_PUBLIC_KEY_FILE=/etc/phantex/jwt-public.pem
PHANTEX_DB_PASSWORD=<generated-db-password>
PHANTEX_DB_ADMIN_PASSWORD=<generated-admin-password>
PHANTEX_DB_SSL_MODE=require
PHANTEX_REDIS_URL=redis://:<generated-redis-password>@redis:6379/0
PHANTEX_INTERNAL_TOKEN=<generated-internal-token>
PHANTEX_CORS_ORIGINS=["https://your-domain.com"]
PHANTEX_WS_LEGACY_TOKEN_ENABLED=false
PHANTEX_GRAPHQL_INTROSPECTION_ENABLED=false4. Start:
docker compose -f docker-compose.dev.yml -f docker-compose.prod.yml \
--env-file .env.production up -d- Generate a new token:
openssl rand -base64 48 - Add it to
gateway/gateway.yamlunderauth.tokens(map token → tenant ID) - Update the sensor's
PHANTEX_AUTH_TOKENenvironment variable or config file - Restart the gateway:
docker restart phantex-gateway - Restart the sensor (or it will reconnect with new token on next retry)
- Generate a new RSA key pair (see above)
- Mount the new keys into the backend container
- Update
PHANTEX_JWT_PRIVATE_KEY_FILEandPHANTEX_JWT_PUBLIC_KEY_FILE - Restart the backend — existing sessions using old tokens will be invalidated
- Connect to Postgres and change the password:
ALTER ROLE phantex_app WITH PASSWORD 'new-password'; - Update
PHANTEX_DB_PASSWORDin.env.production - Restart the backend and all workers
- Generate a new token:
openssl rand -base64 48 - Update
PHANTEX_INTERNAL_TOKENin.env.production - Update
backend.internal_tokeningateway/gateway.yaml - Restart both gateway and backend
The backend refuses to start in production if dev defaults remain. It validates:
| Check | Env Variable | Requirement |
|---|---|---|
| JWT secret | PHANTEX_JWT_SECRET |
Cannot be dev default |
| JWT algorithm | PHANTEX_JWT_ALGORITHM |
Must be RS256 or ES256 (HS256 rejected) |
| JWT key files | PHANTEX_JWT_PRIVATE_KEY_FILE |
Required for asymmetric signing |
| DB passwords | PHANTEX_DB_PASSWORD, PHANTEX_DB_ADMIN_PASSWORD |
Cannot be dev defaults |
| Debug mode | PHANTEX_DEBUG |
Must be false |
| CORS origins | PHANTEX_CORS_ORIGINS |
Cannot contain localhost |
| DB TLS | PHANTEX_DB_SSL_MODE |
Cannot be disable |
| GraphQL introspection | PHANTEX_GRAPHQL_INTROSPECTION_ENABLED |
Must be false |
| Redis URL | PHANTEX_REDIS_URL |
Cannot use dev password |
| Internal token | PHANTEX_INTERNAL_TOKEN |
Cannot be dev default |
| gRPC TLS | grpc.tls_enabled in gateway.yaml |
Must be true |
# Install with default values
helm install phantex infra/helm/ -n phantex --create-namespace
# Production with custom values
helm install phantex infra/helm/ \
-f infra/helm/values-prod.yaml \
-n phantex --create-namespace
# Staging / on-prem variants
helm install phantex infra/helm/ -f infra/helm/values-staging.yaml
helm install phantex infra/helm/ -f infra/helm/values-onprem.yaml# On a connected machine — bundle all images + charts
./packaging/airgap/bundle.sh
# On the air-gapped machine
./packaging/airgap/install.sh./upgrade.sh # 6-step automated upgrade
./upgrade.sh rollback # full state restorationThe upgrade flow: pre-flight checks → extract bundle → backup (7 components) → load images → migrate DB → deploy → health gate → auto-rollback on failure.