QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.
1# QuickDID Configuration Reference
2
3This document provides a comprehensive reference for all configuration options available in QuickDID.
4
5## Table of Contents
6
7- [Required Configuration](#required-configuration)
8- [Network Configuration](#network-configuration)
9- [Caching Configuration](#caching-configuration)
10- [Queue Configuration](#queue-configuration)
11- [Rate Limiting Configuration](#rate-limiting-configuration)
12- [HTTP Caching Configuration](#http-caching-configuration)
13- [Metrics Configuration](#metrics-configuration)
14- [Proactive Refresh Configuration](#proactive-refresh-configuration)
15- [Jetstream Consumer Configuration](#jetstream-consumer-configuration)
16- [Static Files Configuration](#static-files-configuration)
17- [Configuration Examples](#configuration-examples)
18- [Validation Rules](#validation-rules)
19
20## Required Configuration
21
22These environment variables MUST be set for QuickDID to start.
23
24### `HTTP_EXTERNAL`
25
26**Required**: Yes
27**Type**: String
28**Format**: Hostname with optional port
29
30The external hostname where this service will be accessible. This is used to generate the service DID and for AT Protocol identity resolution.
31
32**Examples**:
33```bash
34# Production domain
35HTTP_EXTERNAL=quickdid.example.com
36
37# With non-standard port
38HTTP_EXTERNAL=quickdid.example.com:8080
39
40# Development/testing
41HTTP_EXTERNAL=localhost:3007
42```
43
44**Constraints**:
45- Must be a valid hostname or hostname:port combination
46- Port (if specified) must be between 1-65535
47
48## Network Configuration
49
50### `HTTP_PORT`
51
52**Required**: No
53**Type**: String
54**Default**: `8080`
55**Range**: 1-65535
56
57The port number for the HTTP server to bind to.
58
59**Examples**:
60```bash
61HTTP_PORT=8080 # Default
62HTTP_PORT=3000 # Common alternative
63HTTP_PORT=80 # Standard HTTP (requires root/privileges)
64```
65
66### `PLC_HOSTNAME`
67
68**Required**: No
69**Type**: String
70**Default**: `plc.directory`
71
72The hostname of the PLC directory service for DID resolution.
73
74**Examples**:
75```bash
76PLC_HOSTNAME=plc.directory # Production (default)
77PLC_HOSTNAME=test.plc.directory # Testing environment
78PLC_HOSTNAME=localhost:2582 # Local PLC server
79```
80
81### `DNS_NAMESERVERS`
82
83**Required**: No
84**Type**: String (comma-separated IP addresses)
85**Default**: System DNS
86
87Custom DNS nameservers for handle resolution via TXT records.
88
89**Examples**:
90```bash
91# Google DNS
92DNS_NAMESERVERS=8.8.8.8,8.8.4.4
93
94# Cloudflare DNS
95DNS_NAMESERVERS=1.1.1.1,1.0.0.1
96
97# Multiple providers
98DNS_NAMESERVERS=8.8.8.8,1.1.1.1
99
100# Local DNS
101DNS_NAMESERVERS=192.168.1.1
102```
103
104### `USER_AGENT`
105
106**Required**: No
107**Type**: String
108**Default**: `quickdid/{version} (+https://github.com/smokesignal.events/quickdid)`
109
110HTTP User-Agent header for outgoing requests.
111
112**Examples**:
113```bash
114# Custom agent
115USER_AGENT="MyService/1.0.0 (+https://myservice.com)"
116
117# With contact info
118USER_AGENT="quickdid/1.0.0 (+https://quickdid.example.com; admin@example.com)"
119```
120
121### `CERTIFICATE_BUNDLES`
122
123**Required**: No
124**Type**: String (comma-separated file paths)
125**Default**: System CA certificates
126
127Additional CA certificate bundles for TLS connections.
128
129**Examples**:
130```bash
131# Single certificate
132CERTIFICATE_BUNDLES=/etc/ssl/certs/custom-ca.pem
133
134# Multiple certificates
135CERTIFICATE_BUNDLES=/certs/ca1.pem,/certs/ca2.pem
136
137# Corporate CA
138CERTIFICATE_BUNDLES=/usr/local/share/ca-certificates/corporate-ca.crt
139```
140
141## Caching Configuration
142
143### `REDIS_URL`
144
145**Required**: No (recommended for multi-instance production)
146**Type**: String
147**Format**: Redis connection URL
148
149Redis connection URL for persistent caching. Enables distributed caching and better performance.
150
151**Examples**:
152```bash
153# Local Redis (no auth)
154REDIS_URL=redis://localhost:6379/0
155
156# With authentication
157REDIS_URL=redis://user:password@redis.example.com:6379/0
158
159# Using database 1
160REDIS_URL=redis://localhost:6379/1
161
162# Redis Sentinel
163REDIS_URL=redis-sentinel://sentinel1:26379,sentinel2:26379/mymaster/0
164
165# TLS connection
166REDIS_URL=rediss://secure-redis.example.com:6380/0
167```
168
169### `SQLITE_URL`
170
171**Required**: No (recommended for single-instance production)
172**Type**: String
173**Format**: SQLite database URL
174
175SQLite database URL for persistent caching. Provides single-file persistent storage without external dependencies.
176
177**Examples**:
178```bash
179# File-based database (recommended)
180SQLITE_URL=sqlite:./quickdid.db
181
182# With absolute path
183SQLITE_URL=sqlite:/var/lib/quickdid/cache.db
184
185# In-memory database (testing only)
186SQLITE_URL=sqlite::memory:
187
188# Alternative file syntax
189SQLITE_URL=sqlite:///path/to/database.db
190```
191
192**Cache Priority**: QuickDID uses the first available cache:
1931. Redis (if `REDIS_URL` is configured)
1942. SQLite (if `SQLITE_URL` is configured)
1953. In-memory cache (fallback)
196
197### `CACHE_TTL_MEMORY`
198
199**Required**: No
200**Type**: Integer (seconds)
201**Default**: `600` (10 minutes)
202**Range**: 60-3600 (recommended)
203**Constraints**: Must be > 0
204
205Time-to-live for in-memory cache entries in seconds. Used when Redis is not available.
206
207**Examples**:
208```bash
209CACHE_TTL_MEMORY=300 # 5 minutes (aggressive refresh)
210CACHE_TTL_MEMORY=600 # 10 minutes (default, balanced)
211CACHE_TTL_MEMORY=1800 # 30 minutes (less frequent updates)
212CACHE_TTL_MEMORY=3600 # 1 hour (stable data)
213```
214
215**Recommendations**:
216- Lower values: Fresher data, more DNS/HTTP lookups, higher load
217- Higher values: Better performance, potentially stale data
218- Production with Redis: Can use lower values (300-600)
219- Production without Redis: Use higher values (1800-3600)
220
221### `CACHE_TTL_REDIS`
222
223**Required**: No
224**Type**: Integer (seconds)
225**Default**: `7776000` (90 days)
226**Range**: 3600-31536000 (1 hour to 1 year)
227**Constraints**: Must be > 0
228
229Time-to-live for Redis cache entries in seconds.
230
231**Examples**:
232```bash
233CACHE_TTL_REDIS=3600 # 1 hour (frequently changing data)
234CACHE_TTL_REDIS=86400 # 1 day (recommended for active handles)
235CACHE_TTL_REDIS=604800 # 1 week (balanced)
236CACHE_TTL_REDIS=2592000 # 30 days (stable handles)
237CACHE_TTL_REDIS=7776000 # 90 days (default, maximum stability)
238```
239
240### `CACHE_TTL_SQLITE`
241
242**Required**: No
243**Type**: Integer (seconds)
244**Default**: `7776000` (90 days)
245**Range**: 3600-31536000 (1 hour to 1 year)
246**Constraints**: Must be > 0
247
248Time-to-live for SQLite cache entries in seconds. Only used when `SQLITE_URL` is configured.
249
250**Examples**:
251```bash
252CACHE_TTL_SQLITE=3600 # 1 hour (frequently changing data)
253CACHE_TTL_SQLITE=86400 # 1 day (recommended for active handles)
254CACHE_TTL_SQLITE=604800 # 1 week (balanced)
255CACHE_TTL_SQLITE=2592000 # 30 days (stable handles)
256CACHE_TTL_SQLITE=7776000 # 90 days (default, maximum stability)
257```
258
259**TTL Recommendations**:
260- Social media handles: 1-7 days
261- Corporate/stable handles: 30-90 days
262- Test environments: 1 hour
263- Single-instance deployments: Can use longer TTLs (30-90 days)
264- Multi-instance deployments: Use shorter TTLs (1-7 days)
265
266## Queue Configuration
267
268### `QUEUE_ADAPTER`
269
270**Required**: No
271**Type**: String
272**Default**: `mpsc`
273**Values**: `mpsc`, `redis`, `sqlite`, `noop`, `none`
274
275The type of queue adapter for background handle resolution.
276
277**Options**:
278- `mpsc`: In-memory multi-producer single-consumer queue (default)
279- `redis`: Redis-backed distributed queue
280- `sqlite`: SQLite-backed persistent queue
281- `noop`: Disable queue processing (testing only)
282- `none`: Alias for `noop`
283
284**Examples**:
285```bash
286# Single instance deployment
287QUEUE_ADAPTER=mpsc
288
289# Multi-instance or high availability
290QUEUE_ADAPTER=redis
291
292# Single instance with persistence
293QUEUE_ADAPTER=sqlite
294
295# Testing without background processing
296QUEUE_ADAPTER=noop
297
298# Alternative syntax for disabling
299QUEUE_ADAPTER=none
300```
301
302### `QUEUE_REDIS_URL`
303
304**Required**: No
305**Type**: String
306**Default**: Falls back to `REDIS_URL`
307
308Dedicated Redis URL for queue operations. Use when separating cache and queue Redis instances.
309
310**Examples**:
311```bash
312# Separate Redis for queues
313QUEUE_REDIS_URL=redis://queue-redis:6379/2
314
315# With different credentials
316QUEUE_REDIS_URL=redis://queue_user:queue_pass@redis.example.com:6379/1
317```
318
319### `QUEUE_REDIS_PREFIX`
320
321**Required**: No
322**Type**: String
323**Default**: `queue:handleresolver:`
324
325Redis key prefix for queue operations. Use to namespace queues when sharing Redis.
326
327**Examples**:
328```bash
329# Default
330QUEUE_REDIS_PREFIX=queue:handleresolver:
331
332# Environment-specific
333QUEUE_REDIS_PREFIX=prod:queue:hr:
334QUEUE_REDIS_PREFIX=staging:queue:hr:
335
336# Version-specific
337QUEUE_REDIS_PREFIX=quickdid:v1:queue:
338
339# Instance-specific
340QUEUE_REDIS_PREFIX=us-east-1:queue:hr:
341```
342
343### `QUEUE_REDIS_TIMEOUT`
344
345**Required**: No
346**Type**: Integer (seconds)
347**Default**: `5`
348**Range**: 1-60 (recommended)
349**Constraints**: Must be > 0
350
351Redis blocking timeout for queue operations in seconds. Controls how long to wait for new items.
352
353**Examples**:
354```bash
355QUEUE_REDIS_TIMEOUT=1 # Very responsive, more polling
356QUEUE_REDIS_TIMEOUT=5 # Default, balanced
357QUEUE_REDIS_TIMEOUT=10 # Less polling, slower shutdown
358QUEUE_REDIS_TIMEOUT=30 # Minimal polling, slow shutdown
359```
360
361### `QUEUE_REDIS_DEDUP_ENABLED`
362
363**Required**: No
364**Type**: Boolean
365**Default**: `false`
366
367Enable deduplication for Redis queue to prevent duplicate handles from being queued multiple times within the TTL window. When enabled, uses Redis SET with TTL to track handles currently being processed.
368
369**Examples**:
370```bash
371# Enable deduplication (recommended for production)
372QUEUE_REDIS_DEDUP_ENABLED=true
373
374# Disable deduplication (default)
375QUEUE_REDIS_DEDUP_ENABLED=false
376```
377
378**Use cases**:
379- **Production**: Enable to prevent duplicate work and reduce load
380- **High-traffic**: Essential to avoid processing the same handle multiple times
381- **Development**: Can be disabled for simpler debugging
382
383### `QUEUE_REDIS_DEDUP_TTL`
384
385**Required**: No
386**Type**: Integer (seconds)
387**Default**: `60`
388**Range**: 10-300 (recommended)
389**Constraints**: Must be > 0 when deduplication is enabled
390
391TTL for Redis queue deduplication keys in seconds. Determines how long to prevent duplicate handle resolution requests.
392
393**Examples**:
394```bash
395# Quick deduplication window (10 seconds)
396QUEUE_REDIS_DEDUP_TTL=10
397
398# Default (1 minute)
399QUEUE_REDIS_DEDUP_TTL=60
400
401# Extended deduplication (5 minutes)
402QUEUE_REDIS_DEDUP_TTL=300
403```
404
405**Recommendations**:
406- **Fast processing**: 10-30 seconds
407- **Normal processing**: 60 seconds (default)
408- **Slow processing or high load**: 120-300 seconds
409
410### `QUEUE_WORKER_ID`
411
412**Required**: No
413**Type**: String
414**Default**: `worker1`
415
416Worker identifier for queue operations. Used in logs and monitoring.
417
418**Examples**:
419```bash
420# Simple numbering
421QUEUE_WORKER_ID=worker-001
422
423# Environment-based
424QUEUE_WORKER_ID=prod-us-east-1
425QUEUE_WORKER_ID=staging-worker-2
426
427# Hostname-based
428QUEUE_WORKER_ID=$(hostname)
429
430# Pod name in Kubernetes
431QUEUE_WORKER_ID=$HOSTNAME
432```
433
434### `QUEUE_BUFFER_SIZE`
435
436**Required**: No
437**Type**: Integer
438**Default**: `1000`
439**Range**: 100-100000 (recommended)
440
441Buffer size for the MPSC queue adapter. Only used when `QUEUE_ADAPTER=mpsc`.
442
443**Examples**:
444```bash
445QUEUE_BUFFER_SIZE=100 # Minimal memory, may block
446QUEUE_BUFFER_SIZE=1000 # Default, balanced
447QUEUE_BUFFER_SIZE=5000 # High traffic
448QUEUE_BUFFER_SIZE=10000 # Very high traffic
449```
450
451### `QUEUE_SQLITE_MAX_SIZE`
452
453**Required**: No
454**Type**: Integer
455**Default**: `10000`
456**Range**: 100-1000000 (recommended)
457**Constraints**: Must be >= 0
458
459Maximum queue size for SQLite adapter work shedding. When the queue exceeds this limit, the oldest entries are automatically deleted to maintain the specified size limit, preserving the most recently queued work items.
460
461**Work Shedding Behavior**:
462- New work items are always accepted
463- When queue size exceeds `QUEUE_SQLITE_MAX_SIZE`, oldest entries are deleted
464- Deletion happens atomically with insertion in a single transaction
465- Essential for long-running deployments to prevent unbounded disk growth
466- Set to `0` to disable work shedding (unlimited queue size)
467
468**Examples**:
469```bash
470QUEUE_SQLITE_MAX_SIZE=0 # Unlimited (disable work shedding)
471QUEUE_SQLITE_MAX_SIZE=1000 # Small deployment, frequent processing
472QUEUE_SQLITE_MAX_SIZE=10000 # Default, balanced for most deployments
473QUEUE_SQLITE_MAX_SIZE=100000 # High-traffic deployment with slower processing
474QUEUE_SQLITE_MAX_SIZE=1000000 # Very high-traffic, maximum recommended
475```
476
477**Recommendations**:
478- **Small deployments**: 1000-5000 entries
479- **Production deployments**: 10000-50000 entries
480- **High-traffic deployments**: 50000-1000000 entries
481- **Development/testing**: 100-1000 entries
482- **Disk space concerns**: Lower values (1000-5000)
483- **High ingestion rate**: Higher values (50000-1000000)
484
485## Rate Limiting Configuration
486
487### `RESOLVER_MAX_CONCURRENT`
488
489**Required**: No
490**Type**: Integer
491**Default**: `0` (disabled)
492**Range**: 0-10000
493**Constraints**: Must be between 0 and 10000
494
495Maximum concurrent handle resolutions allowed. When set to a value greater than 0, enables semaphore-based rate limiting to protect upstream DNS and HTTP services from being overwhelmed.
496
497**How it works**:
498- Uses a semaphore to limit concurrent resolutions
499- Applied between the base resolver and caching layers
500- Requests wait for an available permit before resolution
501- Helps prevent overwhelming upstream services
502
503**Examples**:
504```bash
505# Disabled (default)
506RESOLVER_MAX_CONCURRENT=0
507
508# Light rate limiting
509RESOLVER_MAX_CONCURRENT=10
510
511# Moderate rate limiting
512RESOLVER_MAX_CONCURRENT=50
513
514# Heavy traffic with rate limiting
515RESOLVER_MAX_CONCURRENT=100
516
517# Maximum allowed
518RESOLVER_MAX_CONCURRENT=10000
519```
520
521**Recommendations**:
522- **Development**: 0 (disabled) or 10-50 for testing
523- **Production (low traffic)**: 50-100
524- **Production (high traffic)**: 100-500
525- **Production (very high traffic)**: 500-1000
526- **Testing rate limiting**: 1-5 to observe behavior
527
528**Placement in resolver stack**:
529```
530Request → Cache → RateLimited → Base → DNS/HTTP
531```
532
533### `RESOLVER_MAX_CONCURRENT_TIMEOUT_MS`
534
535**Required**: No
536**Type**: Integer (milliseconds)
537**Default**: `0` (no timeout)
538**Range**: 0-60000
539**Constraints**: Must be between 0 and 60000 (60 seconds max)
540
541Timeout for acquiring a rate limit permit in milliseconds. When set to a value greater than 0, requests will timeout if they cannot acquire a permit within the specified time, preventing them from waiting indefinitely when the rate limiter is at capacity.
542
543**How it works**:
544- Applied when `RESOLVER_MAX_CONCURRENT` is enabled (> 0)
545- Uses `tokio::time::timeout` to limit permit acquisition time
546- Returns an error if timeout expires before permit is acquired
547- Prevents request queue buildup during high load
548
549**Examples**:
550```bash
551# No timeout (default)
552RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=0
553
554# Quick timeout for responsive failures (100ms)
555RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=100
556
557# Moderate timeout (1 second)
558RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=1000
559
560# Longer timeout for production (5 seconds)
561RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=5000
562
563# Maximum allowed (60 seconds)
564RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=60000
565```
566
567**Recommendations**:
568- **Development**: 100-1000ms for quick feedback
569- **Production (low latency)**: 1000-5000ms
570- **Production (high latency tolerance)**: 5000-30000ms
571- **Testing**: 100ms to quickly identify bottlenecks
572- **0**: Use when you want requests to wait indefinitely
573
574**Error behavior**:
575When a timeout occurs, the request fails with:
576```
577Rate limit permit acquisition timed out after {timeout}ms
578```
579
580## Metrics Configuration
581
582### `METRICS_ADAPTER`
583
584**Required**: No
585**Type**: String
586**Default**: `noop`
587**Values**: `noop`, `statsd`
588
589Metrics adapter type for collecting and publishing metrics.
590
591**Options**:
592- `noop`: No metrics collection (default)
593- `statsd`: Send metrics to StatsD server
594
595**Examples**:
596```bash
597# No metrics (default)
598METRICS_ADAPTER=noop
599
600# Enable StatsD metrics
601METRICS_ADAPTER=statsd
602```
603
604### `METRICS_STATSD_HOST`
605
606**Required**: Yes (when METRICS_ADAPTER=statsd)
607**Type**: String
608**Format**: hostname:port
609
610StatsD server host and port for metrics collection.
611
612**Examples**:
613```bash
614# Local StatsD
615METRICS_STATSD_HOST=localhost:8125
616
617# Remote StatsD
618METRICS_STATSD_HOST=statsd.example.com:8125
619
620# Docker network
621METRICS_STATSD_HOST=statsd:8125
622```
623
624### `METRICS_STATSD_BIND`
625
626**Required**: No
627**Type**: String
628**Default**: `[::]:0`
629
630Bind address for StatsD UDP socket. Controls which local address to bind for sending UDP packets.
631
632**Examples**:
633```bash
634# IPv6 any address, random port (default)
635METRICS_STATSD_BIND=[::]:0
636
637# IPv4 any address, random port
638METRICS_STATSD_BIND=0.0.0.0:0
639
640# Specific interface
641METRICS_STATSD_BIND=192.168.1.100:0
642
643# Specific port
644METRICS_STATSD_BIND=[::]:8126
645```
646
647### `METRICS_PREFIX`
648
649**Required**: No
650**Type**: String
651**Default**: `quickdid`
652
653Prefix for all metrics. Used to namespace metrics in your monitoring system.
654
655**Examples**:
656```bash
657# Default
658METRICS_PREFIX=quickdid
659
660# Environment-specific
661METRICS_PREFIX=prod.quickdid
662METRICS_PREFIX=staging.quickdid
663
664# Region-specific
665METRICS_PREFIX=us-east-1.quickdid
666METRICS_PREFIX=eu-west-1.quickdid
667
668# Service-specific
669METRICS_PREFIX=api.quickdid
670```
671
672### `METRICS_TAGS`
673
674**Required**: No
675**Type**: String (comma-separated key:value pairs)
676**Default**: None
677
678Default tags for all metrics. Added to all metrics for filtering and grouping.
679
680**Examples**:
681```bash
682# Basic tags
683METRICS_TAGS=env:production,service:quickdid
684
685# Detailed tags
686METRICS_TAGS=env:production,service:quickdid,region:us-east-1,version:1.0.0
687
688# Deployment-specific
689METRICS_TAGS=env:staging,cluster:k8s-staging,namespace:quickdid
690```
691
692**Common tag patterns**:
693- `env`: Environment (production, staging, development)
694- `service`: Service name
695- `region`: Geographic region
696- `version`: Application version
697- `cluster`: Kubernetes cluster name
698- `instance`: Instance identifier
699
700## Proactive Refresh Configuration
701
702### `PROACTIVE_REFRESH_ENABLED`
703
704**Required**: No
705**Type**: Boolean
706**Default**: `false`
707
708Enable proactive cache refresh for frequently accessed handles. When enabled, cache entries that have reached the refresh threshold will be queued for background refresh to keep the cache warm.
709
710**Examples**:
711```bash
712# Enable proactive refresh (recommended for production)
713PROACTIVE_REFRESH_ENABLED=true
714
715# Disable proactive refresh (default)
716PROACTIVE_REFRESH_ENABLED=false
717```
718
719**Benefits**:
720- Prevents cache misses for popular handles
721- Maintains consistent response times
722- Reduces latency spikes during cache expiration
723
724**Considerations**:
725- Increases background processing load
726- More DNS/HTTP requests to upstream services
727- Best for high-traffic services with predictable access patterns
728
729### `PROACTIVE_REFRESH_THRESHOLD`
730
731**Required**: No
732**Type**: Float
733**Default**: `0.8`
734**Range**: 0.0-1.0
735**Constraints**: Must be between 0.0 and 1.0
736
737Threshold as a percentage (0.0-1.0) of cache TTL when to trigger proactive refresh. For example, 0.8 means refresh when an entry has lived for 80% of its TTL.
738
739**Examples**:
740```bash
741# Very aggressive (refresh at 50% of TTL)
742PROACTIVE_REFRESH_THRESHOLD=0.5
743
744# Moderate (refresh at 70% of TTL)
745PROACTIVE_REFRESH_THRESHOLD=0.7
746
747# Default (refresh at 80% of TTL)
748PROACTIVE_REFRESH_THRESHOLD=0.8
749
750# Conservative (refresh at 90% of TTL)
751PROACTIVE_REFRESH_THRESHOLD=0.9
752
753# Very conservative (refresh at 95% of TTL)
754PROACTIVE_REFRESH_THRESHOLD=0.95
755```
756
757**Recommendations**:
758- **High-traffic services**: 0.5-0.7 (aggressive refresh)
759- **Normal traffic**: 0.8 (default, balanced)
760- **Low traffic**: 0.9-0.95 (conservative)
761- **Development**: 0.5 (test refresh behavior)
762
763**Impact on different cache TTLs**:
764- TTL=600s (10 min), threshold=0.8: Refresh after 8 minutes
765- TTL=3600s (1 hour), threshold=0.8: Refresh after 48 minutes
766- TTL=86400s (1 day), threshold=0.8: Refresh after 19.2 hours
767
768## Jetstream Consumer Configuration
769
770### `JETSTREAM_ENABLED`
771
772**Required**: No
773**Type**: Boolean
774**Default**: `false`
775
776Enable Jetstream consumer for real-time cache updates from the AT Protocol firehose. When enabled, QuickDID connects to the Jetstream WebSocket service to receive live updates about account and identity changes.
777
778**How it works**:
779- Subscribes to Account and Identity events from the firehose
780- Processes Account events to purge deleted/deactivated accounts
781- Processes Identity events to update handle-to-DID mappings
782- Automatically reconnects with exponential backoff on connection failures
783- Tracks metrics for successful and failed event processing
784
785**Examples**:
786```bash
787# Enable Jetstream consumer (recommended for production)
788JETSTREAM_ENABLED=true
789
790# Disable Jetstream consumer (default)
791JETSTREAM_ENABLED=false
792```
793
794**Benefits**:
795- Real-time cache synchronization with AT Protocol network
796- Automatic removal of deleted/deactivated accounts
797- Immediate handle change updates
798- Reduces stale data in cache
799
800**Considerations**:
801- Requires stable WebSocket connection
802- Increases network traffic (incoming events)
803- Best for services requiring up-to-date handle mappings
804- Automatically handles reconnection on failures
805
806### `JETSTREAM_HOSTNAME`
807
808**Required**: No
809**Type**: String
810**Default**: `jetstream.atproto.tools`
811
812The hostname of the Jetstream WebSocket service to connect to for real-time AT Protocol events. Only used when `JETSTREAM_ENABLED=true`.
813
814**Examples**:
815```bash
816# Production firehose (default)
817JETSTREAM_HOSTNAME=jetstream.atproto.tools
818
819# Staging environment
820JETSTREAM_HOSTNAME=jetstream-staging.atproto.tools
821
822# Local development firehose
823JETSTREAM_HOSTNAME=localhost:6008
824
825# Custom deployment
826JETSTREAM_HOSTNAME=jetstream.example.com
827```
828
829**Event Processing**:
830- **Account events**:
831 - `status: deleted` → Purges handle and DID from all caches
832 - `status: deactivated` → Purges handle and DID from all caches
833 - Other statuses → Ignored
834
835- **Identity events**:
836 - Updates handle-to-DID mapping in cache
837 - Removes old handle mapping if changed
838 - Maintains bidirectional cache consistency
839
840**Metrics Tracked** (when metrics are enabled):
841- `jetstream.events.received`: Total events received
842- `jetstream.events.processed`: Successfully processed events
843- `jetstream.events.failed`: Failed event processing
844- `jetstream.connections.established`: Successful connections
845- `jetstream.connections.failed`: Failed connection attempts
846
847**Reconnection Behavior**:
848- Initial retry delay: 1 second
849- Maximum retry delay: 60 seconds
850- Exponential backoff with jitter
851- Automatic recovery on transient failures
852
853**Recommendations**:
854- **Production**: Use default `jetstream.atproto.tools`
855- **Development**: Consider local firehose for testing
856- **High availability**: Monitor connection metrics
857- **Network issues**: Check WebSocket connectivity
858
859## Static Files Configuration
860
861### `STATIC_FILES_DIR`
862
863**Required**: No
864**Type**: String (directory path)
865**Default**: `www`
866
867Directory path for serving static files. This directory should contain the landing page and AT Protocol well-known files.
868
869**Directory Structure**:
870```
871www/
872├── index.html # Landing page
873├── .well-known/
874│ ├── atproto-did # Service DID identifier
875│ └── did.json # DID document
876└── (other static assets)
877```
878
879**Examples**:
880```bash
881# Default (relative to working directory)
882STATIC_FILES_DIR=www
883
884# Absolute path
885STATIC_FILES_DIR=/var/www/quickdid
886
887# Docker container path
888STATIC_FILES_DIR=/app/www
889
890# Custom directory
891STATIC_FILES_DIR=./public
892```
893
894**Docker Volume Mounting**:
895```yaml
896volumes:
897 # Mount entire custom directory
898 - ./custom-www:/app/www:ro
899
900 # Mount specific files
901 - ./custom-index.html:/app/www/index.html:ro
902 - ./well-known:/app/www/.well-known:ro
903```
904
905**Generating Well-Known Files**:
906```bash
907# Generate .well-known files for your domain
908HTTP_EXTERNAL=your-domain.com ./generate-wellknown.sh
909```
910
911## HTTP Caching Configuration
912
913### `CACHE_MAX_AGE`
914
915**Required**: No
916**Type**: Integer (seconds)
917**Default**: `86400` (24 hours)
918**Range**: 0-31536000 (0 to 1 year)
919
920Maximum age for HTTP Cache-Control header in seconds. When set to 0, the Cache-Control header is disabled and will not be added to responses. This controls how long clients and intermediate caches can cache responses.
921
922**Examples**:
923```bash
924# Default (24 hours)
925CACHE_MAX_AGE=86400
926
927# Aggressive caching (7 days)
928CACHE_MAX_AGE=604800
929
930# Conservative caching (1 hour)
931CACHE_MAX_AGE=3600
932
933# Disable Cache-Control header
934CACHE_MAX_AGE=0
935```
936
937### `CACHE_STALE_IF_ERROR`
938
939**Required**: No
940**Type**: Integer (seconds)
941**Default**: `172800` (48 hours)
942
943Allows stale content to be served if the backend encounters an error. This provides resilience during service outages.
944
945**Examples**:
946```bash
947# Default (48 hours)
948CACHE_STALE_IF_ERROR=172800
949
950# Extended error tolerance (7 days)
951CACHE_STALE_IF_ERROR=604800
952
953# Minimal error tolerance (1 hour)
954CACHE_STALE_IF_ERROR=3600
955```
956
957### `CACHE_STALE_WHILE_REVALIDATE`
958
959**Required**: No
960**Type**: Integer (seconds)
961**Default**: `86400` (24 hours)
962
963Allows stale content to be served while fresh content is being fetched in the background. This improves perceived performance.
964
965**Examples**:
966```bash
967# Default (24 hours)
968CACHE_STALE_WHILE_REVALIDATE=86400
969
970# Quick revalidation (1 hour)
971CACHE_STALE_WHILE_REVALIDATE=3600
972
973# Extended revalidation (7 days)
974CACHE_STALE_WHILE_REVALIDATE=604800
975```
976
977### `CACHE_MAX_STALE`
978
979**Required**: No
980**Type**: Integer (seconds)
981**Default**: `172800` (48 hours)
982
983Maximum time a client will accept stale responses. This provides an upper bound on how old cached content can be.
984
985**Examples**:
986```bash
987# Default (48 hours)
988CACHE_MAX_STALE=172800
989
990# Extended staleness (7 days)
991CACHE_MAX_STALE=604800
992
993# Strict freshness (1 hour)
994CACHE_MAX_STALE=3600
995```
996
997### `CACHE_MIN_FRESH`
998
999**Required**: No
1000**Type**: Integer (seconds)
1001**Default**: `3600` (1 hour)
1002
1003Minimum time a response must remain fresh. Clients will not accept responses that will expire within this time.
1004
1005**Examples**:
1006```bash
1007# Default (1 hour)
1008CACHE_MIN_FRESH=3600
1009
1010# Strict freshness (24 hours)
1011CACHE_MIN_FRESH=86400
1012
1013# Relaxed freshness (5 minutes)
1014CACHE_MIN_FRESH=300
1015```
1016
1017**Cache-Control Header Format**:
1018
1019When `CACHE_MAX_AGE` is greater than 0, the following Cache-Control header is added to responses:
1020```
1021Cache-Control: public, max-age=86400, stale-while-revalidate=86400, stale-if-error=172800, max-stale=172800, min-fresh=3600
1022```
1023
1024**Recommendations**:
1025- **High-traffic services**: Use longer max-age (86400-604800) to reduce load
1026- **Frequently changing data**: Use shorter max-age (3600-14400)
1027- **Critical services**: Set higher stale-if-error for resilience
1028- **Performance-sensitive**: Enable stale-while-revalidate for better UX
1029- **Disable caching**: Set CACHE_MAX_AGE=0 for real-time data
1030
1031### `ETAG_SEED`
1032
1033**Required**: No
1034**Type**: String
1035**Default**: Application version (from `CARGO_PKG_VERSION`)
1036
1037Seed value for ETAG generation to allow cache invalidation. This value is incorporated into ETAG checksums, allowing server administrators to invalidate client-cached responses after major changes or deployments.
1038
1039**How it works**:
1040- Combined with response content to generate ETAG checksums
1041- Uses MetroHash64 for fast, non-cryptographic hashing
1042- Generates weak ETags (W/"hash") for HTTP caching
1043- Changing the seed invalidates all client caches
1044
1045**Examples**:
1046```bash
1047# Default (uses application version)
1048# ETAG_SEED is automatically set to the version
1049
1050# Deployment-specific seed
1051ETAG_SEED=prod-2024-01-15
1052
1053# Version with timestamp
1054ETAG_SEED=v1.0.0-1705344000
1055
1056# Environment-specific
1057ETAG_SEED=staging-v2
1058
1059# Force cache invalidation after config change
1060ETAG_SEED=config-update-2024-01-15
1061```
1062
1063**Use cases**:
1064- **Major configuration changes**: Update seed to invalidate all cached responses
1065- **Data migration**: Force clients to refetch after backend changes
1066- **Security updates**: Ensure clients get fresh data after security fixes
1067- **A/B testing**: Different seeds for different deployment groups
1068- **Rollback scenarios**: Revert to previous seed to restore cache behavior
1069
1070**Recommendations**:
1071- **Default**: Use the application version (automatic)
1072- **Production**: Include deployment date or config version
1073- **Staging**: Use environment-specific seeds
1074- **After incidents**: Update seed to force fresh data
1075- **Routine deployments**: Keep the same seed if no data changes
1076
1077## Configuration Examples
1078
1079### Minimal Development Configuration
1080
1081```bash
1082# .env.development
1083HTTP_EXTERNAL=localhost:3007
1084RUST_LOG=debug
1085```
1086
1087### Standard Production Configuration (Redis)
1088
1089```bash
1090# .env.production.redis
1091# Required
1092HTTP_EXTERNAL=quickdid.example.com
1093
1094# Network
1095HTTP_PORT=8080
1096USER_AGENT=quickdid/1.0.0 (+https://quickdid.example.com)
1097
1098# Caching (Redis-based)
1099REDIS_URL=redis://redis:6379/0
1100CACHE_TTL_MEMORY=600
1101CACHE_TTL_REDIS=86400 # 1 day
1102
1103# Queue
1104QUEUE_ADAPTER=redis
1105QUEUE_REDIS_TIMEOUT=5
1106QUEUE_BUFFER_SIZE=5000
1107QUEUE_REDIS_DEDUP_ENABLED=true # Prevent duplicate work
1108QUEUE_REDIS_DEDUP_TTL=60
1109
1110# Rate Limiting (optional, recommended for production)
1111RESOLVER_MAX_CONCURRENT=100
1112RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=5000 # 5 second timeout
1113
1114# Metrics (optional, recommended for production)
1115METRICS_ADAPTER=statsd
1116METRICS_STATSD_HOST=localhost:8125
1117METRICS_PREFIX=quickdid
1118METRICS_TAGS=env:prod,service:quickdid
1119
1120# Proactive Refresh (optional, recommended for high-traffic)
1121PROACTIVE_REFRESH_ENABLED=true
1122PROACTIVE_REFRESH_THRESHOLD=0.8
1123
1124# Jetstream Consumer (optional, recommended for real-time sync)
1125JETSTREAM_ENABLED=true
1126JETSTREAM_HOSTNAME=jetstream.atproto.tools
1127
1128# HTTP Caching (Cache-Control headers)
1129CACHE_MAX_AGE=86400 # 24 hours
1130CACHE_STALE_IF_ERROR=172800 # 48 hours
1131CACHE_STALE_WHILE_REVALIDATE=86400 # 24 hours
1132
1133# Logging
1134RUST_LOG=info
1135```
1136
1137### Standard Production Configuration (SQLite)
1138
1139```bash
1140# .env.production.sqlite
1141# Required
1142HTTP_EXTERNAL=quickdid.example.com
1143
1144# Network
1145HTTP_PORT=8080
1146USER_AGENT=quickdid/1.0.0 (+https://quickdid.example.com)
1147
1148# Caching (SQLite-based for single instance)
1149SQLITE_URL=sqlite:/data/quickdid.db
1150CACHE_TTL_MEMORY=600
1151CACHE_TTL_SQLITE=86400 # 1 day
1152
1153# Queue (SQLite for single instance with persistence)
1154QUEUE_ADAPTER=sqlite
1155QUEUE_BUFFER_SIZE=5000
1156QUEUE_SQLITE_MAX_SIZE=10000
1157
1158# Rate Limiting (optional, recommended for production)
1159RESOLVER_MAX_CONCURRENT=100
1160RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=5000 # 5 second timeout
1161
1162# Jetstream Consumer (optional, recommended for real-time sync)
1163JETSTREAM_ENABLED=true
1164JETSTREAM_HOSTNAME=jetstream.atproto.tools
1165
1166# HTTP Caching (Cache-Control headers)
1167CACHE_MAX_AGE=86400 # 24 hours
1168CACHE_STALE_IF_ERROR=172800 # 48 hours
1169CACHE_STALE_WHILE_REVALIDATE=86400 # 24 hours
1170
1171# Logging
1172RUST_LOG=info
1173```
1174
1175### High-Availability Configuration (Redis)
1176
1177```bash
1178# .env.ha.redis
1179# Required
1180HTTP_EXTERNAL=quickdid.example.com
1181
1182# Network
1183HTTP_PORT=8080
1184DNS_NAMESERVERS=8.8.8.8,8.8.4.4,1.1.1.1,1.0.0.1
1185
1186# Caching (separate Redis instances)
1187REDIS_URL=redis://cache-redis:6379/0
1188CACHE_TTL_MEMORY=300
1189CACHE_TTL_REDIS=3600
1190
1191# Queue (dedicated Redis)
1192QUEUE_ADAPTER=redis
1193QUEUE_REDIS_URL=redis://queue-redis:6379/0
1194QUEUE_REDIS_PREFIX=prod:queue:
1195QUEUE_WORKER_ID=${HOSTNAME:-worker1}
1196QUEUE_REDIS_TIMEOUT=10
1197QUEUE_REDIS_DEDUP_ENABLED=true # Essential for multi-instance
1198QUEUE_REDIS_DEDUP_TTL=120 # Longer TTL for HA
1199
1200# Performance
1201QUEUE_BUFFER_SIZE=10000
1202
1203# Rate Limiting (important for HA deployments)
1204RESOLVER_MAX_CONCURRENT=500
1205RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=10000 # 10 second timeout for HA
1206
1207# Metrics (recommended for HA monitoring)
1208METRICS_ADAPTER=statsd
1209METRICS_STATSD_HOST=statsd:8125
1210METRICS_PREFIX=quickdid.prod
1211METRICS_TAGS=env:prod,service:quickdid,cluster:ha
1212
1213# Proactive Refresh (recommended for HA)
1214PROACTIVE_REFRESH_ENABLED=true
1215PROACTIVE_REFRESH_THRESHOLD=0.7 # More aggressive for HA
1216
1217# Jetstream Consumer (recommended for real-time sync in HA)
1218JETSTREAM_ENABLED=true
1219JETSTREAM_HOSTNAME=jetstream.atproto.tools
1220
1221# Logging
1222RUST_LOG=warn
1223```
1224
1225### Hybrid Configuration (Redis + SQLite Fallback)
1226
1227```bash
1228# .env.hybrid
1229# Required
1230HTTP_EXTERNAL=quickdid.example.com
1231
1232# Network
1233HTTP_PORT=8080
1234
1235# Caching (Redis primary, SQLite fallback)
1236REDIS_URL=redis://redis:6379/0
1237SQLITE_URL=sqlite:/data/fallback.db
1238CACHE_TTL_MEMORY=600
1239CACHE_TTL_REDIS=86400
1240CACHE_TTL_SQLITE=604800 # 1 week (longer for fallback)
1241
1242# Queue
1243QUEUE_ADAPTER=redis
1244QUEUE_REDIS_TIMEOUT=5
1245
1246# Logging
1247RUST_LOG=info
1248```
1249
1250### Docker Compose Configuration (Redis)
1251
1252```yaml
1253# docker-compose.redis.yml
1254version: '3.8'
1255
1256services:
1257 quickdid:
1258 image: quickdid:latest
1259 environment:
1260 HTTP_EXTERNAL: quickdid.example.com
1261 HTTP_PORT: 8080
1262 REDIS_URL: redis://redis:6379/0
1263 CACHE_TTL_MEMORY: 600
1264 CACHE_TTL_REDIS: 86400
1265 QUEUE_ADAPTER: redis
1266 QUEUE_REDIS_TIMEOUT: 5
1267 JETSTREAM_ENABLED: true
1268 JETSTREAM_HOSTNAME: jetstream.atproto.tools
1269 RUST_LOG: info
1270 ports:
1271 - "8080:8080"
1272 depends_on:
1273 - redis
1274
1275 redis:
1276 image: redis:7-alpine
1277 command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
1278```
1279
1280### Docker Compose Configuration (SQLite)
1281
1282```yaml
1283# docker-compose.sqlite.yml
1284version: '3.8'
1285
1286services:
1287 quickdid:
1288 image: quickdid:latest
1289 environment:
1290 HTTP_EXTERNAL: quickdid.example.com
1291 HTTP_PORT: 8080
1292 SQLITE_URL: sqlite:/data/quickdid.db
1293 CACHE_TTL_MEMORY: 600
1294 CACHE_TTL_SQLITE: 86400
1295 QUEUE_ADAPTER: sqlite
1296 QUEUE_BUFFER_SIZE: 5000
1297 QUEUE_SQLITE_MAX_SIZE: 10000
1298 JETSTREAM_ENABLED: true
1299 JETSTREAM_HOSTNAME: jetstream.atproto.tools
1300 RUST_LOG: info
1301 ports:
1302 - "8080:8080"
1303 volumes:
1304 - quickdid-data:/data
1305
1306volumes:
1307 quickdid-data:
1308 driver: local
1309```
1310
1311## Validation Rules
1312
1313QuickDID validates configuration at startup. The following rules are enforced:
1314
1315### Required Fields
1316
13171. **HTTP_EXTERNAL**: Must be provided
13182. **HTTP_EXTERNAL**: Must be provided
1319
1320### Value Constraints
1321
13221. **TTL Values** (`CACHE_TTL_MEMORY`, `CACHE_TTL_REDIS`, `CACHE_TTL_SQLITE`):
1323 - Must be positive integers (> 0)
1324 - Recommended minimum: 60 seconds
1325
13262. **Timeout Values** (`QUEUE_REDIS_TIMEOUT`):
1327 - Must be positive integers (> 0)
1328 - Recommended range: 1-60 seconds
1329
13303. **Queue Adapter** (`QUEUE_ADAPTER`):
1331 - Must be one of: `mpsc`, `redis`, `sqlite`, `noop`, `none`
1332 - Case-sensitive
1333
13344. **Rate Limiting** (`RESOLVER_MAX_CONCURRENT`):
1335 - Must be between 0 and 10000
1336 - 0 = disabled (default)
1337 - Values > 10000 will fail validation
1338
13395. **Rate Limiting Timeout** (`RESOLVER_MAX_CONCURRENT_TIMEOUT_MS`):
1340 - Must be between 0 and 60000 (milliseconds)
1341 - 0 = no timeout (default)
1342 - Values > 60000 will fail validation
1343
13446. **Port** (`HTTP_PORT`):
1345 - Must be valid port number (1-65535)
1346 - Ports < 1024 require elevated privileges
1347
1348### Validation Errors
1349
1350If validation fails, QuickDID will exit with one of these error codes:
1351
1352- `error-quickdid-config-1`: Missing required environment variable
1353- `error-quickdid-config-2`: Invalid configuration value
1354- `error-quickdid-config-3`: Invalid TTL value (must be positive)
1355- `error-quickdid-config-4`: Invalid timeout value (must be positive)
1356
1357### Testing Configuration
1358
1359Test your configuration without starting the service:
1360
1361```bash
1362# Validate configuration
1363HTTP_EXTERNAL=test quickdid --help
1364
1365# Test with specific values
1366CACHE_TTL_MEMORY=0 quickdid --help # Will fail validation
1367
1368# Check parsed configuration (with debug logging)
1369RUST_LOG=debug HTTP_EXTERNAL=test quickdid
1370```
1371
1372## Best Practices
1373
1374### Security
1375
13761. Use environment-specific configuration management
13772. Use TLS for Redis connections in production (`rediss://`)
13783. Never commit sensitive configuration to version control
13795. Implement network segmentation for Redis access
1380
1381### Performance
1382
13831. **With Redis**: Use lower memory cache TTL (300-600s)
13842. **With SQLite**: Use moderate memory cache TTL (600-1800s)
13853. **Without persistent cache**: Use higher memory cache TTL (1800-3600s)
13864. **High traffic**: Increase QUEUE_BUFFER_SIZE (5000-10000)
13875. **Multi-region**: Use region-specific QUEUE_WORKER_ID
1388
1389### Caching and Queue Strategy
1390
13911. **Multi-instance/HA deployments**: Use Redis for distributed caching and queuing
13922. **Single-instance deployments**: Use SQLite for persistent caching and queuing
13933. **Development/testing**: Use memory-only caching with MPSC queuing
13944. **Hybrid setups**: Configure both Redis and SQLite for redundancy
13955. **Real-time sync**: Enable Jetstream consumer for live cache updates
13966. **Queue adapter guidelines**:
1397 - Redis: Best for multi-instance deployments with distributed processing
1398 - SQLite: Best for single-instance deployments needing persistence
1399 - MPSC: Best for single-instance deployments without persistence needs
14007. **Cache TTL guidelines**:
1401 - Redis: Shorter TTLs (1-7 days) for frequently updated handles
1402 - SQLite: Longer TTLs (7-90 days) for stable single-instance caching
1403 - Memory: Short TTLs (5-30 minutes) as fallback
14048. **Jetstream guidelines**:
1405 - Production: Enable for real-time cache synchronization
1406 - High-traffic: Essential for reducing stale data
1407 - Development: Can be disabled for simpler testing
1408 - Monitor WebSocket connection health in production
1409
1410### Monitoring
1411
14121. Set descriptive QUEUE_WORKER_ID for log correlation
14132. Use structured logging with appropriate RUST_LOG levels
14143. Monitor Redis memory usage and adjust TTLs accordingly
14154. Track cache hit rates to optimize TTL values
1416
1417### Deployment
1418
14191. Use `.env` files for local development
14202. Use secrets management for production configurations
14213. Set resource limits in container orchestration
14224. Use health checks to monitor service availability
14235. Implement gradual rollouts with feature flags
14246. **SQLite deployments**: Ensure persistent volume for database file
14257. **Redis deployments**: Configure Redis persistence and backup
14268. **Hybrid deployments**: Test fallback scenarios (Redis unavailable)