Subdomain Resolution¶
The subdomain strategy extracts the tenant identifier from the leftmost subdomain of the incoming Host (or X-Forwarded-Host) header.
Configuration¶
config = TenancyConfig(
database_url="...",
resolution_strategy="subdomain",
domain_suffix=".example.com", # required — must include the leading dot
)
domain_suffix is required
The subdomain strategy will raise ValidationError at construction time
if domain_suffix is not set.
How a request is resolved¶
- The
Hostheader value"acme-corp.example.com"is extracted - The port suffix is stripped (e.g.
"acme-corp.example.com:8000"→"acme-corp.example.com") - The configured
domain_suffix(.example.com) is stripped, leaving"acme-corp" - The identifier is validated against tenant slug rules
store.get_by_identifier("acme-corp")looks up the tenant
Reverse proxies and X-Forwarded-Host¶
When your app sits behind a reverse proxy (nginx, Traefik, AWS ALB), the original Host header may be replaced by the proxy. The resolver reads X-Forwarded-Host first when trust_x_forwarded=True (the default):
# Default — reads X-Forwarded-Host first
resolver = SubdomainTenantResolver(store, domain_suffix=".example.com", trust_x_forwarded=True)
# Disable if you DON'T have a trusted reverse proxy
resolver = SubdomainTenantResolver(store, domain_suffix=".example.com", trust_x_forwarded=False)
Disable trust_x_forwarded without a trusted proxy
If your application is directly internet-accessible (no reverse proxy),
any client can spoof X-Forwarded-Host. Set trust_x_forwarded=False
in that case.
DNS setup¶
Each tenant needs a DNS record pointing to your application:
# DNS zone file for example.com
acme-corp CNAME app.example.com.
globex CNAME app.example.com.
* CNAME app.example.com. # wildcard — catches new tenants automatically
For local development, add entries to /etc/hosts:
TLS certificates¶
Use a wildcard certificate for *.example.com so new tenants automatically get HTTPS:
# Let's Encrypt wildcard with Certbot + DNS challenge
certbot certonly \
--manual \
--preferred-challenges dns \
-d "*.example.com"
Or use a CDN/load balancer (Cloudflare, AWS CloudFront) that handles wildcard TLS automatically.