Skip to main content

Security Best Practices

Production security configuration for Zeq OS deployments.

API Authentication

The API Gateway requires API keys for authenticated endpoints:

# Generate a secure API key
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Set in .env
ZEQ_API_KEYS=your_generated_key_here

All authenticated requests must include the X-API-Key header:

# Authenticated request
curl -H "X-API-Key: $ZEQ_API_KEY" http://localhost:4000/api/v1/operators/all

# Without key → 401 Unauthorized
curl http://localhost:4000/api/v1/operators/all

Multiple keys can be comma-separated for key rotation:

ZEQ_API_KEYS=current_key_abc123,previous_key_def456

Secret Generation

Use the provided script to generate all secrets automatically:

./scripts/generate-secrets.sh

This generates cryptographically secure values for:

  • JWT_SECRET — 64-character base64 session token
  • ZEQ_MI_JWT_SECRET — 64-character hex for Zeq MI auth
  • ZEQ_MI_CREDS_KEY — 32-character hex encryption key
  • ZEQ_MI_CREDS_IV — 16-character hex initialization vector
  • ZEQ_API_KEYS — 64-character hex API gateway key
  • DISCOURSE_DB_PASSWORD — 32-character hex database password
  • RAG_DB_PASSWORD — 32-character hex for PGVector

Run with --force to regenerate existing secrets:

./scripts/generate-secrets.sh --force

CORS Configuration

Configure allowed origins for your domain:

# .env
DOMAIN=https://zeq.hulyas.org
ALLOWED_ORIGINS=https://zeq.hulyas.org

For development with multiple origins:

ALLOWED_ORIGINS=http://localhost,http://localhost:3000,http://localhost:3002

Never use * in production.

Rate Limiting

The API Gateway enforces per-IP rate limiting:

# .env — requests per minute per IP
RATE_LIMIT_RPM=100

nginx adds a secondary rate limit layer:

API endpoints:     10 requests/second (burst 20)
General traffic: 30 requests/second

Exceeding the limit returns 429 Too Many Requests.

SSL / TLS

Let's Encrypt Setup

  1. Set your domain and email in .env:
DOMAIN=https://zeq.hulyas.org
SSL_EMAIL=admin@hulyas.org
  1. Run certbot for initial certificate:
docker run -it --rm \
-v letsencrypt_data:/etc/letsencrypt \
-v certbot_webroot:/var/www/certbot \
certbot/certbot certonly \
--webroot -w /var/www/certbot \
-d zeq.hulyas.org \
--email admin@hulyas.org \
--agree-tos --no-eff-email
  1. nginx is pre-configured with modern TLS settings:
Protocols:     TLSv1.2, TLSv1.3
Ciphers: ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-GCM-SHA256, ...
HSTS: max-age=63072000; includeSubDomains; preload
Session cache: shared:SSL:10m
  1. Set up auto-renewal via cron:
0 3 * * * docker run --rm -v letsencrypt_data:/etc/letsencrypt certbot/certbot renew --quiet

Environment Variables

Required for Production

VariablePurposeGenerate With
JWT_SECRETSession tokensgenerate-secrets.sh
ZEQ_API_KEYSAPI authenticationgenerate-secrets.sh
ZEQ_MI_JWT_SECRETZeq MI authgenerate-secrets.sh
DOMAINCORS, routingSet manually

HITE / TESC (Optional — graceful degradation when empty)

VariableServicePurpose
ZEQ_HITE_SECRETAPI GatewayHITE encrypted HTTP channel key derivation
ZEQ_SYNC_SECRETSync EngineTESC PLAT generation secret
ZEQ_SYNC_UIDSync EngineServer identity in PLATs (default: genesis-node)

Required for AI Features

VariablePurposeSource
DEEPSEEK_API_KEYDeepSeek LLMdeepseek.com
OPENAI_API_KEYOpenAI / embeddingsopenai.com
FIREWORKS_API_KEYFireworks AIfireworks.ai

Optional

VariableDefaultPurpose
RATE_LIMIT_RPM100API rate limit
LOG_LEVELinfoLogging verbosity
SSL_EMAILLet's Encrypt registration

HITE Encryption Recommendations

  • Minimum passphrase length: 12 characters
  • PBKDF2 iterations: 100,000 (default — do not reduce)
  • Entropy collection: Collect full 256 bits before encrypting
  • File size limit: 100MB recommended (browser memory constraints)
  • Memory zeroization: Always enabled (HRO00 — 7-pass overwrite)
  • API Gateway: Set ZEQ_HITE_SECRET to enable encrypted HTTP channels. Sessions expire after 1 hour.
  • Session key: Derived via PBKDF2 from the shared secret and handshake nonces — unique per session

TESC Deployment

  • Clock synchronization: Ensure server clocks are NTP-synced (drift > 1 Zeqond = rejected messages)
  • PLAT window: 0.777s is strict — high-latency connections may need the ±1 Zeqond drift tolerance
  • Channel secrets: Use strong, unique secrets per channel (32+ characters)
  • Session rotation: Rotate channel secrets periodically
  • Sync Engine: Set ZEQ_SYNC_SECRET to enable chained PLAT attestation on tick broadcasts
  • Chain verification: Clients should verify the chain hash included in each tick to detect tampering

Database Security

  • Change default passwords in .env (never use mypassword in production)
  • MongoDB: Not exposed on public ports (internal Docker network only)
  • Redis: Internal network only, no authentication by default
  • PostgreSQL: Strong password via DISCOURSE_DB_PASSWORD and RAG_DB_PASSWORD

Operator Access Control

Operators use a tiered access model that protects intellectual property while allowing public discovery:

Public (No Auth Required)

Unauthenticated users can browse the operator catalog with metadata:

# Returns: id, name, description, category, tier, tierLabel
# Does NOT include: equation, equationLaTeX, founder
curl http://localhost:8080/api/zeq/operators

Authenticated (Bearer Token Required)

Authenticated users see full operator details including equations:

# Returns all fields including equations and founder attribution
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/zeq/operators

# Execute operators (auth required)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"params":{"x":1}}' \
http://localhost:8080/api/zeq/operators/execute?operator=KO1

# Live state (auth required)
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/zeq/state/live

Protected Endpoints

EndpointAuthReturns
GET /api/zeq/operatorsOptionalCatalog (equations only with auth)
GET /api/zeq/operators/:idOptionalDetails (equations only with auth)
POST /api/zeq/operators/executeRequiredComputed result
GET /api/zeq/state/liveRequiredAll live operator values
GET /api/zeq/operators/:id/liveRequiredSingle live value
POST /api/7step/parseRequiredParsed intent
POST /api/7step/runRequiredComputation result
POST /api/7step/strictRequiredStrict computation result

Operator Sandboxing

Operators in the registry are mathematical functions — they do not execute arbitrary code. The API server:

  • Validates operator IDs against the registry before processing
  • Enforces the 4-operator limit per computation (KO42 + up to 3 additional)
  • Rejects unknown operator IDs with 404 Not Found
  • Rate-limits operator queries per IP
  • All computation runs server-side — equations are never shipped in the browser bundle

Health Monitoring

All services expose health endpoints:

curl http://localhost/nginx-health          # nginx
curl http://localhost:4000/health # API Gateway
curl http://localhost:4001/health # Sync Engine
curl http://localhost:3080/api/health # Zeq MI
curl http://localhost:3000/api/v1/version # Zeq Git
curl http://localhost:2871/health # Zeqond Daemon

Verify Landauer headers are present:

curl -sI http://localhost:4000/health | grep X-Zeq-Landauer
# X-Zeq-Landauer-Energy: 3.324e+56
# X-Zeq-Landauer-Suns-Required: 2.770e+12
# X-Zeq-Landauer-Bits: 256

Verify TESC is active on the Sync Engine:

curl -s http://localhost:4001/health | python3 -m json.tool | grep tesc
# "tesc_enabled": true

Use ./scripts/deploy-prod.sh status for a complete health check.