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 tokenZEQ_MI_JWT_SECRET— 64-character hex for Zeq MI authZEQ_MI_CREDS_KEY— 32-character hex encryption keyZEQ_MI_CREDS_IV— 16-character hex initialization vectorZEQ_API_KEYS— 64-character hex API gateway keyDISCOURSE_DB_PASSWORD— 32-character hex database passwordRAG_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
- Set your domain and email in
.env:
DOMAIN=https://zeq.hulyas.org
SSL_EMAIL=admin@hulyas.org
- 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
- 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
- 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
| Variable | Purpose | Generate With |
|---|---|---|
JWT_SECRET | Session tokens | generate-secrets.sh |
ZEQ_API_KEYS | API authentication | generate-secrets.sh |
ZEQ_MI_JWT_SECRET | Zeq MI auth | generate-secrets.sh |
DOMAIN | CORS, routing | Set manually |
HITE / TESC (Optional — graceful degradation when empty)
| Variable | Service | Purpose |
|---|---|---|
ZEQ_HITE_SECRET | API Gateway | HITE encrypted HTTP channel key derivation |
ZEQ_SYNC_SECRET | Sync Engine | TESC PLAT generation secret |
ZEQ_SYNC_UID | Sync Engine | Server identity in PLATs (default: genesis-node) |
Required for AI Features
| Variable | Purpose | Source |
|---|---|---|
DEEPSEEK_API_KEY | DeepSeek LLM | deepseek.com |
OPENAI_API_KEY | OpenAI / embeddings | openai.com |
FIREWORKS_API_KEY | Fireworks AI | fireworks.ai |
Optional
| Variable | Default | Purpose |
|---|---|---|
RATE_LIMIT_RPM | 100 | API rate limit |
LOG_LEVEL | info | Logging verbosity |
SSL_EMAIL | — | Let'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_SECRETto 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_SECRETto 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 usemypasswordin 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_PASSWORDandRAG_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
| Endpoint | Auth | Returns |
|---|---|---|
GET /api/zeq/operators | Optional | Catalog (equations only with auth) |
GET /api/zeq/operators/:id | Optional | Details (equations only with auth) |
POST /api/zeq/operators/execute | Required | Computed result |
GET /api/zeq/state/live | Required | All live operator values |
GET /api/zeq/operators/:id/live | Required | Single live value |
POST /api/7step/parse | Required | Parsed intent |
POST /api/7step/run | Required | Computation result |
POST /api/7step/strict | Required | Strict 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.