Self-Hosting & Deployment
The backend's container image, required external services, and the full environment-variable configuration surface for operators running their own instance.
This page documents what the ArmorIQ backend actually needs to run - its container image, its external dependencies, and its full environment-variable surface - so you can host it on your own infrastructure. It does not describe a specific Docker Compose or Kubernetes setup, because the backend repository does not ship one.
ArmorIQ's own hosted deployment runs on Google Cloud Run, built and migrated through Cloud Build. There is no production docker-compose.yml or Kubernetes manifest in the backend repository - only a Dockerfile and a local-development Docker Compose file for running OPA alongside Postgres during development. If you self-host, you are responsible for your own container orchestration, TLS termination, and secret management around the image and environment variables described below.
Container image
The backend ships a two-stage Dockerfile: a build stage that installs dependencies, generates the Prisma client, and compiles the NestJS app, and a slim runtime stage that copies only the compiled output and production dependencies. The runtime image:
- listens on port 8080 (
PORTenv var, defaults to 8080), - runs as a non-root user,
- starts with
node dist/main.js, - does not run database migrations on startup - migrations (
prisma migrate deploy) are expected to run as a separate step before you deploy a new image, against a Prisma-CLI-capable build (the runtime image strips dev dependencies including the Prisma CLI).
No global route prefix is set - routes are served directly at the paths documented in the API Reference, and Swagger UI is available at /api-docs outside production.
Required external services
| Service | Why it's required |
|---|---|
| PostgreSQL | Primary datastore via DATABASE_URL. Prisma manages the schema. |
| An OPA (Open Policy Agent) Policy Decision Point | Policy evaluation calls out to OPA_PDP_URL; the backend throws if this isn't configured when OPA evaluation is invoked. ArmorIQ's own deployment runs OPA as a sidecar container next to the backend; local development runs it via Docker Compose instead. |
| A Google Cloud project | Used for Cloud KMS (encrypting certificate private keys and other secrets at rest) and Certificate Authority Service (issuing certificates). Not required if you don't use the certificate feature. |
| SMTP | Transactional email - OTP verification, password reset, invitations. |
Two more services are optional depending on which features you enable: a CSRG service for building Merkle-verified reasoning graphs on intent plans, and a PAP gateway service for the pre-flight plan-refinement step described in Plans Governance.
Environment variables
These are grouped by the concern they configure. Values shown are the shipped example defaults, not requirements - set real values for anything you run in production.
Core
| Variable | Default | Notes |
|---|---|---|
PORT | 3000 | Container listens on 8080 in the shipped image |
NODE_ENV | development | |
APP_ENV | local | local | dev | staging | prod |
APP_NAME | ArmorIQ | |
FRONTEND_URL | - | Dashboard origin, used in emails and redirects |
CORS_ORIGIN | - | Allowed origin for browser requests |
CONMAP_AUTO_URL / CONMAP_AUTO_INTERNAL_URL | - | The backend's own public and internal URLs |
CONMAP_AUTO_API_KEY | - | Internal service-to-service key |
CONMAP_SCANNER_URL | - | URL of the separate MCP-scanning service used by Quick Scan and server scans |
NODE_TLS_REJECT_UNAUTHORIZED | 1 | Set to 0 only for local self-signed TLS; never in production |
Database
| Variable | Notes |
|---|---|
DATABASE_URL | Required. Postgres connection string. |
PGSSLMODE | Optional libpq SSL mode, e.g. require for a managed Postgres instance. |
Authentication and secrets
| Variable | Notes |
|---|---|
JWT_SECRET | Required. Signs dashboard session JWTs. |
ENCRYPTION_KEY | Required. 64-hex-char symmetric key for encrypting secrets at rest. |
PROXY_JWT_SECRET, PROXY_SECRET | Required if you run the separate enforcement proxy - shared secrets between it and the backend. |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_CALLBACK_URL | Optional, enables Google OAuth sign-in. |
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_CALLBACK_URL | Optional, enables GitHub OAuth sign-in. |
ALLOW_SELF_APPROVAL | false by default. Allows a user to approve their own delegation request from the dashboard - see the caveat in Plans Governance. |
Delegation and IAP
| Variable | Default | Notes |
|---|---|---|
DELEGATION_EXPIRY_SECONDS | 3600 | How long an unapproved delegation request stays valid |
IAP_MAX_DEFERRAL_DEPTH | 3 | Max nested deferrals before an intent plan is auto-blocked |
IAP_JWT_SECRET | - | Legacy HS256 signing secret for intent tokens; kept for verify-only backward compatibility |
IAP_TOKEN_ED25519_PRIVATE_KEY | - | PKCS#8 Ed25519 private key (PEM or base64) for signing intent tokens - see How It Works |
IAP_TOKEN_ED25519_PUBLIC_KEY | - | SPKI Ed25519 public key (PEM or base64); also served unauthenticated at GET /iap/public-key |
OPA policy engine
| Variable | Default | Notes |
|---|---|---|
OPA_PDP_URL | http://localhost:8181 | Required if OPA evaluation is enabled |
OPA_ENFORCE_MODE | strict | strict | permissive |
OPA_SHADOW_MODE | false | Log-only, does not enforce |
OPA_COMPILATION_ENABLED | false | |
OPA_TIMEOUT_MS / EXTERNAL_OPA_TIMEOUT_MS | 5000 / 10000 | |
OPA_BUNDLE_GCS_BUCKET, OPA_BUNDLE_PUBLISH_DIR | - | Optional, for publishing compiled OPA bundles |
GCP (certificates and KMS)
| Variable | Notes |
|---|---|
GCP_PROJECT_ID, GCP_LOCATION_ID | Project and region ArmorIQ uses for IAP's KMS key lookups |
GOOGLE_APPLICATION_CREDENTIALS | Path to a service-account JSON credential |
CERT_KMS_KEY_NAME | Not present in the shipped .env.example - set this yourself to encrypt certificate private keys at rest. See Certificates. |
CSRG / reasoning-graph service
| Variable | Default | Notes |
|---|---|---|
CSRG_ENABLED, CSRG_IAP_ENABLED | false | Enable the CSRG-backed reasoning graph and intent token |
CSRG_IAP_REQUIRED | false | Reject requests that lack a valid CSRG-issued token |
CSRG_IAP_URL | http://localhost:8771 | CSRG service URL |
CSRG_IAP_TIMEOUT_MS | 5000 |
PAP gateway
| Variable | Default | Notes |
|---|---|---|
PAP_GATEWAY_URL | http://127.0.0.1:8770 | Forwards the plan pre-flight refinement step to a separate PAP gateway service |
PAP_GATEWAY_API_KEY | - | Auth for that service |
Email (SMTP)
| Variable | Notes |
|---|---|
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM | Outbound mail transport |
SUPPORT_EMAIL | Displayed as the support contact |
EMAIL_SECRET_KEY | 64-hex-char secret for signing action links in emails |
Other
| Variable | Default | Notes |
|---|---|---|
OBLIGATION_STORE_BACKEND | memory | A Redis backend is referenced as planned but not implemented |
OBLIGATION_STORE_TTL_SECONDS | 3600 | |
TRUST_BROADCAST_ENABLED, TRUST_NOTIFY_CHANNEL | false | Optional trust-delta broadcast channel |
AUDIT_DRIFT_WORKER_ENABLED, AUDIT_DRIFT_WORKER_INTERVAL_MS, AUDIT_DRIFT_WORKER_BATCH | false / 60000 / 100 | Background audit-consistency worker |
HYBRID_TOKEN_ENABLED, HYBRID_TOKEN_WRITE_THROUGH | false | Dual JWT + API-key token mode |
AIQGRAPH_BACKEND_URL | - | Data source the AIQraph feature reads from - normally the backend's own URL |
DEFAULT_MCP_TARGET_URL, SMITHERY_API_KEY | - | Optional MCP tool-discovery configuration |
LLM_PROVIDER, LLM_MODEL, ANTHROPIC_API_KEY, OPENAI_API_KEY | - | Model provider for AI-assisted policy drafting and AIQraph chat |
Set all of these as real environment variables or secrets in your own infrastructure - ArmorIQ's own deployment injects them through Google Secret Manager rather than shipping an .env file to production.
Custom frameworks
Wrap any agent framework with ArmorIQ using the raw-client pattern. Concrete wiring for CrewAI, LangChain, OpenAI Assistants, and Anthropic tool-use - plus a template for anything else.
Audit Logs
Track all platform activity with filterable, searchable audit logs - categorized by source, severity, and time range.