Add TRUST_PROXY env var for reverse-proxy deployments

Fixes express-rate-limit's ERR_ERL_UNEXPECTED_X_FORWARDED_FOR warning
and incorrect IP keying when nginx runs on a separate server in front
of the app.
This commit is contained in:
2026-08-26 14:36:51 +02:00
parent 2dfe8d32c4
commit 1fce343b33
7 changed files with 33 additions and 3 deletions
+6
View File
@@ -7,6 +7,12 @@ and this project follows [Semantic Versioning](https://semver.org/).
## [Unreleased] ## [Unreleased]
## [1.9.4] - 2026-08-26
### Added
- New `TRUST_PROXY` backend env var — set it when the app runs behind a reverse proxy (e.g. nginx on a separate server) so rate limiting reads the real client IP from `X-Forwarded-For` instead of the proxy's. Accepts a hop count, `true`/`false`, or trusted proxy IP(s)/CIDR(s).
## [1.9.3] - 2026-08-26 ## [1.9.3] - 2026-08-26
### Fixed ### Fixed
+7
View File
@@ -8,6 +8,13 @@ JWT_SECRET=your_jwt_secret_here_minimum_32_characters
PORT=5000 PORT=5000
NODE_ENV=development NODE_ENV=development
# Set this if the app runs behind a reverse proxy (e.g. nginx on a separate
# server) so rate limiting reads the real client IP instead of the proxy's.
# Accepts a hop count ("1"), "true"/"false", or comma-separated IP(s)/CIDR(s)
# of your trusted proxy (e.g. "10.0.0.5" or "10.0.0.0/8"). Leave unset if the
# app is not behind a proxy.
# TRUST_PROXY=1
# ─── CORS ───────────────────────────────────────────────────────────────────── # ─── CORS ─────────────────────────────────────────────────────────────────────
# Comma-separated list of allowed frontend origins # Comma-separated list of allowed frontend origins
FRONTEND_URL=http://localhost:3000 FRONTEND_URL=http://localhost:3000
+1
View File
@@ -84,6 +84,7 @@ Create `backend/.env` from `.env.example`. The only variables you must set are:
| `APP_BASE_URL` | — | Public frontend URL — used in email links (fallback if not set via admin panel) | | `APP_BASE_URL` | — | Public frontend URL — used in email links (fallback if not set via admin panel) |
| `BACKEND_URL` | — | Public backend URL — used to serve ticket PDFs over WhatsApp | | `BACKEND_URL` | — | Public backend URL — used to serve ticket PDFs over WhatsApp |
| `PORT` | — | Port to listen on (default `3000`) | | `PORT` | — | Port to listen on (default `3000`) |
| `TRUST_PROXY` | — | Set when running behind a reverse proxy (e.g. nginx on a separate server), so `req.ip`/`X-Forwarded-For` are read correctly by rate limiting. Accepts a hop count (`1`), `true`/`false`, or comma-separated trusted proxy IP(s)/CIDR(s). |
| `NODE_ENV` | — | `production` or `development` | | `NODE_ENV` | — | `production` or `development` |
| `WAWP_ACCESS_TOKEN` | — | WAWP fallback token (preferred: set via Admin → Site Settings) | | `WAWP_ACCESS_TOKEN` | — | WAWP fallback token (preferred: set via Admin → Site Settings) |
| `WAWP_INSTANCE_ID` | — | WAWP fallback instance ID (preferred: set via Admin → Site Settings) | | `WAWP_INSTANCE_ID` | — | WAWP fallback instance ID (preferred: set via Admin → Site Settings) |
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "event-management-backend", "name": "event-management-backend",
"version": "1.9.3", "version": "1.9.4",
"description": "Event Management System Backend", "description": "Event Management System Backend",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
+16
View File
@@ -18,6 +18,22 @@ const prisma = new PrismaClient();
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
// Trust proxy — required when running behind a reverse proxy (e.g. nginx on a
// separate server) so req.ip / X-Forwarded-For are read correctly by
// express-rate-limit and friends. Accepts a hop count ("1"), "true"/"false",
// or a comma-separated list of trusted proxy IPs/CIDRs.
if (process.env.TRUST_PROXY) {
const raw = process.env.TRUST_PROXY.trim();
let trustProxyValue;
if (raw === 'true') trustProxyValue = true;
else if (raw === 'false') trustProxyValue = false;
else if (/^\d+$/.test(raw)) trustProxyValue = parseInt(raw, 10);
else if (raw.includes(',')) trustProxyValue = raw.split(',').map((s) => s.trim());
else trustProxyValue = raw;
app.set('trust proxy', trustProxyValue);
console.log(`[startup] trust proxy set to: ${JSON.stringify(trustProxyValue)}`);
}
// CORS — allow only the configured frontend origin // CORS — allow only the configured frontend origin
const allowedOrigins = (process.env.FRONTEND_URL || 'http://localhost:3000') const allowedOrigins = (process.env.FRONTEND_URL || 'http://localhost:3000')
.split(',') .split(',')
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hope-events-frontend", "name": "hope-events-frontend",
"version": "1.9.3", "version": "1.9.4",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hope-events", "name": "hope-events",
"version": "1.9.3", "version": "1.9.4",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"dev:backend": "cd backend && npm run dev", "dev:backend": "cd backend && npm run dev",