| Variable | Required | Default | Description |
|---|---|---|---|
| SECRET | Yes | $ecret.key |
HMAC signing/verification key. Must be changed in production |
| ALGORITHM | SHA-256 |
Hash algorithm: SHA-256, SHA-512, SHA-1 |
|
| PORT | 3000 |
API server port | |
| EXPIREMINUTES | 10 |
Challenge expiry in minutes. User must submit within this time | |
| COMPLEXITY | 1000000 |
PoW complexity. Higher values increase client browser computation time | |
| MAXRECORDS | 1000 |
Token reuse prevention cache size (memory/sqlite only, redis uses TTL) | |
| CORS_ORIGIN | * |
Allowed origins (comma-separated) | |
| RATE_LIMIT | 0 (unlimited) |
Requests per second per IP | |
| STORE | memory |
Token store: memory, sqlite, redis |
|
| SQLITE_PATH | data/altcha.db |
SQLite file path (when STORE=sqlite) | |
| REDIS_URL | redis://localhost:6379 |
Redis connection URL (when STORE=redis) | |
| REDIS_CLUSTER | false |
Use cluster mode when true (ElastiCache, Valkey, etc.) |
|
| LOG_LEVEL | info |
info: API logs only, debug: API + demo logs |
|
| TRUSTED_PROXY | Extract client IP from X-Forwarded-For header when set. Use behind a load balancer (NLB, ALB, etc.) |
||
| DEMO | false |
Start demo UI on port 8000 when true |
|
| POSTGRES_URL | PostgreSQL connection URL. Enables analytics when set | ||
| GEOIP_DB | Path to GeoLite2-Country.mmdb (optional, enables location stats) | ||
| DASHBOARD_PORT | 9000 |
Dashboard server port | |
| AUTH_PROVIDER | Dashboard auth method: basic or keycloak |
||
| AUTH_USERNAME | Basic auth username | ||
| AUTH_PASSWORD | Basic auth password | ||
| AUTH_ISSUER | Keycloak realm URL | ||
| AUTH_CLIENT_ID | OIDC client ID | ||
| AUTH_CLIENT_SECRET | OIDC client secret | ||
| AUTH_PKCE | true |
Enable PKCE |
- EXPIREMINUTES: Validity period (in minutes) for tokens generated by
/challenge. With the default of 10 minutes, users must submit within 10 minutes of receiving the challenge. Expired tokens are automatically rejected by/verify. - COMPLEXITY: Maximum number controlling PoW difficulty. The client browser must find the answer between 0 and this number. Higher values increase solving time, raising the cost for bot attacks, but also increase perceived delay for regular users.
- MAXRECORDS: How many verified tokens to remember. When the cache is full, the oldest entries are removed (FIFO). Redis store ignores this value as TTL handles automatic expiration.
.envfile in the project rootenvironmentsection incompose.yaml- Shell environment variables
Example .env:
SECRET=change-me-to-a-long-random-string
PORT=3000
EXPIREMINUTES=10
COMPLEXITY=1000000
MAXRECORDS=1000
STORE=memory
DEMO=falseThree storage backends are provided for token reuse prevention.
In-memory FIFO cache. Simplest option with no external dependencies.
- Cache is cleared on pod restart.
- Suitable for single-instance environments.
STORE=memory
MAXRECORDS=1000File-based persistent store. Data survives pod restarts or migrations when a PV (Persistent Volume) is mounted.
- Use when you need persistence with a single instance.
- Uses a pure Go driver (no CGO required).
STORE=sqlite
SQLITE_PATH=data/altcha.db
MAXRECORDS=1000Shared store. Multiple instances (pods) can share the same Redis for horizontal scaling.
- Uses
EXPIREMINUTESas TTL for automatic expiration. MAXRECORDSsetting is ignored (TTL handles cleanup).
Single node:
STORE=redis
REDIS_URL=redis://redis-host:6379Cluster (ElastiCache, Valkey, etc. with single endpoint):
STORE=redis
REDIS_URL=redis://cluster-endpoint:6379
REDIS_CLUSTER=trueCluster (multiple nodes, auto-detected):
STORE=redis
REDIS_URL=redis://node1:6379,redis://node2:6379,redis://node3:6379