openvibers/openvibe.chat Commits

nginx: every Chat location that sets its own proxy_set_header (Connection "" for upstream keepalive) repeats Host and the client address: /auth/me, /auth/, /api/ and / had lost the server-level ones, so REST requests reached Chat as 127.0.0.1 (per-IP limits and bans saw one address); the test fails a location without them

OP OpenVibers committed 26 Sept 2026 · b2d329a380 · 2 files, +33 −0


Changes

ddiff --git a/deploy/nginx/openvibe.chat.conf b/deploy/nginx/openvibe.chat.conf
iindex 65b9a0b..d3edb79 100644
---- a/deploy/nginx/openvibe.chat.conf
++++ b/deploy/nginx/openvibe.chat.conf
@@@ -113,10 +113,17 @@ server {
# The session probe: the shared navbar asks it on every page view, so it cannot share the sign-in
# budget below (10 a minute): a visitor reading quickly was answered 503 and looked signed out
# (found by the browser check, OpenVibe.Host scripts/browser-check.js).
++ # These locations set Connection "" (keepalive to the upstream), and any proxy_set_header in a
++ # location replaces every server-level one, so the client address and Host are repeated in each.
location = /auth/me {
limit_req zone=ovchat_api burst=30 nodelay;
limit_req_status 429;
proxy_set_header Connection "";
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
}
@@@ -124,6 +131,11 @@ server {
limit_req zone=ovchat_auth burst=10 nodelay;
limit_req_status 429;
proxy_set_header Connection "";
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
}
@@@ -131,12 +143,22 @@ server {
limit_req zone=ovchat_api burst=40 nodelay;
client_max_body_size 10m;
proxy_set_header Connection "";
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
}
location / {
limit_req zone=ovchat_write burst=20 nodelay;
proxy_set_header Connection "";
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
}
}
ddiff --git a/test/nginx-auth-limit.test.js b/test/nginx-auth-limit.test.js
iindex 9b9461c..0eb39d7 100644
---- a/test/nginx-auth-limit.test.js
++++ b/test/nginx-auth-limit.test.js
@@@ -17,4 +17,15 @@ assert.match(auth, /limit_req zone=ovchat_auth burst=10 nodelay;/);
for (const b of [probe, auth]) assert.match(b, /limit_req_status 429;/);
const upstream = (b) => (b.match(/proxy_pass (\S+);/) || [])[1];
assert.ok(upstream(probe) && upstream(probe) === upstream(auth), 'the same upstream');
++// Any location that sets its own proxy_set_header loses the server-level ones, so each must carry the
++// client address and Host itself (a location without them sent every REST request as 127.0.0.1).
++{
++ const conf = require('fs').readFileSync(require('path').join(__dirname, '..', 'deploy', 'nginx', 'openvibe.chat.conf'), 'utf8');
++ const blocks = conf.split(/\n location /).slice(1);
++ for (const b of blocks) {
++ const body = b.slice(0, b.indexOf('\n }'));
++ if (!/proxy_set_header/.test(body) || !/proxy_pass/.test(body)) continue;
++ for (const h of ['Host $host', 'X-Real-IP $remote_addr', 'CF-Connecting-IP $remote_addr']) require('assert').ok(body.includes(`proxy_set_header ${h}`), `location ${b.split(' ')[0]} ${b.split(' ')[1] || ''}: proxy_set_header ${h}`);
++ }
++}
console.log('nginx auth limit: /auth/me on the API zone, 429 when limited');