Skip to main content

Environment Configuration

EvilTwin is configured entirely through environment variables loaded from a .env file. This document describes every variable, its type, its default value, and when you must change it.

Generating secrets

Never use default or guessable values for secrets. Generate them:

openssl rand -hex 32   # 64-character hex string — good for SECRET_KEY, CANARY_WEBHOOK_SECRET
openssl rand -hex 20 # For POSTGRES_PASSWORD

Configuration Principles

  • Defaults are safe for local development, not for production
  • Backend startup validation (via Pydantic Settings) will fail fast if a required value is missing
  • Optional integrations log their enabled/disabled state on startup
  • Never commit real secrets to git — .env is in .gitignore

Database

VariableTypeDefaultRequiredDescription
POSTGRES_HOSTstringpostgresNoPostgreSQL hostname (Docker service name in Compose)
POSTGRES_PORTint5432NoPostgreSQL port
POSTGRES_DBstringeviltwinNoDatabase name
POSTGRES_USERstringeviltwinNoDatabase user
POSTGRES_PASSWORDstringYesDatabase password — change before production

Authentication and JWT

EvilTwin uses JSON Web Tokens (JWT) for user authentication. These variables control how tokens are signed and when they expire.

VariableTypeDefaultRequiredDescription
SECRET_KEYstringYesThe HMAC secret used to sign all JWT tokens. Changing this invalidates all existing sessions. Generate with openssl rand -hex 32.
ALGORITHMstringHS256NoJWT signing algorithm. HS256 is secure for most deployments.
ACCESS_TOKEN_EXPIRE_MINUTESint30NoMinutes until an access token expires. Shorter = more secure but requires more refreshes.
REFRESH_TOKEN_EXPIRE_DAYSint7NoDays until a refresh token expires. Users must re-login after this period.
Rotating SECRET_KEY in production

If you rotate SECRET_KEY, all currently logged-in users will be immediately logged out — their tokens will fail signature verification. Plan rotations for maintenance windows and communicate to users.


CORS (Cross-Origin Resource Sharing)

CORS controls which web origins (domains) are allowed to make requests to the backend API. This matters when your frontend is served from a different domain than your backend.

VariableTypeDefaultRequiredDescription
CORS_ORIGINSstring (comma-separated URLs)http://localhost:5173NoAllowed frontend origins. In production, set this to your actual frontend domain, e.g. https://soc.example.com.

Example for production:

CORS_ORIGINS=https://soc.example.com,https://soc-backup.example.com
Do not use wildcard * in production

Setting CORS_ORIGINS=* allows any website to make requests to your API, which is a security risk. Always specify exact origins.


SDN and Threat Evaluation

VariableTypeDefaultRequiredDescription
RYU_REST_URLstringhttp://ryu:8080NoSDN controller REST API URL
HONEYPOT_IPstring10.0.2.10NoIP to redirect suspicious traffic to
REAL_NET_CIDRstring10.0.1.0/24NoYour real production network CIDR — used to avoid accidentally redirecting legitimate traffic
THREAT_REDIRECT_THRESHOLDint3NoMinimum threat level (0–4) that triggers SDN redirection. Lower = more aggressive.
SCORE_CACHE_TTLint300NoSeconds to cache threat scores before re-computing (reduces DB load)
MODEL_PATHstring/app/ai/model.pklNoPath to the trained ML model file

LLM / AI Assistant

EvilTwin can integrate with any OpenAI-compatible LLM API for natural language threat analysis. If these variables are not set, AI endpoints return 503 with {"available": false}.

VariableTypeDefaultRequiredDescription
LLM_API_KEYstringNoAPI key for the LLM provider (OpenAI, Anthropic via proxy, Ollama, etc.)
LLM_BASE_URLstringhttps://api.openai.com/v1NoBase URL of the OpenAI-compatible API
LLM_MODELstringgpt-4o-miniNoModel name to use for threat analysis
LLM_MAX_TOKENSint2000NoMaximum tokens per LLM response
LLM_TEMPERATUREfloat0.3NoResponse randomness (0.0 = deterministic, 1.0 = creative). 0.3 is good for analysis.

Using OpenAI (cloud):

LLM_API_KEY=sk-proj-...
LLM_BASE_URL=https://api.openai.com/v1
LLM_MODEL=gpt-4o-mini

Using Ollama (local, free):

LLM_API_KEY=ollama
LLM_BASE_URL=http://host.docker.internal:11434/v1
LLM_MODEL=llama3.2
Using Ollama for no-cost local AI

Ollama runs LLMs locally on your machine with no API costs. Install it, then ollama pull llama3.2, and use the URL above. Use host.docker.internal because Docker containers can't use localhost to reach the host machine.


Canary Webhooks

Canary tokens are unique tracked identifiers embedded in files or links. When triggered, they call back to EvilTwin's webhook endpoint.

VariableTypeDefaultRequiredDescription
CANARY_WEBHOOK_SECRETstringYesHMAC-SHA256 secret shared with your canary service. Used to verify that webhook requests came from the right source.
CANARY_WEBHOOK_TOLERANCE_SECONDSint300NoMaximum age of a webhook request (in seconds). Requests older than this are rejected to prevent replay attacks.

External Threat Intelligence

These variables enable enrichment of attacker IPs with geographic and reputation data. All are optional; if missing, enrichment is skipped gracefully.

VariableTypeDefaultRequiredDescription
IPINFO_TOKENstringNoIPInfo API token for country/ASN/VPN detection
ABUSEIPDB_API_KEYstringNoAbuseIPDB key for IP reputation scoring

Splunk Integration

VariableTypeDefaultRequiredDescription
SPLUNK_HEC_URLstringNoSplunk HTTP Event Collector endpoint URL
SPLUNK_HEC_TOKENstringNoSplunk HEC authentication token

When both are set, the backend forwards enriched session events to Splunk automatically.


Frontend Variables

These variables are used by the Vite-based React frontend (prefix VITE_ makes them available in browser code).

VariableTypeDefaultDescription
VITE_API_BASE_URLstringhttp://localhost:8000Backend API base URL
VITE_WS_URLstringws://localhost:8000/ws/alertsWebSocket URL for live alerts

In production, update these to your actual domain:

VITE_API_BASE_URL=https://api.soc.example.com
VITE_WS_URL=wss://api.soc.example.com/ws/alerts

Note: wss:// is WebSocket over HTTPS (encrypted), equivalent to https://. Always use wss:// in production.


Deployment Configuration Profiles

Local Development

# Minimal .env for local dev
POSTGRES_PASSWORD=devpassword
SECRET_KEY=dev_secret_key_not_for_production_12345678901234567890
CANARY_WEBHOOK_SECRET=dev_canary_secret
CORS_ORIGINS=http://localhost:5173
# Leave LLM vars unset to skip AI features, or set LLM_API_KEY for testing

Production

# Production .env — use real secrets
POSTGRES_PASSWORD=$(openssl rand -hex 20)
SECRET_KEY=$(openssl rand -hex 32)
CANARY_WEBHOOK_SECRET=$(openssl rand -hex 32)
CORS_ORIGINS=https://soc.example.com
VITE_API_BASE_URL=https://api.soc.example.com
VITE_WS_URL=wss://api.soc.example.com/ws/alerts

# LLM integration (optional but recommended)
LLM_API_KEY=sk-proj-...
LLM_MODEL=gpt-4o-mini

# Threat intelligence enrichment
IPINFO_TOKEN=your_token_here
ABUSEIPDB_API_KEY=your_key_here

# Optional: Splunk forwarding
SPLUNK_HEC_URL=https://splunk.example.com:8088/services/collector/event
SPLUNK_HEC_TOKEN=your_splunk_token

Startup Validation Checklist

Before starting the platform, verify these:

# 1. Required secrets are set
grep -E "POSTGRES_PASSWORD|SECRET_KEY|CANARY_WEBHOOK_SECRET" .env \
| grep -v "changeme\|your_" # Should print all 3 lines

# 2. Docker Compose can parse the configuration
docker compose config > /dev/null && echo "Config OK"

# 3. Validate the backend sees expected settings
curl -s http://localhost:8000/health | python3 -m json.tool

# 4. Check AI service status
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8000/ai/status