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