Files
proxy/ops/nginx_conf/nginx.conf
T
wmantly 6092468901 Add per-host reverse-proxy controls (rate limit, cache, headers, IP ACL)
Every proxied request flows through one shared OpenResty location whose
behavior is chosen at request time from the host's Redis hash. Add per-host
controls as new Host fields enforced in Lua rather than static nginx config
(which can't key off a per-request variable):

- Rate limiting: per-client-IP token bucket via resty.limit.req
  (ratelimit_enabled/rate/burst), backed by a new `ratelimit` shared dict.
- Response caching: opt-in per host via a global proxy_cache zone gated by
  $skip_cache (respcache_enabled). Off by default; upstream Cache-Control
  still honored.
- Custom/security headers: req_headers (upstream) + resp_headers (client) and
  hsts_enabled, applied in access/header_filter phases.
- IP allow/deny CIDR lists via resty.ipmatcher (deny wins; non-empty allow is
  default-deny).

New ops/nginx_conf/hostfeatures.lua holds the enforcement; proxy.conf's
access_by_lua string becomes a block that calls it, plus a header_filter block.
nodejs/utils/host_features.js is the pure, unit-tested normalize/validate layer
(header/CIDR parsing, range clamping, injection-safe values) applied in
routes/host.js and mirrored by the hosts.ejs edit form. install.sh gains the
ipmatcher rock, the cache dir, and the hostfeatures.lua symlink.

Per-host cache TTL is intentionally deferred (global default only) — see the
plan's limitations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 22:10:55 -04:00

100 lines
2.2 KiB
Nginx Configuration File

#user nobody;
worker_processes 8;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
client_max_body_size 4g;
lua_shared_dict auto_ssl 100m;
lua_shared_dict auto_ssl_settings 64k;
# Per-host rate limiting (resty.limit.req) counter storage.
lua_shared_dict ratelimit 10m;
# Per-host response cache. Enabled per request via $skip_cache in proxy.conf;
# 10m is the default TTL when the upstream doesn't send its own Cache-Control.
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=proxycache:100m
max_size=2g inactive=60m use_temp_path=off;
proxy_cache_valid 200 301 302 10m;
resolver 8.8.4.4 8.8.8.8;
init_by_lua_block {
auto_ssl = (require "resty.auto-ssl").new()
auto_ssl:set("storage_adapter", "resty.auto-ssl.storage_adapters.redis")
local targetInfo = require "targetinfo"
auto_ssl:set("allow_domain", function(domain)
return ngx.ctx.toAllow
end)
auto_ssl:set("request_domain", function(ssl, ssl_options)
local domain, err = ssl.server_name()
local res = targetInfo.get(ngx, domain, ngx.ctx.targetInfo)
if res['wildcard_parent'] then
return res['wildcard_parent'], err
end
return domain, err
end)
auto_ssl:init()
}
init_worker_by_lua_block {
auto_ssl:init_worker()
}
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server {
listen 127.0.0.1:8999;
# Increase the body buffer size, to ensure the internal POSTs can always
# parse the full POST contents into memory.
client_body_buffer_size 128k;
client_max_body_size 128k;
location / {
content_by_lua_block {
auto_ssl:hook_server()
}
}
}
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
include sites-enabled/*;
}