Building a multi-tenant Software-as-a-Service (SaaS) platform—such as an e-commerce storefront builder, agency website network, or enterprise portal in Pakistan—requires allowing clients to connect their own custom domains (e.g., store.clientbrand.pk).
In traditional Nginx setups, provisioning an SSL certificate for a new custom domain requires generating a new server { ... } block in a .conf file and issuing an nginx -s reload command. While manageable for a dozen sites, this architecture completely falls apart at scale:
- Reload Thrashing: When hundreds of custom domains are onboarded daily, continuous Nginx reloads cause CPU spikes, worker process churn, and intermittent HTTP/2 stream resets for active shoppers.
- Configuration Bloat: An
nginx.confcontaining 5,000 separateserverblocks consumes gigabytes of memory and takes over 30 seconds just to validate syntax.
The enterprise solution is Dynamic TLS Termination with OpenResty. Utilizing OpenResty’s non-blocking Lua engine and the ssl_certificate_by_lua_block directive, Nginx intercepts the TLS handshake, dynamically fetches the domain’s certificate and private key from an in-memory Redis or HashiCorp Vault cluster, and terminates encryption on the fly—with zero Nginx reloads and zero downtime.
Deploying OpenResty dynamic SSL on high-performance Dedicated Servers empowers Pakistani engineering teams to onboard tens of thousands of custom domains seamlessly.
1. Dynamic TLS Architecture: How It Operates
Instead of reading certificates from local static .pem files on disk, OpenResty intercepts the TLS ClientHello during the initial handshake:
Client (Browser)
|
| 1. Initiates TLS Handshake with SNI: "shop.brand.pk"
v
[ OpenResty Edge Gateway ]
|
| 2. ssl_certificate_by_lua_block fires
| 3. Extract SNI domain: "shop.brand.pk"
|
+---> Check Local L1 Cache (lua_shared_dict: ~0.05ms)
| |
| +---> [ Cache Hit ] -> Parse DER Certificate & Key -> Complete Handshake!
| |
| +---> [ Cache Miss ]
| |
| v
| Query Centralized Redis / HashiCorp Vault (Private 10GbE Network)
| |
| +---> Fetch Encrypted PEM Key & Fullchain
| +---> Populate Local L1 Cache (TTL: 1 Hour)
| +---> Inject into Active TLS Session via ngx.ssl
v
[ Secure TLS 1.3 Pipe Established ]
(Zero Nginx reloads, zero disk I/O, sub-millisecond handshake)
2. Installing OpenResty on Enterprise Linux
OpenResty bundles standard Nginx with the LuaJIT runtime and the core lua-nginx-module. On AlmaLinux 9 or Rocky Linux 9:
# Add official OpenResty yum repository
dnf install -y yum-utils
yum-config-manager --add-repo https://openresty.org/package/rhel/openresty.repo
# Install OpenResty and Lua resty modules
dnf install -y openresty openresty-resty openresty-opm
systemctl enable --now openresty
Install the official Redis driver:
opm get openresty/lua-resty-redis
3. Storing Certificates in Redis
In your SaaS backend automation pipeline (e.g., after issuing a Let’s Encrypt certificate via Certbot or ACME client), store the DER-formatted certificate and private key inside Redis:
# Key format: ssl:<domain_name>
# Storing JSON payload containing base64-encoded cert and key
redis-cli -h 127.0.0.1 -p 6379 SET "ssl:shop.brand.pk" \
'{"cert": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----", "key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"}'
4. Configuring OpenResty for Dynamic Certificate Resolution
Create the master dynamic TLS configuration:
# /usr/local/openresty/nginx/conf/conf.d/dynamic_ssl.conf
# 1. Allocate in-memory shared dictionary for L1 cache (128MB holds ~20,000 domains)
lua_shared_dict ssl_cache 128m;
# 2. DNS resolver for upstream Redis lookup
resolver 127.0.0.1 1.1.1.1 valid=300s;
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
# Fallback dummy certificate (required by Nginx syntax validation)
ssl_certificate /etc/pki/tls/certs/fallback.crt;
ssl_certificate_key /etc/pki/tls/private/fallback.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 3. Dynamic SSL Handshake Hook
ssl_certificate_by_lua_block {
local ssl = require("ngx.ssl")
local redis = require("resty.redis")
local cjson = require("cjson.safe")
-- Clear default fallback certificate
ssl.clear_certs()
-- Extract requested SNI hostname
local server_name, err = ssl.server_name()
if not server_name then
ngx.log(ngx.ERR, "Unable to extract SNI server name: ", err)
return ngx.exit(ngx.ERROR)
end
local cache = ngx.shared.ssl_cache
local cache_key = "ssl:" .. server_name
-- Check L1 In-Memory Shared Cache
local cached_payload = cache:get(cache_key)
local cert_pem, key_pem
if cached_payload then
local data = cjson.decode(cached_payload)
cert_pem = data.cert
key_pem = data.key
else
-- Cache Miss: Query Centralized Redis
local red = redis:new()
red:set_timeout(500) -- 500ms timeout
local ok, conn_err = red:connect("10.0.0.50", 6379)
if not ok then
ngx.log(ngx.ERR, "Failed to connect to Redis: ", conn_err)
return ngx.exit(ngx.ERROR)
end
-- Optional Redis authentication
-- red:auth("StrongProductionPassword")
local res, redis_err = red:get(cache_key)
red:set_keepalive(10000, 100) -- Return connection to pool
if not res or res == ngx.null then
ngx.log(ngx.WARN, "No SSL certificate found in Redis for: ", server_name)
return ngx.exit(ngx.ERROR)
end
local data = cjson.decode(res)
cert_pem = data.cert
key_pem = data.key
-- Store in L1 cache for 3600 seconds (1 Hour)
cache:set(cache_key, res, 3600)
end
-- Parse and inject certificate chain
local der_cert, der_err = ssl.cert_pem_to_der(cert_pem)
if not der_cert then
ngx.log(ngx.ERR, "Failed to parse PEM certificate: ", der_err)
return ngx.exit(ngx.ERROR)
end
ssl.set_der_cert(der_cert)
-- Parse and inject private key
local der_key, key_err = ssl.priv_key_pem_to_der(key_pem)
if not der_key then
ngx.log(ngx.ERR, "Failed to parse PEM private key: ", key_err)
return ngx.exit(ngx.ERROR)
end
ssl.set_der_priv_key(der_key)
}
location / {
proxy_pass http://saas_backend_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
5. Automated Let’s Encrypt ACME HTTP-01 Challenges
When a client points a new custom domain to your cluster, how do you issue certificates automatically without manual intervention?
OpenResty can intercept ACME HTTP-01 challenge requests (/.well-known/acme-challenge/*) and query Redis for the validation token:
server {
listen 80;
server_name _;
location /.well-known/acme-challenge/ {
content_by_lua_block {
local redis = require("resty.redis")
local token = ngx.var.uri:match("/.well-known/acme-challenge/(.+)")
local red = redis:new()
red:connect("10.0.0.50", 6379)
local key_auth = red:get("acme:" .. token)
red:set_keepalive(10000, 100)
if key_auth and key_auth ~= ngx.null then
ngx.say(key_auth)
else
ngx.exit(404)
end
}
}
location / {
return 301 https://$host$request_uri;
}
}
Now, your central control plane issues an ACME certificate request, drops the token into Redis, and Let’s Encrypt completes verification within seconds—without touching a single web server configuration file!
6. Architecture Comparison: Static vs. Dynamic OpenResty SSL
| Architecture Metric | Traditional Static Nginx | Dynamic OpenResty + Redis |
|---|---|---|
| New Domain Onboarding | Edit file + nginx -s reload |
Instant Redis write (Zero Reloads) |
| Reload Penalty | Resets HTTP/2 connections, CPU spikes | 0% impact on active traffic |
| Memory Consumption | Scales linearly with domain count | Fixed L1 shared memory cache pool |
| Maximum Domain Capacity | Bottlenecks at ~500 domains | 100,000+ domains per node |
| Cert Expiration Rotation | Update local files + reload | Update Redis key (Instantly propagates) |
Deploying OpenResty on high-capacity Dedicated Servers in Pakistan equips software platforms with hyper-scale multi-tenant TLS provisioning, unmatched uptime, and enterprise architectural agility.
Enterprise Dedicated Infrastructure for Multi-Tenant SaaS
Scale your cloud applications with bare-metal dedicated servers connected to low-latency national networks. Enjoy dedicated gigabit ports, zero virtualization lag, and complete root control with NextGen.
Deploy Dedicated Server in Pakistan