mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
The shared proxy's nginx.conf derived worker_connections from the
openresty container's pids_limit. pids_limit caps processes and threads,
worker_connections caps simultaneous sockets per worker (client and
upstream), so with pids_limit 256 and one worker the whole host's proxy
held about 256 sockets, roughly 128 proxied requests in flight across
every vhost. Raising pids_limit to buy connections would loosen the
fork-bomb guard.
svc-prx-openresty now declares services.openresty.worker_connections
(4096 per worker, the common nginx production range, enough for several
chunk-heavy apps such as OpenWebUI at ~150-170 requests per page load).
WEBSERVER_PROXY_WORKER_CONNECTIONS reads it through lookup('config'),
without a default, so a missing key fails loudly. pids_limit stays 256.
WEBSERVER_PROXY_WORKER_RLIMIT_NOFILE is derived as 2x worker_connections
(8192), one descriptor for each client and upstream socket of a proxied
request, and nginx.conf renders it as worker_rlimit_nofile. The openresty
container pins its nofile ulimit (soft and hard) to the same value:
workers call setrlimit as root without CAP_SYS_RESOURCE, so they can only
lower the hard limit, and the inherited hard limit depends on the host
daemon (Docker >= 25 defaults to 1024:524288, DiD nests whatever the
outer container has). An explicit ulimit makes the rlimit succeed on
every host instead of logging a setrlimit alert.
The unit test pins worker_connections 4096, worker_rlimit_nofile 8192 and
the container ulimit, and fails when worker_connections follows
pids_limit again.
Live proof (compose deploy of web-svc-html, both plays failed=0): the
deployed nginx.conf renders worker_rlimit_nofile 8192 and
worker_connections 4096; openresty's master, worker and cache manager
run with "Max open files 8192 8192"; the openresty log carries no
setrlimit or "worker_connections are not enough" line.
Closes #1300
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
50 lines
2.1 KiB
YAML
50 lines
2.1 KiB
YAML
---
|
|
# Webserver Configuration
|
|
|
|
# Effective CPUs (float) across proxy and the current app
|
|
WEBSERVER_CPUS_EFFECTIVE: >-
|
|
{{
|
|
[
|
|
(lookup('applications') | resource_filter('svc-prx-openresty', 'cpus', service_name | default(''), RESOURCE_CPUS)) | float,
|
|
(lookup('applications') | resource_filter(application_id, 'cpus', service_name | default(''), RESOURCE_CPUS)) | float
|
|
] | min
|
|
}}
|
|
|
|
WEBSERVER_WORKER_PROCESSES: >-
|
|
{{
|
|
1 if (WEBSERVER_CPUS_EFFECTIVE | float) < 1
|
|
else (WEBSERVER_CPUS_EFFECTIVE | float | int)
|
|
}}
|
|
|
|
# worker_connections from pids_limit (use the smaller one), with correct key/defaults
|
|
WEBSERVER_WORKER_CONNECTIONS: >-
|
|
{{
|
|
[
|
|
(lookup('applications') | resource_filter('svc-prx-openresty', 'pids_limit', service_name | default(''), RESOURCE_PIDS_LIMIT)) | int,
|
|
(lookup('applications') | resource_filter(application_id, 'pids_limit', service_name | default(''), RESOURCE_PIDS_LIMIT)) | int
|
|
] | min
|
|
}}
|
|
|
|
# Not WEBSERVER_WORKER_*: their application_id is whichever role loaded the shared proxy first, whose limits then cap every vhost.
|
|
WEBSERVER_PROXY_WORKER_PROCESSES: >-
|
|
{{
|
|
[
|
|
(lookup('applications') | resource_filter('svc-prx-openresty', 'cpus', '', RESOURCE_CPUS)) | float | int,
|
|
1
|
|
] | max
|
|
}}
|
|
|
|
WEBSERVER_PROXY_WORKER_CONNECTIONS: "{{ lookup('config', 'svc-prx-openresty', 'services.openresty.worker_connections') | int }}"
|
|
|
|
WEBSERVER_PROXY_WORKER_RLIMIT_NOFILE: "{{ (WEBSERVER_PROXY_WORKER_CONNECTIONS | int) * 2 }}"
|
|
|
|
# Response security headers of every vhost; an app overrides any key under `security_headers` in its meta/server.yml.
|
|
WEBSERVER_SECURITY_HEADERS:
|
|
nosniff: false # X-Content-Type-Options: nosniff
|
|
referrer_policy: "" # Referrer-Policy, sent only when the upstream sends none; "" sends none
|
|
permissions_policy: "" # Permissions-Policy on HTML documents; "" sends none
|
|
hsts:
|
|
max_age: 31536000 # Strict-Transport-Security max-age in seconds
|
|
include_subdomains: false # adds includeSubDomains, which covers every subdomain of the vhost
|
|
preload: false # adds preload; requires include_subdomains and a max_age of one year
|