AUTONOMY DIRECTORATE

๐Ÿ  Main

๐Ÿงช Interactive Apps

๐Ÿ“ฐ News

๐Ÿ›ก๏ธ PQ Crypta Proxy

๐Ÿ‘ค Account

โŸจ QUANTUM ERROR PORTAL โŸฉ

Navigate the Error Dimensions

PQ Crypta Logo

Proxy Control Plane

PQCrypta Reverse Proxy — Live Configuration Dashboard

๐Ÿ”’ Read Only Live Config proxy-config.toml
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐ŸŒ
Primary Port
443
QUIC/HTTP3/WebTransport
QUIC, HTTP/3 and WebTransport listener. Also serves HTTP/2 and HTTP/1.1 via ALPN negotiation on the same port.server.udp_port
โšก
Max Connections
10,000
Concurrent QUIC sessions
Maximum concurrent QUIC sessions across all clients. Prevents connection exhaustion under high load.server.max_connections
๐Ÿ›ก
PQC Algorithm
X25519MLKEM768
Hybrid key exchange active
Post-quantum key encapsulation mechanism used for TLS key exchange. ML-KEM-1024 provides NIST Level 5 quantum resistance. Applied in hybrid mode alongside classical X25519.pqc.preferred_kem
๐Ÿ”€
Backends
9
Defined single backends
Named upstream servers available for routing. Each backend has its own TLS mode, timeouts, health check path, and connection limits. Does not include pool members.[backends.NAME]
๐Ÿ—บ
Routes
40
Active routing rules
HTTP routing rules evaluated in order by host and path prefix or regex pattern. Each rule selects a backend or load-balanced pool and can override headers.[[routes]]
โš™
LB Algorithm
least_connections
Load balancing strategy
Default strategy for distributing requests across backend pool servers. Options: round_robin, least_connections, ip_hash, random, weighted. Individual pools can override this.load_balancer.default_algorithm
๐Ÿ”
Circuit Breaker
Active
Backend protection
Stops forwarding to backends that exceed the failure threshold. Uses a half-open state to probe recovery. Prevents cascading failures across the backend pool.circuit_breaker.enabled
โฑ
Rate Limit
Configured
Multi-layer rate limiting
Multi-layer rate limiting: global RPS cap, per-IP limits, per-API-key quotas, and AI-based adaptive rate control. Redis-backed for distributed enforcement across instances.[rate_limiting] ยท [advanced_rate_limiting]
๐Ÿ’พ
Response Cache
128
MB RFC 9111 cache
In-memory HTTP response cache following RFC 9111 (Cache-Control semantics). Reduces backend load for cacheable GET responses. Shared across all routes.cache.max_size_mb
๐Ÿ“ก
ALPN Protocols
h3, h2, http/1.1
+ 1 more
TLS Application-Layer Protocol Negotiation list advertised during the handshake. Controls which HTTP versions clients can request. h3=HTTP/3, h2=HTTP/2, http/1.1.tls.alpn_protocols
๐Ÿ”
TLS Min Version
TLS 1.3
QUIC requires TLS 1.3
Minimum accepted TLS version for incoming connections. QUIC mandates TLS 1.3. TLS 1.2 may be enabled for HTTP/1.1 and HTTP/2 legacy client compatibility.tls.min_version
๐Ÿค–
JA3/JA4 Fingerprint
Enabled
TLS fingerprint detection
Fingerprints the TLS ClientHello to identify bot families, automated scanners, and malicious clients by their TLS stack signature. Cross-referenced against blocklists.fingerprint.enabled
โšก
Server
bind_address, udp_port, max_connections
QUIC/HTTP3 listener settings: bind address, ports, connection limits, worker threads, idle timeouts, and graceful shutdown behaviour.
๐Ÿ”
TLS & PKI
cert_path, alpn_protocols, ocsp_stapling
TLS certificate paths, ALPN protocol list, minimum TLS version, OCSP stapling, mTLS client auth, and ACME/Let's Encrypt auto-renewal.
๐Ÿ›ก
Post-Quantum Crypto
provider, preferred_kem, fallback
Post-quantum cryptography: KEM algorithm selection (ML-KEM-1024), hybrid mode toggle, OQS provider path, and classical fallback policy.
๐Ÿ”’
Security & WAF
dos_protection, blocked_ips, geoip
WAF and threat protection: DoS limits, static IP/CIDR blocklists, GeoIP country blocking, TLS fingerprint rules, and suspicious pattern detection.
โฑ
Rate Limiting
basic + advanced, redis, adaptive
Basic global RPS caps plus advanced per-IP, per-API-key, and per-route quotas. Redis-backed for distributed enforcement. Includes AI-based adaptive rate control.
๐Ÿ”
Circuit Breaker
failure_threshold, half_open
Automatically opens when a backend exceeds the failure threshold, then probes recovery via a half-open state. Prevents cascading failures across the pool.
โšก
HTTP/3 & Cache
otel, cache RFC 9111
HTTP response cache (RFC 9111 Cache-Control), OpenTelemetry tracing export, and HTTP/3-specific QUIC transport tuning parameters.
๐Ÿ“‹
Security Headers
HSTS, CSP, CORS, NEL, Report-To
Security and compliance response headers: HSTS, Content-Security-Policy, CORS policy, Permissions-Policy, NEL, Report-To, and custom header injection/removal rules.
๐Ÿ”€
Backends & LB
9 backends, least_connections
Upstream backend definitions (individual servers and load-balanced pools), default LB algorithm, connection pool sizing, health check paths, and canary traffic splitting.
๐Ÿ—บ
Routes
40 routing rules across 4 host(s)
HTTP routing rules matched by host and path. Each rule selects a backend or pool, can override headers, enforce HTTPS redirect, and apply per-route CORS or rate limit overrides.
๐Ÿ“
Logging & Admin
json logs, admin management API
Structured JSON logging level and output, admin management API bind address and auth token, and database blocklist sync configuration for dynamic IP/fingerprint blocking.
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
โšก Server Configuration [server] 12 settings โ–ผ
bind_address

Bind address for QUIC/UDP listener

udp_portport

Primary UDP port for QUIC/HTTP3/WebTransport

max_connectionsconnections

Maximum concurrent connections

max_streams_per_connectionstreams

Maximum concurrent streams per QUIC connection

keepalive_interval_secsseconds

Keep-alive interval

max_idle_timeout_secsseconds

Maximum idle timeout before connection close

worker_threadsthreads

Worker threads (0 = auto-detect CPU cores)

graceful_shutdown_timeout_secsseconds

Graceful shutdown drain timeout after SIGTERM before forced exit

enable_ipv6

Enable IPv6 dual-stack binding

additional_ports

Additional ports to listen on (all support QUIC/HTTP3/WebTransport)

4434
webtransport_allowed_origins

Allowed WebTransport origins โ€” browser Origin header validation. Empty = reject all browser connections.

https://pqcrypta.comhttps://www.pqcrypta.comhttps://api.pqcrypta.com
โ†ฉ HTTP Redirect [http_redirect] 4 settings โ–ผ
enabled

Enable HTTP redirect server on port 80

portport

HTTP port โ€” listens for plain HTTP and redirects to HTTPS

redirect_to_https

Redirect all HTTP traffic to HTTPS

allowed_domains

Allowed hostnames for the HTTPโ†’HTTPS redirect. Requests with a Host header not in this list receive 400 (prevents open-redirect abuse).

pqcrypta.comapi.pqcrypta.comwww.pqcrypta.com
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ” TLS Configuration [tls] 9 settings โ–ผ
cert_path

Path to TLS certificate chain (PEM format)

key_path

Path to TLS private key (PEM format)

ca_cert_path

Optional CA certificate for client certificate verification (mTLS). Not set = mTLS disabled unless require_client_cert is true.

require_client_cert

Require client certificates (mTLS mode)

min_version

Minimum TLS version โ€” only TLS 1.3 is supported for QUIC

  • 1.3 required for QUIC
  • 1.2
alpn_protocols

ALPN protocols advertised during TLS handshake

h3h2http/1.1webtransport
ocsp_stapling

Enable OCSP stapling for revocation status

cert_reload_interval_secsseconds

Certificate hot-reload interval (0 = disabled)

enable_0rtt

Enable 0-RTT early data for faster reconnections. โš ๏ธ Vulnerable to replay attacks.

๐Ÿ”„ ACME Certificate Automation [acme] 11 settings โ–ผ
enabled

Enable ACME certificate automation (Let's Encrypt)

domains

Domains to manage certificates for

pqcrypta.comapi.pqcrypta.com
challenge_type

ACME challenge type for domain validation

  • http-01 port 80 required
  • dns-01
  • tls-alpn-01
directory_url

ACME directory URL

email

Contact email for Let's Encrypt notifications

certs_path

Directory to store managed certificates

account_path

ACME account credentials storage

renewal_daysdays

Renew certificates this many days before expiry

check_interval_hourshours

Check interval for certificate expiry

use_ecdsa

Use ECDSA P-256 keys โ€” smaller keys, faster TLS handshakes than RSA

accept_tos

Accept CA terms of service (required for Let's Encrypt)

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ›ก Post-Quantum Cryptography [pqc] 12 settings โ–ผ
enabled

Enable PQC hybrid key exchange in TLS handshake

provider

PQC provider โ€” auto uses rustls for QUIC, OpenSSL for broader algorithms

  • auto recommended
  • rustls pure Rust, QUIC-native
  • openssl3.5 ML-KEM native
openssl_path

Path to OpenSSL 3.5+ binary with PQC support

openssl_lib_path

OpenSSL library path for dynamic linking

preferred_kem

Preferred KEM algorithm for hybrid key exchange (IETF standard)

  • X25519MLKEM768 recommended hybrid
  • x25519_kyber768 hybrid classical+PQ
  • SecP256r1MLKEM768
  • SecP384r1MLKEM1024 Level 5
  • ML-KEM-1024 FIPS 203 pure PQC
fallback_to_classical

Fall back to classical TLS if PQC is unavailable

min_security_levelNIST level

Minimum NIST security level (1=128-bit, 3=192-bit, 5=256-bit)

additional_kems

Additional KEM algorithms to offer (in preference order after preferred_kem)

SecP256r1MLKEM768SecP384r1MLKEM1024
enable_signatures

Enable PQC signatures (ML-DSA) โ€” requires pqc-signatures feature

require_hybrid

Require hybrid mode โ€” reject pure PQC or pure classical connections

verify_provider

Verify OpenSSL provider integrity at startup

check_key_permissions

Check TLS key file permissions (should be 0600 or 0400)

strict_key_permissions

Fail startup if key permissions are insecure (vs just warning)

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ”’ Security Settings [security] 15 settings โ–ผ
max_request_sizebytes

Maximum request body size

max_header_sizebytes

Maximum header size

connection_timeout_secsseconds

Connection establishment timeout

dos_protection

Enable DoS protection layer

max_connections_per_ipconnections

Maximum concurrent connections from a single IP

blocked_ips

Blocked IP addresses (manual blocklist)

No IPs blocked
allowed_ips

Allowed IP allowlist (empty = allow all)

Allowlist disabled โ€” all IPs permitted
blocked_countries

Blocked ISO 3166-1 alpha-2 country codes

No countries blocked
error_4xx_threshold

4xx errors before triggering suspicious-pattern check

min_requests_for_error_check

Minimum requests before error rate check activates

error_rate_threshold

Error rate (0.0โ€“1.0) that triggers suspicious pattern (e.g. 0.7 = 70%)

error_window_secsseconds

Sliding window duration for error detection

auto_block_threshold

Suspicious pattern count before auto-block triggers

auto_block_duration_secsseconds

Duration of automatic IP block after threshold exceeded

๐Ÿ”ฌ TLS Fingerprint Detection (JA3/JA4) [fingerprint] 7 settings โ–ผ
enabled

Enable TLS fingerprint detection middleware

block_malicious

Automatically block connections presenting known-malicious JA3/JA4 fingerprints. false = advisory-only (log but not block).

malicious_block_duration_secsseconds

Block duration for confirmed malicious fingerprints

suspicious_block_duration_secsseconds

Block duration for suspicious fingerprints with high request rate

suspicious_rate_threshold

Request count threshold to trigger suspicious fingerprint rate check

suspicious_rate_window_secsseconds

Time window for suspicious rate detection

cache_max_age_secsseconds

Fingerprint cache max age before cleanup

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
โฑ Basic Rate Limiting [rate_limiting] 5 settings โ–ผ
enabled

Enable basic rate limiting (overridden by advanced when both enabled)

requests_per_secondreq/s

Maximum requests per second per IP address

burst_size

Token bucket burst size โ€” allows short spikes above the rate limit

connection_rate_limit

Enable connection rate limiting (new connections per second)

connections_per_secondconn/s

New connections allowed per second per IP

๐Ÿง  Advanced Rate Limiting [advanced_rate_limiting] composite keys, JA3, Redis, adaptive ML โ–ผ
Core Settings
enabled

Enable advanced multi-dimensional rate limiting (overrides basic)

ipv6_subnet_bitsbits

IPv6 subnet grouping โ€” /64 subnets treated as a single client (NAT-aware)

trusted_proxies

Trusted proxies for X-Forwarded-For parsing

[private]/8[private]/12[private]/16[loopback]
Key Strategy [advanced_rate_limiting.key_strategy]
order

Priority order for rate limit key resolution (first found wins)

1: api_key 2: jwt_subject 3: ja3_fingerprint 4: real_ip 5: source_ip
fallback

Key resolution fallback when no other key is found

  • source_ip default fallback
  • real_ip
  • ja3_fingerprint
use_composite

Use composite key (combines multiple dimensions)

Headers [advanced_rate_limiting.headers]
api_key

Header name for API key extraction

user_id

Header name for user ID extraction

tenant_id

Header name for tenant ID extraction

real_ip

Header name for real IP extraction

Global Limits [advanced_rate_limiting.global_limits]
requests_per_secondreq/s

Global DDoS protection layer req/s

burst_size

Global burst bucket size

Per-IP Limits [advanced_rate_limiting.global_limits.per_ip]
requests_per_secondreq/s

Per-IP requests per second

burst_size

Per-IP burst size

requests_per_minutereq/min

Per-IP requests per minute

requests_per_hourreq/hr

Per-IP requests per hour

Per-Fingerprint Limits [advanced_rate_limiting.global_limits.per_fingerprint]
requests_per_secondreq/s

Per JA3/JA4 fingerprint req/s

burst_size

Per-fingerprint burst size

requests_per_minutereq/min

Per-fingerprint requests per minute

requests_per_hourreq/hr

Per-fingerprint requests per hour

Per-API-Key Limits [advanced_rate_limiting.global_limits.per_api_key]
requests_per_secondreq/s

Per API key requests per second

burst_size

Per API key burst size

requests_per_minutereq/min

Per API key requests per minute

requests_per_hourreq/hr

Per API key requests per hour

Per-Composite Limits [advanced_rate_limiting.global_limits.per_composite]
requests_per_secondreq/s

Per composite key req/s

burst_size

Per composite key burst size

requests_per_minutereq/min

Per composite key requests per minute

requests_per_hourreq/hr

Per composite key requests per hour

Redis Distributed [advanced_rate_limiting.redis]
url

Redis URL for distributed counter sharing across proxy instances

key_prefix

Redis key prefix for all rate limit counters

connect_timeout_msms

Redis connection timeout

command_timeout_msms

Redis command timeout โ€” fast fail to prevent blocking

distribute_per_second

Use per-second distributed sliding window

JA3/JA4 Fingerprint Limiting [advanced_rate_limiting.fingerprint_limiting]
enabled

Enable fingerprint-based rate limiting (NAT-friendly)

prefer_over_ip

Prefer fingerprint key over IP address for limiting

blocked_fingerprints

Explicitly blocked JA3/JA4 fingerprint hashes

No fingerprints blocked
Unknown Fingerprint Limits [advanced_rate_limiting.fingerprint_limiting.unknown_limits]
requests_per_secondreq/s

Rate limit for unknown/unclassified fingerprints

burst_size

Burst size for unknown fingerprints

requests_per_minutereq/min

Per-minute limit for unknown fingerprints

requests_per_hourreq/hr

Per-hour limit for unknown fingerprints

Adaptive Rate Limiting [advanced_rate_limiting.adaptive]
enabled

Enable ML-inspired adaptive rate limiting with anomaly detection

baseline_window_secsseconds

Baseline measurement window for normal traffic profiling

sensitivity

Detection sensitivity (0.0 = off, 1.0 = maximum)

auto_adjust

Automatically adjust limits based on detected anomalies

min_samples

Minimum sample count before adaptive limiting activates

std_dev_multiplier

Standard deviation multiplier for anomaly threshold (requests > mean + N*stddev = anomaly)

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ” Circuit Breaker [circuit_breaker] 6 settings โ–ผ
enabled

Enable circuit breaker for backend protection against cascading failures

failure_threshold

Failure count to open the circuit

half_open_delay_secsseconds

Time before circuit transitions from Open โ†’ Half-Open state

half_open_max_requests

Maximum test requests allowed in Half-Open state

success_threshold

Success count required to close circuit from Half-Open state

stale_counter_cleanup_secsseconds

Stale request counter cleanup interval

๐Ÿ”— HTTP Connection Pool [connection_pool] 4 settings โ–ผ
idle_timeout_secsseconds

How long idle connections remain in pool before being closed

max_idle_per_host

Maximum idle connections kept per backend host

max_connections_per_host

Maximum total connections per backend host

acquire_timeout_msms

Connection acquire timeout from pool

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ“ก OpenTelemetry Distributed Tracing [otel] 4 settings โ–ผ
enabled

Enable OTLP span export to tracing backend (Jaeger, Grafana Tempo, Honeycomb, etc.)

service_name

Service name shown in the tracing UI

otlp_endpoint

OTLP HTTP/JSON endpoint โ€” use your collector or tracing backend

sample_ratio

Sampling ratio: 1.0 = every trace, 0.1 = 10%, 0.0 = off. Uses ParentBased(TraceIdRatio).

๐Ÿ’พ Response Cache (RFC 9111) [cache] 6 settings โ–ผ
enabled

Enable RFC 9111 compliant response cache

max_size_mbMB

Maximum cache size in memory

default_ttl_secsseconds

Default TTL for cacheable responses without explicit Cache-Control

max_body_size_bytesbytes

Maximum response body size to cache

no_cache_set_cookie

Never cache responses that set cookies

excluded_paths

Paths excluded from caching

/api//ws/stream/auth/admin
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ“‹ Security Headers [headers] 17 settings โ–ผ
๐Ÿ”
Header / Setting Value
Strict-Transport-Security
hsts
max-age=63072000; includeSubDomains; preload
X-Frame-Options
x_frame_options
DENY
X-Content-Type-Options
x_content_type_options
nosniff
Referrer-Policy
referrer_policy
strict-origin-when-cross-origin
Permissions-Policy
permissions_policy
camera=(), microphone=(), geolocation=(), interest-cohort=()
Cross-Origin-Opener-Policy
cross_origin_opener_policy
unsafe-none
Cross-Origin-Embedder-Policy
cross_origin_embedder_policy
unsafe-none
Cross-Origin-Resource-Policy
cross_origin_resource_policy
cross-origin
X-Permitted-Cross-Domain-Policies
x_permitted_cross_domain_policies
none
X-Download-Options
x_download_options
noopen
X-DNS-Prefetch-Control
x_dns_prefetch_control
off
X-Quantum-Resistant
x_quantum_resistant
ML-KEM-1024, ML-DSA-87, X25519MLKEM768
X-Security-Level
x_security_level
Post-Quantum Ready
HTTP/3 Priority
priority
u=3,i=?0
Accept-CH
accept_ch
DPR, Viewport-Width, Width, ECT, RTT, Downlink, Sec-CH-UA-Platform, Sec-CH-UA-Mobile
NEL
nel
{"report_to":"default","max_age":86400,"include_subdomains":true}
Report-To
report_to
{"group":"default","max_age":86400,"endpoints":[{"url":"https://api.pqcrypta.com/reports"}]}
Server-Timing
server_timing_enabled
Enabled
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
โš– Load Balancer [load_balancer] 10 settings โ–ผ
enabled

Enable load balancing (auto-enabled when backend_pools defined)

default_algorithm

Default load balancing algorithm for all pools

  • least_connections active
  • round_robin
  • weighted_round_robin
  • random
  • ip_hash
  • least_response_time
Session Affinity [load_balancer.session_affinity]
enabled

Enable sticky sessions (session affinity via cookie)

cookie_name

Cookie name for sticky session tracking

cookie_ttl_secsseconds

Cookie TTL in seconds (0 = session cookie)

cookie_secure

Use Secure cookies (HTTPS only)

cookie_httponly

Use HttpOnly cookies (prevent XSS access)

cookie_samesite

SameSite attribute for sticky session cookie

  • lax cross-site allowed
  • strict
  • none requires Secure
Queue [load_balancer.queue]
enabled

Enable request queue for when all backends are saturated

max_size

Maximum queued requests before returning 503

timeout_msms

Maximum wait time in queue before timeout

Slow Start [load_balancer.slow_start]
enabled

Gradually increase traffic to recovering backends

duration_secsseconds

Duration of slow start ramp-up period

initial_weight_percent%

Initial traffic weight during slow start

Connection Draining [load_balancer.connection_draining]
enabled

Enable graceful connection draining on backend removal

timeout_secsseconds

Maximum drain time before forceful close

apache HTTP1
address [loopback]:8080
tls_mode terminate
timeout_ms 30,000 ms
max_connections 100
health_check /health
check_interval 30s
api HTTP1
address [loopback]:3003
tls_mode terminate
timeout_ms 30,000 ms
max_connections 100
health_check /health
check_interval 30s
internal-api HTTP1
address internal.example.com:443
tls_mode reencrypt
timeout_ms 30,000 ms
max_connections 50
health_check /health
check_interval 30s
tls_cert /etc/pqcrypta/internal-ca.pem
tls_client_cert /etc/pqcrypta/client.pem
tls_sni internal.example.com
php UNIX
address unix:/run/php-fpm.sock
tls_mode terminate
timeout_ms 30,000 ms
max_connections 100
health_check /health
check_interval 30s
http2-backend HTTP2
address api.internal.example.com:443
tls_mode reencrypt
timeout_ms 30,000 ms
max_connections 50
health_check /health
check_interval 30s
quic-backend HTTP3
address backend.example.com:4433
tls_mode reencrypt
timeout_ms 30,000 ms
max_connections 50
tcp-service TCP
address [loopback]:9000
tls_mode terminate
timeout_ms 10,000 ms
max_connections 100
grafana HTTP1
address [loopback]:3000
tls_mode terminate
timeout_ms 30,000 ms
max_connections 50
health_check /api/health
check_interval 30s
prometheus HTTP1
address [loopback]:9090
tls_mode terminate
timeout_ms 30,000 ms
max_connections 50
health_check /-/healthy
check_interval 30s
๐Ÿ”€ Pool: api-pool [backend_pools.api-pool] 2 servers โ–ผ
algorithm

Load balancing algorithm for this pool

health_aware

Skip unhealthy backends when routing

affinity

Session affinity mode (none, cookie, ip_hash, header)

health_check_path

Health check path for all servers in pool

health_check_interval_secsseconds

Health check interval

Canary / Traffic Splitting [backend_pools.api-pool.canary]
enabled

Enable canary routing for this pool

sticky

Keep users on the same canary server once assigned

sticky_cookie_name

Cookie name for canary server assignment

sticky_cookie_ttl_secsseconds

Cookie lifetime for canary assignment

auto_rollback

Automatically suspend canary on high error rate

rollback_error_rate

Error rate threshold to trigger auto-rollback (0.0โ€“1.0)

rollback_window_secsseconds

Sliding window for canary error tracking

rollback_min_requests

Minimum requests before rollback can trigger

Servers
# Address Weight Priority Max Conn Timeout TLS Mode Flags
1 [loopback]:3003 100 1 100 30000 ms terminate โ€”
2 [loopback]:3004 100 1 100 30000 ms terminate โ€”
๐Ÿ”€ Pool: apache-pool [backend_pools.apache-pool] 2 servers โ–ผ
algorithm

Load balancing algorithm for this pool

health_aware

Skip unhealthy backends when routing

affinity

Session affinity mode (none, cookie, ip_hash, header)

health_check_path

Health check path for all servers in pool

health_check_interval_secsseconds

Health check interval

Servers
# Address Weight Priority Max Conn Timeout TLS Mode Flags
1 [loopback]:8080 100 1 200 โ€” terminate โ€”
2 [loopback]:8081 100 1 200 โ€” terminate โ€”
๐Ÿ”€ Pool: session-pool [backend_pools.session-pool] 2 servers โ–ผ
algorithm

Load balancing algorithm for this pool

health_aware

Skip unhealthy backends when routing

affinity

Session affinity mode (none, cookie, ip_hash, header)

health_check_path

Health check path for all servers in pool

health_check_interval_secsseconds

Health check interval

Servers
# Address Weight Priority Max Conn Timeout TLS Mode Flags
1 [loopback]:8000 100 1 100 โ€” terminate โ€”
2 [loopback]:8001 100 1 100 โ€” terminate โ€”
๐Ÿ”€ Pool: secure-pool [backend_pools.secure-pool] 2 servers โ–ผ
algorithm

Load balancing algorithm for this pool

health_aware

Skip unhealthy backends when routing

affinity

Session affinity mode (none, cookie, ip_hash, header)

affinity_header

Header name when affinity = header

queue_max_size

Pool-specific queue max size (overrides global)

queue_timeout_msms

Pool-specific queue timeout in ms (overrides global)

health_check_path

Health check path for all servers in pool

health_check_interval_secsseconds

Health check interval

Servers
# Address Weight Priority Max Conn Timeout TLS Mode Flags
1 [private]:443 100 1 50 30000 ms reencrypt sni:backend1.internal.com
2 [private]:443 100 1 50 30000 ms reencrypt sni:backend2.internal.com
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ—บ Route Definitions [[routes]] 40 routes โ–ผ
๐Ÿ”
40 routes
Name Host Path Backend Type Priority
api-route api.example.com prefix:/ api HTTP 100
Routing
backend:api
type:http
priority:100
forward_client_identity:true
client_identity_header:X-Client-IP
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
main-site example.com prefix:/ apache HTTP 100
Routing
backend:apache
type:http
priority:100
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
www-redirect www.example.com prefix:/ โ†’ https://example.com 301 REDIRECT 1
Routing
backend:โ€”
type:redirect
priority:1
Redirect
redirect:https://example.com
permanent:301 (permanent)
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
internal-api-route example.com prefix:/internal-api internal-api HTTP 50
Routing
backend:internal-api
type:http
priority:50
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
seo-old-path example.com prefix:/old_path โ†’ /new-path 301 REDIRECT 1
Routing
backend:โ€”
type:redirect
priority:1
Redirect
redirect:/new-path
permanent:301 (permanent)
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
seo-legacy example.com prefix:/legacy_page โ†’ /modern-page 301 REDIRECT 1
Routing
backend:โ€”
type:redirect
priority:1
Redirect
redirect:/modern-page
permanent:301 (permanent)
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
webtransport-encrypt api.example.com prefix:/encrypt api WebTransport 10
Routing
backend:api
type:webtransport
priority:10
stream_to_method:POST
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
webtransport-stream api.example.com prefix:/stream api WebTransport 10
Routing
backend:api
type:webtransport
priority:10
stream_to_method:POST
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
custom-headers example.com prefix:/embed apache HTTP 50
Routing
backend:apache
type:http
priority:50
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
php-route example.com prefix:/app php HTTP 80
Routing
backend:php
type:http
priority:80
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
api-versioned api.example.com regex:^/v[0-9]+/.* api HTTP 20
Routing
backend:api
type:http
priority:20
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
exact-health api.example.com exact:/health api HTTP 5
Routing
backend:api
type:http
priority:5
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
sanitized-api api.example.com prefix:/public api HTTP 60
Routing
backend:api
type:http
priority:60
forward_client_identity:true
Remove Headers
X-Internal-Token, X-Debug-Info
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
seo-friendly example.com prefix:/sitemap apache HTTP 30
Routing
backend:apache
type:http
priority:30
allow_http11:true
skip_bot_blocking:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
checkout-page example.com prefix:/checkout apache HTTP 40
Routing
backend:apache
type:http
priority:40
stripe_compatibility:true โ€” removes COEP/COOP headers
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
long-running-api api.example.com prefix:/export api HTTP 45
Routing
backend:api
type:http
priority:45
timeout_override_ms:120000
forward_client_identity:true
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
grafana pqcrypta.com prefix:/grafana grafana HTTP 20
Routing
backend:grafana
type:http
priority:20
forward_client_identity:true
client_identity_header:X-Real-IP
stripe_compatibility:true โ€” removes COEP/COOP headers
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
prometheus pqcrypta.com prefix:/prometheus prometheus HTTP 20
Routing
backend:prometheus
type:http
priority:20
forward_client_identity:true
client_identity_header:X-Real-IP
(unnamed) * / โ€” HTTP โ€”
Routing
backend:โ€”
type:http
priority:โ€”
default * prefix:/ apache HTTP 1000
Routing
backend:apache
type:http
priority:1000
๐Ÿ”€ TLS Passthrough Routes [[passthrough_routes]] 3 passthrough routes โ–ผ
Name SNI Pattern Backend Proxy Protocol Timeout
external-mail mail.example.com 192.0.2.10:443 Disabled 30000 ms
internal-wildcard *.internal.example.com 192.0.2.20:443 Enabled 30000 ms
legacy-service legacy.example.com 192.0.2.100:443 Disabled 60000 ms
๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ“ Logging Configuration [logging] 4 settings โ–ผ
level

Log verbosity level

  • trace very verbose
  • debug
  • info active
  • warn
  • error errors only
format

Log output format

  • json structured logging
  • text human readable
access_log

Enable access logging for all requests

access_log_file

Access log file path (empty/commented = stdout)

๐Ÿ”ง Admin API [admin] 6 settings โ–ผ
enabled

Enable admin HTTP API for runtime management

bind_address

Admin API bind address โ€” 127.0.0.1 for local-only access

portport

Admin API listening port

require_mtls

Require mutual TLS for admin API connections

auth_token

Bearer token for admin API authentication (AUD-01)

[NOT SET โ€” REQUIRED in production]
allowed_ips

Allowed IP addresses for admin API access

[loopback]::1
๐Ÿ—„ Database Blocklist Sync [database] 8 settings โ–ผ
enabled

Enable database sync for IP/fingerprint blocklists from PostgreSQL

host

PostgreSQL host

portport

PostgreSQL port

database

Database name

user

Database user

min_connections

Minimum connection pool size

max_connections

Maximum connection pool size

connection_timeout_secsseconds

Database connection timeout

sync_interval_secsseconds

Blocklist refresh interval

max_blocklist_size

Maximum blocklist entries in memory

Blocklist Queries [database.blocklist_queries]
blocked_ips

SQL query to fetch blocked IP addresses (returns: ip_address, reason, expires_at)

blocked_fingerprints

SQL query to fetch blocked TLS fingerprints (returns: fingerprint, type, reason)

blocked_countries

SQL query to fetch blocked country codes (returns: country_code, reason)

Database Logging [database.logging]
enabled

Log proxy-level detections back to database for analytics

log_blocked_requests

Log blocked requests to database

log_suspicious_patterns

Log suspicious patterns detected at proxy level

detection_table

Database table for proxy detection records

insert_detection

SQL template for inserting proxy detection records (uses $1, $2, โ€ฆ for parameters)

๐Ÿ”’This is a read-only control plane. All controls display current configuration values from proxy-config.toml. No changes can be made from this interface.
๐Ÿ“„ proxy-config.toml
# PQCrypta Proxy Configuration
# =============================
# Production-ready HTTP/3/QUIC/WebTransport reverse proxy with hybrid PQC TLS.
#
# All values are configurable - no hardcoded ports, paths, or addresses.
# CLI arguments and environment variables can override these settings.

# =============================
# Server Configuration
# =============================
[server]
# Bind address for QUIC/UDP listener
bind_address = "0.0.0.0"

# Primary UDP port for QUIC/HTTP3/WebTransport (default: 443)
udp_port = 443

# Additional ports to listen on (all support QUIC/HTTP3/WebTransport)
# Note: port 4433 is omitted here โ€” the proxy binds it exclusively as the
# dedicated WebTransport server (hardcoded in main.rs). Listing it here would
# cause a second QUIC listener to attempt the same port and also advertise it
# in Alt-Svc as a generic h3 endpoint, which is incorrect.
additional_ports = ["[configured]"]

# Allowed origins for browser WebTransport sessions (SR-02).
# Browsers send an Origin header; sessions whose origin is not listed are
# rejected with 403.  Non-browser / native clients (no Origin header) are
# always accepted.  Empty list = reject ALL browser connections.
webtransport_allowed_origins = ["https://pqcrypta.com", "https://www.pqcrypta.com", "https://api.pqcrypta.com"]

# Maximum concurrent connections
max_connections = 10000

# Maximum concurrent streams per connection
max_streams_per_connection = 1000

# Keep-alive interval in seconds
keepalive_interval_secs = 15

# Maximum idle timeout in seconds
max_idle_timeout_secs = 120

# Enable IPv6 dual-stack binding
enable_ipv6 = false

# Worker threads (0 = auto-detect based on CPU cores)
worker_threads = 0

# Graceful shutdown drain timeout in seconds (AUD-11).
# After SIGTERM/SIGQUIT, the proxy waits up to this many seconds for in-flight
# requests to complete before exiting.  Must not exceed systemd TimeoutStopSec.
graceful_shutdown_timeout_secs = 30

# =============================
# TLS Configuration
# =============================
[tls]
# Path to TLS certificate chain (PEM format)
# Managed by built-in ACME service (see [acme] section below)
cert_path = "/[system]/[key-material]"

# Path to TLS private key (PEM format)
key_path = "/[system]/[key-material]"

# Optional: CA certificate for client verification (mTLS)
# ca_cert_path = "/[system]/[key-material]"

# Require client certificates (mTLS mode)
require_client_cert = false

# ALPN protocols to advertise (h3/webtransport for QUIC, h2/http1.1 for TCP)
alpn_protocols = ["h3", "h2", "http/1.1", "webtransport"]

# Minimum TLS version (only "1.3" supported for QUIC)
min_version = "1.3"

# Enable OCSP stapling
ocsp_stapling = true

# Certificate reload interval in seconds (0 = disabled)
cert_reload_interval_secs = 3600

# Enable 0-RTT (early data) for faster reconnections
# SECURITY WARNING: 0-RTT is vulnerable to replay attacks!
# Only enable if your application can handle replay protection,
# or if the performance benefit outweighs the security risk.
# Default: false (disabled for security)
enable_0rtt = false

# =============================
# HTTPโ†’HTTPS Redirect Server
# =============================
[http_redirect]
# Enable HTTP redirect server on port 80
enabled = true

# HTTP port (redirects to HTTPS on primary port)
port = 80

# Redirect all HTTP to HTTPS (301 permanent redirect)
redirect_to_https = true

# AUD-02: Allowed hostnames for the HTTPโ†’HTTPS redirect.
# Requests whose Host header is not in this list receive 400 Bad Request,
# preventing open-redirect abuse (attacker sends Host: evil.com and gets
# a redirect to https://evil.com/).
# Set to your canonical domain(s).  Empty list disables the check.
allowed_domains = ["pqcrypta.com", "api.pqcrypta.com", "www.pqcrypta.com"]

# =============================
# ACME Certificate Automation (Let's Encrypt)
# =============================
# Automatic TLS certificate provisioning and renewal via ACME protocol (RFC 8555).
# Checks cert expiry once daily โ€” actual ACME protocol only runs ~once every 60 days
# when renewal is needed (certs last 90 days, renewal triggers at 30 days remaining).
# HTTP-01 challenges served on port 80 before HTTPS redirect.

[acme]
# Enable ACME certificate automation
enabled = true

# Let's Encrypt production CA
directory_url = "https://acme-v02.api.letsencrypt.org/directory"

# Contact email for account registration and expiry notifications
# AUD-06: Do NOT commit a real email address here โ€” use a placeholder in version control.
# Replace with your actual operator address in the private config on each host.
email = "admin@example.com"

# Domains to include in the SAN certificate (single cert covers all)
domains = ["pqcrypta.com", "api.pqcrypta.com"]

# Certificate and key storage path
certs_path = "/[system]/certs"

# ACME account credentials storage
account_path = "/etc/pqcrypta/acme/account.json"

# Renew when certificate expires within this many days
# Let's Encrypt certs last 90 days; 30 days gives a comfortable renewal window
renewal_days = 30

# How often to check certificate expiry (hours)
# 24h = once daily. The check is local (reads cert file) โ€” zero network cost.
# ACME protocol only runs when renewal is actually needed (~once every 60 days).
check_interval_hours = 24

# Use ECDSA keys (P-256) โ€” smaller keys, faster TLS handshakes than RSA
use_ecdsa = true

# HTTP-01 challenge validation (served on port 80 redirect server)
challenge_type = "http-01"

# Accept CA terms of service
accept_tos = true

# =============================
# Response Cache (RFC 9111)
# =============================
[cache]
enabled = false
max_size_mb = 128
default_ttl_secs = 60
max_body_size_bytes = 2097152
excluded_paths = ["/api/", "/ws", "/stream", "/auth", "/admin"]
no_cache_set_cookie = true

# =============================
# OpenTelemetry Distributed Tracing
# =============================
# Propagates trace context across all HTTP transports:
#   - HTTP/1.1 and HTTP/2 (W3C traceparent/tracestate + B3 headers)
#   - HTTP/3 / QUIC
#   - WebTransport
#
# Compatible backends: Jaeger, Grafana Tempo, Honeycomb, Datadog, OTEL Collector
# Default OTLP HTTP port: 4318 (JSON), 4317 (gRPC โ€” not supported by this build)
[otel]
# Set to true to enable OTLP span export (default: false)
enabled = false

# Service name shown in the tracing UI (default: pqcrypta-proxy)
service_name = "pqcrypta-proxy"

# OTLP HTTP/JSON endpoint โ€” use your collector or tracing backend
# Jaeger:          http://localhost:4318
# Grafana Tempo:   http://localhost:4318
# OTEL Collector:  http://otel-collector:4318
otlp_endpoint = "http://localhost:4318"

# Sampling: 1.0 = record every trace, 0.1 = record 10%, 0.0 = off
# Uses ParentBased(TraceIdRatio) so downstream services inherit the decision.
sample_ratio = 1.0

# Optional resource attributes added to every span (arbitrary key/value pairs)
# [otel.resource_attributes]
# deployment.environment = "production"
# k8s.namespace = "pqcrypta"

# =============================
# Security Headers
# =============================
# These headers are automatically injected into all responses.
# The Server header is always replaced with "PQCProxy v0.1.0".
[headers]
# HTTP Strict Transport Security (2 years, preload-ready)
hsts = "max-age=63072000; includeSubDomains; preload"

# Prevent clickjacking
x_frame_options = "DENY"

# Prevent MIME-type sniffing
x_content_type_options = "nosniff"

# Control referrer information
referrer_policy = "strict-origin-when-cross-origin"

# Disable browser features (FLoC, camera, microphone, geolocation)
permissions_policy = "camera=(), microphone=(), geolocation=(), interest-cohort=()"

# Cross-origin isolation headers
# NOTE: require-corp/same-origin can break apps like Grafana that use modern JS
cross_origin_opener_policy = "unsafe-none"
cross_origin_embedder_policy = "unsafe-none"
cross_origin_resource_policy = "cross-origin"

# Additional security headers
x_permitted_cross_domain_policies = "none"
x_download_options = "noopen"
x_dns_prefetch_control = "off"

# Custom branding headers (advertise PQC capabilities)
x_quantum_resistant = "ML-KEM-1024, ML-DSA-87, X25519MLKEM768"
x_security_level = "Post-Quantum Ready"

# =============================
# HTTP/3 Performance & Monitoring Headers
# =============================
# Enable Server-Timing header for performance metrics
server_timing_enabled = true

# Accept-CH header for Client Hints (responsive content delivery)
accept_ch = "DPR, Viewport-Width, Width, ECT, RTT, Downlink, Sec-CH-UA-Platform, Sec-CH-UA-Mobile"

# NEL (Network Error Logging) for client-side error reporting
nel = '{"report_to":"default","max_age":86400,"include_subdomains":true}'

# Report-To endpoint configuration for NEL and other reports
report_to = '{"group":"default","max_age":86400,"endpoints":[{"url":"https://api.pqcrypta.com/reports"}]}'

# HTTP/3 Priority (RFC 9218) - u=0-7 (urgency), i=?0 (not incremental)
# u=3 is default urgency, i=?0 means non-incremental delivery
priority = "u=3,i=?0"

# =============================
# Post-Quantum Cryptography
# =============================
# Two TLS backends available:
# - rustls (default): Pure Rust, memory-safe, QUIC support, uses aws-lc-rs
# - OpenSSL 3.5+: Broader algorithm support, hardware acceleration
#
# Algorithm Support Matrix:
# | Algorithm           | rustls | OpenSSL 3.5+ |
# |---------------------|--------|--------------|
# | X25519MLKEM768      | โœ…     | โœ…           |
# | SecP256r1MLKEM768   | โณ     | โœ…           |
# | SecP384r1MLKEM1024  | โณ     | โœ…           |
# | ML-KEM-512/768/1024 | โœ…     | โœ…           |
# | ML-DSA-44/65/87     | ๐Ÿ”ง     | โœ…           |
# โœ… = Available, โณ = Planned, ๐Ÿ”ง = Requires pqc-signatures feature

[pqc]
# Enable PQC hybrid key exchange
enabled = true

# PQC provider selection:
# - "auto" (recommended): Use rustls for QUIC, OpenSSL for broader algorithms
# - "rustls": Pure Rust via aws-lc-rs (memory-safe, QUIC support)
# - "openssl3.5": OpenSSL 3.5+ with native ML-KEM (broader algorithms)
provider = "auto"

# Path to OpenSSL 3.5+ binary (for OpenSSL backend)
openssl_path = "/[system]/openssl-pq/..."

# OpenSSL library path
openssl_lib_path = "/[system]/openssl-pq/..."

# Preferred KEM algorithm for key exchange (IETF standard)
# Recommended: X25519MLKEM768 (NIST Level 3, best compatibility)
# Options:
#   Hybrid (classical + PQC):
#     - X25519MLKEM768 (recommended, IETF standard)
#     - SecP256r1MLKEM768 (NIST curve variant)
#     - SecP384r1MLKEM1024 (Level 5 security)
#     - X448MLKEM1024 (maximum security)
#   Pure ML-KEM (FIPS 203):
#     - ML-KEM-512 (Level 1)
#     - ML-KEM-768 (Level 3)
#     - ML-KEM-1024 (Level 5)
preferred_kem = "X25519MLKEM768"

# Fallback to classical TLS if PQC is unavailable
fallback_to_classical = true

# Minimum security level (NIST levels 1-5)
# 1 = 128-bit, 3 = 192-bit (recommended), 5 = 256-bit
min_security_level = 3

# Additional KEM algorithms to offer (in preference order after preferred_kem)
additional_kems = ["SecP256r1MLKEM768", "SecP384r1MLKEM1024"]

# Enable PQC signatures (ML-DSA) - requires pqc-signatures feature
enable_signatures = false

# Require hybrid mode (reject pure PQC or pure classical)
require_hybrid = false

# Security hardening options:

# Verify OpenSSL provider integrity at startup
verify_provider = true

# Check TLS key file permissions (should be 0600 or 0400)
check_key_permissions = true

# Fail startup if key permissions are insecure (vs just warning)
# AUD-09: Set to true so a misconfigured deployment with world-readable TLS key
# fails fast rather than silently serving traffic with an insecure key.
strict_key_permissions = true

# =============================
# Admin API Configuration
# =============================
[admin]
# Enable admin HTTP API
enabled = true

# Admin API bind address (use 127.0.0.1 for local-only access)
bind_address = "[loopback]"

# Admin API port
port = [configured]

# Require mTLS for admin API
require_mtls = false

# AUD-01: Bearer token for admin API authentication.
# REQUIRED: Generate a strong random token and set it here.
# Without this, any process on the host can call destructive endpoints
# (shutdown, reload) without credentials.
#
# Generate with:  openssl rand -base64 32
# Then set:       auth_token = "<your-generated-token>"
#
# IMPORTANT: Do NOT leave this commented out in production.
# auth_token = "CHANGE_ME_run_openssl_rand_base64_32_and_paste_result_here"

# Allowed IP addresses for admin API access
allowed_ips = ["[loopback]", "::1"]

# =============================
# Logging Configuration
# =============================
[logging]
# Log level: trace, debug, info, warn, error
level = "info"

# Log format: "json" or "text"
format = "json"

# Log file path (empty = stdout)
# file = "/[logs]/..."

# Enable access logs
access_log = true

# Access log file path
# access_log_file = "/[logs]/..."

# =============================
# Rate Limiting (Basic)
# =============================
[rate_limiting]
# Enable basic rate limiting
enabled = true

# Requests per second per IP
requests_per_second = [configured]

# Burst size for rate limiter
burst_size = [configured]

# Enable connection rate limiting
connection_rate_limit = true

# New connections per second per IP
connections_per_second = [configured]

# =============================
# Advanced Multi-Dimensional Rate Limiting
# =============================
# Cutting-edge rate limiting inspired by Cloudflare, Envoy, HAProxy, and Traefik.
# Features: composite keys, JA3 fingerprinting, X-Forwarded-For trust, adaptive ML.

[advanced_rate_limiting]
# Enable advanced rate limiting (overrides basic when enabled)
enabled = true

# IPv6 subnet grouping (64 = /64 subnets treated as single client)
ipv6_subnet_bits = 64

# Trusted proxies for X-Forwarded-For parsing (CIDR or IP)
trusted_proxies = ["[RFC1918]", "[RFC1918]", "[RFC1918]", "[loopback]"]

# Key resolution strategy
[advanced_rate_limiting.key_strategy]
# Priority order for key resolution (first found wins)
# Options: source_ip, real_ip, api_key, jwt_subject, ja3_fingerprint, ja4_fingerprint
order = ["api_key", "jwt_subject", "ja3_fingerprint", "real_ip", "source_ip"]

# Fallback key if none found
fallback = "source_ip"

# Enable composite keys (combine multiple keys)
use_composite = false

# Header names for key extraction
[advanced_rate_limiting.headers]
api_key = "X-API-Key"
user_id = "X-User-ID"
tenant_id = "X-Tenant-ID"
real_ip = "X-Real-IP"

# Global limits (DDoS protection layer)
[advanced_rate_limiting.global_limits]
requests_per_second = [configured]
burst_size = [configured]

[advanced_rate_limiting.global_limits.per_ip]
requests_per_second = [configured]
burst_size = [configured]
requests_per_minute = [configured]
requests_per_hour = [configured]

[advanced_rate_limiting.global_limits.per_fingerprint]
requests_per_second = [configured]
burst_size = [configured]
requests_per_minute = [configured]
requests_per_hour = [configured]

[advanced_rate_limiting.global_limits.per_api_key]
requests_per_second = [configured]
burst_size = [configured]
requests_per_minute = [configured]
requests_per_hour = [configured]

[advanced_rate_limiting.global_limits.per_composite]
requests_per_second = [configured]
burst_size = [configured]
requests_per_minute = [configured]
requests_per_hour = [configured]

# Distributed rate limiting via Redis (all proxy instances share counters)
[advanced_rate_limiting.redis]
url = "redis://[loopback]"
key_prefix = "pqcp"
connect_timeout_ms = 2000
command_timeout_ms = 50
distribute_per_second = true

# JA3/JA4 fingerprint-based limiting (NAT-friendly)
[advanced_rate_limiting.fingerprint_limiting]
enabled = true
prefer_over_ip = false  # Use fingerprint as primary key for NAT scenarios
blocked_fingerprints = []  # Block known malicious fingerprints

# Unknown fingerprint limits (more restrictive)
[advanced_rate_limiting.fingerprint_limiting.unknown_limits]
requests_per_second = [configured]
burst_size = [configured]
requests_per_minute = [configured]
requests_per_hour = [configured]

# Adaptive rate limiting (ML-inspired anomaly detection)
[advanced_rate_limiting.adaptive]
enabled = false  # Disabled by default, enable for production
baseline_window_secs = 3600  # 1 hour baseline learning
sensitivity = [configured]
auto_adjust = false
min_samples = 1000
std_dev_multiplier = [configured]  # Requests > mean + 3*std_dev = anomaly

# Per-route rate limits (uncomment to enable)
# Each route can have its own rate limits with optional key override and exemptions

# [advanced_rate_limiting.route_limits.api_heavy]
# pattern = "/api/heavy"                    # Route pattern (path prefix or regex)
# key_override = "api_key"                  # Override key resolution for this route
# exempt_keys = ["internal-service-key"]    # Keys exempt from rate limiting
# [advanced_rate_limiting.route_limits.api_heavy.limits]
# requests_per_second = 10
# burst_size = 5
# requests_per_minute = 300
# requests_per_hour = 5000

# [advanced_rate_limiting.route_limits.public_api]
# pattern = "/api/public/.*"
# [advanced_rate_limiting.route_limits.public_api.limits]
# requests_per_second = 50
# burst_size = 25
# requests_per_minute = 1500

# Composite key configuration (combine multiple keys for rate limiting)
# Useful for tenant-aware rate limiting or complex scenarios

# [[advanced_rate_limiting.composite_keys]]
# name = "tenant-user"                      # Name for logging/metrics
# keys = ["header:X-Tenant-ID", "jwt_subject"]  # Keys to combine
# routes = ["/api/.*"]                      # Routes this applies to (empty = all)
# [advanced_rate_limiting.composite_keys.limits]
# requests_per_second = 500
# burst_size = 250
# requests_per_minute = 15000
# requests_per_hour = 250000

# [[advanced_rate_limiting.composite_keys]]
# name = "ip_plus_path"
# keys = ["source_ip", "path"]
# routes = []                               # Empty = all routes
# [advanced_rate_limiting.composite_keys.limits]
# requests_per_second = 50
# burst_size = 25

# =============================
# Security Settings
# =============================
[security]
# Maximum request body size in bytes (10MB default)
max_request_size = 10485760

# Maximum header size in bytes (64KB default)
max_header_size = 65536

# Connection timeout in seconds
connection_timeout_secs = 30

# Enable DoS protection
dos_protection = true

# Blocked IP addresses
blocked_ips = []

# Allowed IP addresses (whitelist mode - empty = allow all)
allowed_ips = []

# GeoIP database path for country blocking (optional)
# geoip_db_path = "/[data]/..."

# Blocked country codes (ISO 3166-1 alpha-2)
blocked_countries = []  # e.g., ["CN", "RU", "KP", "IR"]

# Maximum connections per IP
max_connections_per_ip = [configured]

# Error-based blocking thresholds (prevents false positives from scanners)
error_4xx_threshold = [configured]          # 4xx errors before checking rate
min_requests_for_error_check = [configured] # Minimum requests before error check
error_rate_threshold = [configured]         # 70% error rate triggers suspicious pattern
error_window_secs = 60             # Sliding window duration (seconds)
auto_block_threshold = [configured]          # Suspicious patterns before auto-block
auto_block_duration_secs = [configured]     # Block duration (seconds)

# =============================
# TLS Fingerprint Detection (JA3/JA4)
# =============================
[fingerprint]
# Enable TLS fingerprint detection
enabled = true

# Block duration for malicious fingerprints (seconds)
malicious_block_duration_secs = [configured]   # 1 hour

# Block duration for suspicious fingerprints with high request rate (seconds)
suspicious_block_duration_secs = [configured]   # 5 minutes

# Request count threshold to trigger suspicious fingerprint rate check
suspicious_rate_threshold = [configured]

# Time window for suspicious rate detection (seconds)
suspicious_rate_window_secs = 60       # 1 minute

# Fingerprint cache max age before cleanup (seconds)
cache_max_age_secs = 3600              # 1 hour

# AUD-12: Automatically block connections presenting known-malicious JA3/JA4 fingerprints.
# true  (default) โ€” block IPs whose JA3/JA4 hash matches a Malicious entry in the fingerprint DB.
# false           โ€” advisory-only; Malicious fingerprints are logged but not blocked.
# Only effective when fingerprint_db_path is configured and contains Malicious entries.
block_malicious = true

# =============================
# Circuit Breaker Configuration
# =============================
[circuit_breaker]
# Enable circuit breaker for backend protection
enabled = true

# Time before circuit breaker transitions from Open to Half-Open (seconds)
half_open_delay_secs = 30

# Maximum test requests allowed in Half-Open state
half_open_max_requests = 3

# Failure threshold to open the circuit
failure_threshold = [configured]

# Success threshold to close the circuit from Half-Open
success_threshold = 2

# Stale request counter cleanup interval (seconds)
stale_counter_cleanup_secs = 300       # 5 minutes

# =============================
# HTTP Connection Pool Configuration
# =============================
[connection_pool]
# Pool idle timeout - how long idle connections stay in pool (seconds)
idle_timeout_secs = 90

# Maximum idle connections per backend host
max_idle_per_host = 10

# Maximum total connections per backend host
max_connections_per_host = 100

# Connection acquire timeout (milliseconds)
acquire_timeout_ms = 5000              # 5 seconds

# =============================
# Load Balancer Configuration
# =============================
# Configure load balancing for backend pools with multiple servers.
# Supports: least_connections (default), round_robin, weighted_round_robin,
#           random, ip_hash, least_response_time

[load_balancer]
# Enable load balancing (automatically enabled when backend_pools defined)
enabled = true

# Default algorithm for all pools (can be overridden per-pool)
# Options: least_connections, round_robin, weighted_round_robin, random, ip_hash, least_response_time
default_algorithm = "least_connections"

# Session affinity (sticky sessions) configuration
[load_balancer.session_affinity]
# Enable session affinity globally
enabled = false
# Cookie name for session tracking
cookie_name = "PQCPROXY_BACKEND"
# Cookie TTL in seconds (0 = session cookie)
cookie_ttl_secs = 3600
# Use secure cookies (HTTPS only)
cookie_secure = true
# Use HttpOnly cookies (prevent XSS access)
cookie_httponly = true
# SameSite attribute: strict, lax, none
cookie_samesite = "lax"

# Request queue for when all backends are saturated
[load_balancer.queue]
enabled = true
max_size = 1000
timeout_ms = 5000

# Slow start for recovering backends (gradual traffic increase)
[load_balancer.slow_start]
enabled = true
duration_secs = 30
initial_weight_percent = 10

# Connection draining for graceful backend removal
[load_balancer.connection_draining]
enabled = true
timeout_secs = 30

# =============================
# Backend Pools (Load Balanced)
# =============================
# Backend pools define multiple servers for load balancing.
# Routes can reference pools by name just like single backends.
# Pools take priority over single backends with the same name.

# Example: API pool with 3 servers using least_connections
[backend_pools.api-pool]
name = "api-pool"
algorithm = "least_connections"  # Override default algorithm
health_aware = true              # Skip unhealthy backends
affinity = "none"                # Options: none, cookie, ip_hash, header
# affinity_header = "X-Session-ID"  # Header name when affinity = "header"
# queue_max_size = 500             # Pool-specific queue size (overrides global)
# queue_timeout_ms = 3000          # Pool-specific queue timeout (overrides global)
health_check_path = "/health"
health_check_interval_secs = 10

# Canary / percentage traffic splitting for api-pool
# Set enabled = true and mark a server with canary = true to activate.
[backend_pools.api-pool.canary]
enabled = false              # flip to true to enable canary routing
sticky = true               # keep users on the same canary server
sticky_cookie_name = "PQCPROXY_CANARY"  # cookie written on first canary assignment
sticky_cookie_ttl_secs = 3600              # cookie lifetime in seconds (1 hour)
# sticky_header        = "X-Canary-Group"  # optional: pre-assign group via request header
auto_rollback = true              # auto-suspend on high error rate
rollback_error_rate = 0.05             # suspend when canary error rate exceeds 5 %
rollback_window_secs = 60              # sliding window for error tracking (seconds)
rollback_min_requests = 10             # require at least 10 requests before rollback triggers

[[backend_pools.api-pool.servers]]
address = "[loopback]"
weight = 100          # For weighted algorithms
priority = 1          # Lower = higher priority for failover
max_connections = 100
timeout_ms = 30000
tls_mode = "terminate"

[[backend_pools.api-pool.servers]]
address = "[loopback]"
weight = 100
priority = 1
max_connections = 100
timeout_ms = 30000
tls_mode = "terminate"

# AUD-04: Example secondary/failover node โ€” replace with your real remote server address.
# [[backend_pools.api-pool.servers]]
# address = "[private]:3003"
# weight = 50           # Half the traffic (weighted algorithms)
# priority = 2          # Failover only (used when priority 1 servers down)
# max_connections = 50
# timeout_ms = 30000
# tls_mode = "terminate"

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Canary / Percentage Traffic Splitting
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
# Enable canary routing in any backend pool by (a) adding a [backend_pools.NAME.canary]
# section and (b) setting canary = true on one or more servers with a
# canary_weight_percent value (0-100).
#
# How it works:
#   1. Incoming requests that carry the sticky canary cookie are sent to the same
#      canary server they were assigned to before (consistent experience).
#   2. New requests are probabilistically routed: if rand(0,100) < canary_weight_percent
#      the canary server is chosen; otherwise a normal stable server is used.
#   3. If auto_rollback is enabled and the canary's error rate in the rolling window
#      exceeds rollback_error_rate, the canary is suspended automatically.
#   4. Use the admin API to inspect, suspend, resume, or adjust weight at runtime:
#        GET  /canary
#        POST /canary/suspend/:server_id
#        POST /canary/resume/:server_id
#        POST /canary/weight/:server_id  (body: {"percent": 10})
#
# [backend_pools.api-pool.canary]
# enabled                = true
# sticky                 = true                # Once assigned, keep same canary
# sticky_cookie_name     = "PQCPROXY_CANARY"  # Cookie used for sticky routing
# sticky_cookie_ttl_secs = 3600               # Cookie lifetime (1 hour)
# sticky_header          = "X-Canary-Group"   # Optional: pre-assign via request header
# auto_rollback          = true               # Suspend canary on high error rate
# rollback_error_rate    = 0.05               # 5 % errors โ†’ auto-suspend
# rollback_window_secs   = 60                 # Sliding window for error tracking
# rollback_min_requests  = 10                 # Minimum requests before rollback triggers
#
# Canary server (mark with canary = true):
# [[backend_pools.api-pool.servers]]
# address                = "[loopback]"
# canary                 = true               # Mark as canary server
# canary_weight_percent  = 5                  # Route 5 % of new traffic here
# weight                 = 100
# priority               = 1
# max_connections        = 100
# timeout_ms             = 30000
# tls_mode               = "terminate"

# Example: Apache pool with IP hash for session stickiness
[backend_pools.apache-pool]
name = "apache-pool"
algorithm = "ip_hash"   # Consistent hashing by client IP
health_aware = true
affinity = "ip_hash"    # Built-in IP-based stickiness
health_check_path = "/health"
health_check_interval_secs = 10

[[backend_pools.apache-pool.servers]]
address = "[loopback]"
weight = 100
priority = 1
max_connections = 200

[[backend_pools.apache-pool.servers]]
address = "[loopback]"
weight = 100
priority = 1
max_connections = 200

# Example: Session pool with cookie-based sticky sessions
[backend_pools.session-pool]
name = "session-pool"
algorithm = "round_robin"
health_aware = true
affinity = "cookie"     # Cookie-based sticky sessions
health_check_path = "/health"
health_check_interval_secs = 10

# AUD-04/AUD-13: Replace with your actual backend addresses.
[[backend_pools.session-pool.servers]]
address = "[loopback]"
weight = 100
priority = 1
max_connections = 100

[[backend_pools.session-pool.servers]]
address = "[loopback]"
weight = 100
priority = 1
max_connections = 100

# Example: Pool with header-based affinity and TLS to backends
[backend_pools.secure-pool]
name = "secure-pool"
algorithm = "round_robin"
health_aware = true
affinity = "header"                    # Header-based sticky sessions
affinity_header = "X-Session-ID"       # Required when affinity = "header"
queue_max_size = 200                   # Pool-specific queue max size
queue_timeout_ms = 2000                # Pool-specific queue timeout
health_check_path = "/health"
health_check_interval_secs = 15

# Pool server with TLS re-encryption to backend
[[backend_pools.secure-pool.servers]]
address = "[private]:443"
weight = 100
priority = 1
max_connections = 50
timeout_ms = 30000
tls_mode = "reencrypt"                 # TLS to backend
tls_cert = "/[system]/[key-material]"  # CA cert for verification
tls_skip_verify = false                # DANGEROUS if true - only for testing
tls_sni = "backend1.internal.com"      # Custom SNI hostname

[[backend_pools.secure-pool.servers]]
address = "[private]:443"
weight = 100
priority = 1
max_connections = 50
timeout_ms = 30000
tls_mode = "reencrypt"
tls_cert = "/[system]/[key-material]"
tls_skip_verify = false
tls_sni = "backend2.internal.com"

# =============================
# Backend Definitions (Single)
# =============================
# Backends support three TLS modes:
#   - terminate (default): TLS terminates at proxy, plain HTTP to backend
#   - reencrypt: TLS terminates at proxy, new HTTPS connection to backend
#   - passthrough: No TLS termination, SNI-based routing (see [[passthrough_routes]])

# Apache/PHP backend (TLS Terminate - default)
[backends.apache]
name = "apache"
type = "http1"
address = "[loopback]"
tls_mode = "terminate"  # Default - can be omitted
timeout_ms = 30000
max_connections = 100
health_check = "/health"
health_check_interval_secs = 30

# Rust API backend (TLS Terminate)
[backends.api]
name = "api"
type = "http1"
address = "[loopback]"
tls_mode = "terminate"
timeout_ms = 30000
max_connections = 100
health_check = "/health"
health_check_interval_secs = 30

# Internal HTTPS API (TLS Re-encrypt with mTLS)
[backends.internal-api]
name = "internal-api"
type = "http1"
address = "internal.example.com:443"
tls_mode = "reencrypt"
# Custom CA for backend certificate verification
tls_cert = "/[system]/[key-material]"
# mTLS client certificate (optional)
tls_client_cert = "/[system]/[key-material]"
tls_client_key = "/[system]/[key-material]"
# DANGEROUS: Only set true for testing
tls_skip_verify = false
# Custom SNI hostname (optional)
tls_sni = "internal.example.com"
timeout_ms = 30000
max_connections = 50
health_check = "/health"
health_check_interval_secs = 30

# PHP-FPM backend via Unix socket
[backends.php]
name = "php"
type = "unix"
address = "unix:/run/php-fpm.sock"
timeout_ms = 30000
max_connections = 100
health_check = "/health"
health_check_interval_secs = 30

# HTTP/2 backend with TLS
[backends.http2-backend]
name = "http2-backend"
type = "http2"
address = "api.internal.example.com:443"
tls_mode = "reencrypt"
tls_skip_verify = false
timeout_ms = 30000
max_connections = 50
health_check = "/health"
health_check_interval_secs = 30

# HTTP/3 backend (QUIC to QUIC)
[backends.quic-backend]
name = "quic-backend"
type = "http3"
address = "backend.example.com:4433"
tls_mode = "reencrypt"
timeout_ms = 30000
max_connections = 50

# Raw TCP backend
[backends.tcp-service]
name = "tcp-service"
type = "tcp"
address = "[loopback]"
timeout_ms = 10000
max_connections = 100

# Grafana monitoring dashboard
[backends.grafana]
name = "grafana"
type = "http1"
address = "[loopback]"
tls_mode = "terminate"
timeout_ms = 30000
max_connections = 50
health_check = "/api/health"
health_check_interval_secs = 30

# Prometheus metrics server
[backends.prometheus]
name = "prometheus"
type = "http1"
address = "[loopback]"
tls_mode = "terminate"
timeout_ms = 30000
max_connections = 50
health_check = "/-/healthy"
health_check_interval_secs = 30

# =============================
# TLS Passthrough Routes (SNI Routing)
# =============================
# These routes bypass TLS termination entirely.
# Traffic is routed based on SNI (Server Name Indication) without decryption.
# Use for services that must handle their own TLS or require end-to-end encryption.

# AUD-04/AUD-13: Passthrough routes contain actual backend addresses โ€” never commit real
# infrastructure IPs here.  The examples below use documentation-only addresses
# (RFC 5737 TEST-NET-1 192.0.2.0/24) to avoid disclosing real topology.

# Example: External service with SNI routing
[[passthrough_routes]]
name = "external-mail"
sni = "mail.example.com"
backend = "192.0.2.10:443"
proxy_protocol = false  # Enable for client IP preservation
timeout_ms = 30000

# Example: Wildcard SNI routing (matches *.internal.example.com)
[[passthrough_routes]]
name = "internal-wildcard"
sni = "*.internal.example.com"
backend = "192.0.2.20:443"
proxy_protocol = true
timeout_ms = 30000

# Example: Legacy service requiring passthrough
[[passthrough_routes]]
name = "legacy-service"
sni = "legacy.example.com"
backend = "192.0.2.100:443"
timeout_ms = 60000

# =============================
# Route Configuration
# =============================
# Routes are matched by priority (lower = higher priority).
# Routes support: domain matching, path matching, CORS, redirects, headers override.

# API subdomain route with CORS
[[routes]]
name = "api-route"
host = "api.example.com"
path_prefix = "/"
backend = "api"
forward_client_identity = true
client_identity_header = "X-Client-IP"
priority = 100

[routes.cors]
allow_origin = "https://example.com"
allow_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allow_headers = ["Content-Type", "Authorization", "X-API-Key", "X-Request-ID"]
allow_credentials = true
max_age = 86400

[routes.add_headers]
X-Forwarded-Proto = "https"
X-API-Version = "v1"

# Traffic shadowing example โ€” uncomment to mirror 10% of API traffic to a canary:
# [routes.shadow]
# backend             = "api-canary"      # Must be a key in [backends.*]
# percent             = 10                # 0โ€“100 % of requests to mirror
# timeout_ms          = 5000              # Shadow task abandoned after this many ms
# shadow_header       = "X-Shadow-Request"
# shadow_header_value = "1"
# log_responses       = true

# Main site route (Apache backend)
[[routes]]
name = "main-site"
host = "example.com"
path_prefix = "/"
backend = "apache"
forward_client_identity = true
priority = 100

# www redirect to non-www
[[routes]]
name = "www-redirect"
host = "www.example.com"
path_prefix = "/"
redirect = "https://example.com"
redirect_permanent = true
priority = 1

# Internal API route (TLS re-encrypt)
[[routes]]
name = "internal-api-route"
host = "example.com"
path_prefix = "/internal-api"
backend = "internal-api"
forward_client_identity = true
priority = 50

# SEO redirect: underscore to hyphen
[[routes]]
name = "seo-old-path"
host = "example.com"
path_prefix = "/old_path"
redirect = "/new-path"
redirect_permanent = true
priority = 1

# SEO redirect: legacy URL
[[routes]]
name = "seo-legacy"
host = "example.com"
path_prefix = "/legacy_page"
redirect = "/modern-page"
redirect_permanent = true
priority = 1

# WebTransport route for real-time encryption
[[routes]]
name = "webtransport-encrypt"
host = "api.example.com"
path_prefix = "/encrypt"
webtransport = true
backend = "api"
stream_to_method = "POST"
forward_client_identity = true
priority = 10

[routes.add_headers]
X-WebTransport = "true"

# WebTransport route for streaming
[[routes]]
name = "webtransport-stream"
host = "api.example.com"
path_prefix = "/stream"
webtransport = true
backend = "api"
stream_to_method = "POST"
forward_client_identity = true
priority = 10

# Route with custom headers override
[[routes]]
name = "custom-headers"
host = "example.com"
path_prefix = "/embed"
backend = "apache"
priority = 50

# Override global security headers for this route
[routes.headers_override]
x_frame_options = "SAMEORIGIN"  # Allow embedding from same origin
cross_origin_embedder_policy = "unsafe-none"  # Disable for legacy content

# PHP-FPM route
[[routes]]
name = "php-route"
host = "example.com"
path_prefix = "/app"
backend = "php"
forward_client_identity = true
priority = 80

# Regex path matching (requires path_regex instead of path_prefix)
[[routes]]
name = "api-versioned"
host = "api.example.com"
path_regex = "^/v[0-9]+/.*"
backend = "api"
forward_client_identity = true
priority = 20

# Exact path match (stricter than path_prefix)
[[routes]]
name = "exact-health"
host = "api.example.com"
path_exact = "/health"             # Only matches /health exactly, not /health/db
backend = "api"
priority = 5

# Route with headers removal
[[routes]]
name = "sanitized-api"
host = "api.example.com"
path_prefix = "/public"
backend = "api"
forward_client_identity = true
priority = 60
remove_headers = ["X-Internal-Token", "X-Debug-Info"]  # Headers to strip before sending to backend

[routes.add_headers]
X-Public-Request = "true"

# Route allowing HTTP/1.1 (for search bots like Googlebot that don't support HTTP/3)
[[routes]]
name = "seo-friendly"
host = "example.com"
path_prefix = "/sitemap"
backend = "apache"
allow_http11 = true                # Allow HTTP/1.1 for this route (search bots)
skip_bot_blocking = true           # Don't block bots on this route
priority = 30

# Route with Stripe.js compatibility (removes COEP/COOP headers that break Stripe)
[[routes]]
name = "checkout-page"
host = "example.com"
path_prefix = "/checkout"
backend = "apache"
stripe_compatibility = true        # Removes Cross-Origin-Embedder-Policy and Cross-Origin-Opener-Policy
priority = 40

# Route with custom timeout override
[[routes]]
name = "long-running-api"
host = "api.example.com"
path_prefix = "/export"
backend = "api"
timeout_override_ms = 120000       # 2 minute timeout for long exports
forward_client_identity = true
priority = 45

# Grafana monitoring dashboard route
[[routes]]
name = "grafana"
host = "pqcrypta.com"
path_prefix = "/grafana"
backend = "grafana"
forward_client_identity = true
client_identity_header = "X-Real-IP"
stripe_compatibility = true        # Removes COEP/COOP headers that can break Grafana login
priority = 20

[routes.add_headers]
X-Forwarded-Proto = "https"
X-Forwarded-Host = "pqcrypta.com"

[routes.headers_override]
cross_origin_embedder_policy = "unsafe-none"
cross_origin_opener_policy = "unsafe-none"

# Prometheus metrics route
[[routes]]
name = "prometheus"
host = "pqcrypta.com"
path_prefix = "/prometheus"
backend = "prometheus"
forward_client_identity = true
client_identity_header = "X-Real-IP"
priority = 20

[routes.add_headers]
X-Forwarded-Proto = "https"
X-Forwarded-Host = "pqcrypta.com"

# Wildcard catch-all route
[[routes]]
name = "default"
path_prefix = "/"
backend = "apache"
priority = 1000

# =============================
# Database Blocklist Sync
# =============================
# Synchronize blocklists from PostgreSQL database.
# The API server's WAF/honeypot system stores detected threats in the database.
# This enables the proxy to automatically block known malicious IPs/fingerprints.

[database]
# Enable database sync for blocklists
enabled = true

# PostgreSQL connection settings
# Credentials are read from environment variables for security:
#   PQCRYPTA_DB_HOST, PQCRYPTA_DB_PORT, PQCRYPTA_DB_USER,
#   PQCRYPTA_DB_PASSWORD, PQCRYPTA_DB_NAME
host = "localhost"
port = 5432
database = "pqcrypta"
user = "pqcrypta_user"
# Password should be set via PQCRYPTA_DB_PASSWORD environment variable
# password = ""  # DO NOT hardcode - use env var

# Connection pool settings
min_connections = 2
max_connections = 10
connection_timeout_secs = 10

# Sync interval in seconds (how often to refresh blocklist from database)
sync_interval_secs = 60

# Maximum blocklist size (memory protection)
max_blocklist_size = 50000

# Blocklist queries - customize based on your schema
[database.blocklist_queries]
# Query for blocked IPs (should return: ip_address, reason, expires_at)
blocked_ips = """
SELECT ip_address, reason, expires_at
FROM bot_blocklist
WHERE is_active = true
  AND (expires_at IS NULL OR expires_at > NOW())
"""

# Query for blocked fingerprints (should return: fingerprint, type, reason)
blocked_fingerprints = """
SELECT fingerprint, fingerprint_type, reason
FROM fingerprint_blocklist
WHERE is_active = true
  AND (expires_at IS NULL OR expires_at > NOW())
"""

# Query for blocked countries (should return: country_code, reason)
blocked_countries = """
SELECT country_code, reason
FROM country_blocklist
WHERE is_active = true
"""

# Query to log proxy-level detections back to database
# This bridges the gap between proxy detection and API WAF detection
[database.logging]
enabled = true

# Log blocked requests to database for analytics
log_blocked_requests = true

# Log suspicious patterns detected at proxy level
log_suspicious_patterns = true

# Table for proxy-level detections
detection_table = "proxy_detections"

# Insert query template (use $1, $2, etc. for parameters)
insert_detection = """
INSERT INTO proxy_detections
  (ip_address, fingerprint, path, method, user_agent, detection_type, blocked, timestamp)
VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
"""

# =============================
# Configuration Notes
# =============================

# TLS Modes Explained:
# --------------------
# 1. TERMINATE (default): TLS terminates at proxy
#    - Client โ†(HTTPS)โ†’ Proxy โ†(HTTP)โ†’ Backend
#    - Most common mode for internal backends
#    - Proxy can inspect/modify traffic
#
# 2. REENCRYPT: TLS terminates and re-establishes
#    - Client โ†(HTTPS)โ†’ Proxy โ†(HTTPS)โ†’ Backend
#    - Use for backends requiring end-to-end encryption
#    - Supports mTLS for mutual authentication
#    - Proxy can still inspect traffic
#
# 3. PASSTHROUGH: No TLS termination (SNI routing)
#    - Client โ†(HTTPS)โ†’ Proxy โ†(HTTPS)โ†’ Backend (same TLS session)
#    - Use for services handling their own TLS
#    - Proxy cannot inspect traffic
#    - Configured via [[passthrough_routes]], not backends

# Security Headers:
# -----------------
# The proxy automatically injects security headers from [headers] section.
# The Server header is always replaced with "PQCProxy v0.1.0" to hide
# backend identity (Apache, nginx, etc.).

# CORS Handling:
# --------------
# When [routes.cors] is configured:
# - OPTIONS preflight requests are handled automatically
# - CORS headers are added to all responses
# - Credentials and custom headers supported

# HTTP Redirect:
# --------------
# When [http_redirect] is enabled:
# - Port 80 redirects all requests to HTTPS
# - Uses 301 (permanent) redirect
# - Preserves path and query string

# Alt-Svc Advertisement:
# ----------------------
# All responses include Alt-Svc header advertising HTTP/3:
#   Alt-Svc: h3=":443"; ma=86400, h3=":4433"; ma=86400, h3=":4434"; ma=86400

# Hot Reload:
# -----------
# Configuration can be reloaded without restart:
#   curl -X POST http://127.0.0.1:8081/reload
# TLS certificates can be reloaded separately:
#   curl -X POST http://127.0.0.1:8081/reload -d '{"tls_only":true}'

# Route Options Reference:
# ------------------------
# Path Matching (use one):
#   - path_prefix: Matches if path starts with value (e.g., "/api" matches "/api/v1")
#   - path_exact: Matches only the exact path (e.g., "/health" won't match "/health/db")
#   - path_regex: Regex pattern for complex matching (e.g., "^/v[0-9]+/.*")
#
# Headers:
#   - add_headers: Headers to add to backend request
#   - remove_headers: Headers to strip before sending to backend
#   - headers_override: Override global security headers for this route
#
# Special Modes:
#   - allow_http11: Allow HTTP/1.1 for search bots (Googlebot doesn't support HTTP/3)
#   - skip_bot_blocking: Don't apply bot protection to this route
#   - stripe_compatibility: Removes COEP/COOP headers that break Stripe.js
#   - timeout_override_ms: Custom timeout for slow endpoints
#
# Backend Pool Options:
# ---------------------
#   - affinity: Session stickiness mode (none, cookie, ip_hash, header)
#   - affinity_header: Header name when affinity = "header"
#   - queue_max_size: Pool-specific queue size (overrides [load_balancer.queue])
#   - queue_timeout_ms: Pool-specific queue timeout
#
# Pool Server TLS Options:
# ------------------------
#   - tls_mode: terminate, reencrypt, or passthrough
#   - tls_cert: CA certificate for backend verification
#   - tls_skip_verify: Skip verification (DANGEROUS - testing only)
#   - tls_sni: Custom SNI hostname for TLS handshake