From ecb27521b411339d7cf9e9652d37b3e8174ed26c Mon Sep 17 00:00:00 2001
From: Stefano Badoino <16034687+SBado@users.noreply.github.com>
Date: Wed, 23 Feb 2022 11:32:39 +0100
Subject: [PATCH 01/33] PROXY Protocol support implementation
---
backend/internal/nginx.js | 3 +-
.../20220209144645_proxy_protocol.js | 36 +++++++++++++++++++
backend/schema/endpoints/proxy-hosts.json | 28 +++++++++++++++
backend/templates/_listen.conf | 20 ++++++++---
backend/templates/_proxy_protocol.conf | 6 ++++
backend/templates/proxy_host.conf | 1 +
frontend/js/app/nginx/proxy/form.ejs | 17 ++++++++-
frontend/js/app/nginx/proxy/form.js | 14 +++++++-
frontend/js/i18n/messages.json | 4 ++-
frontend/js/models/proxy-host.js | 2 ++
10 files changed, 122 insertions(+), 9 deletions(-)
create mode 100644 backend/migrations/20220209144645_proxy_protocol.js
create mode 100644 backend/templates/_proxy_protocol.conf
diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js
index 52bdd66dcc..0291dfda6d 100644
--- a/backend/internal/nginx.js
+++ b/backend/internal/nginx.js
@@ -157,7 +157,8 @@ const internalNginx = {
for (let i = 0; i < host.locations.length; i++) {
let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
{ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
- {allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
+ {allow_websocket_upgrade: host.allow_websocket_upgrade}, {enable_proxy_protocol: host.enable_proxy_protocol},
+ {load_balancer_ip: host.load_balancer_ip}, {http2_support: host.http2_support},
{hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
{certificate: host.certificate}, host.locations[i]);
diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js
new file mode 100644
index 0000000000..8c80991288
--- /dev/null
+++ b/backend/migrations/20220209144645_proxy_protocol.js
@@ -0,0 +1,36 @@
+const migrate_name = 'proxy_protocol';
+const logger = require('../logger').migrate;
+
+/**
+ * Migrate
+ *
+ * @see http://knexjs.org/#Schema
+ *
+ * @param {Object} knex
+ * @param {Promise} Promise
+ * @returns {Promise}
+ */
+exports.up = function (knex/*, Promise*/) {
+ logger.info('[' + migrate_name + '] Migrating Up...');
+
+ return knex.schema.table('proxy_host', function (proxy_host) {
+ proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0);
+ proxy_host.string('load_balancer_ip').notNull().defaultTo('');
+ })
+ .then(() => {
+ logger.info('[' + migrate_name + '] proxy_host Table altered');
+ });
+
+};
+
+/**
+ * Undo Migrate
+ *
+ * @param {Object} knex
+ * @param {Promise} Promise
+ * @returns {Promise}
+ */
+exports.down = function (knex, Promise) {
+ logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
+ return Promise.resolve(true);
+};
\ No newline at end of file
diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json
index 9a3fff2fc7..27a8ec2ab0 100644
--- a/backend/schema/endpoints/proxy-hosts.json
+++ b/backend/schema/endpoints/proxy-hosts.json
@@ -58,6 +58,16 @@
"example": true,
"type": "boolean"
},
+ "enable_proxy_protocol": {
+ "description": "Enable PROXY Protocol support",
+ "example": true,
+ "type": "boolean"
+ },
+ "load_balancer_ip": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 255
+ },
"access_list_id": {
"$ref": "../definitions.json#/definitions/access_list_id"
},
@@ -155,6 +165,12 @@
"allow_websocket_upgrade": {
"$ref": "#/definitions/allow_websocket_upgrade"
},
+ "enable_proxy_protocol": {
+ "$ref": "#/definitions/enable_proxy_protocol"
+ },
+ "load_balancer_ip": {
+ "$ref": "#/definitions/load_balancer_ip"
+ },
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
@@ -245,6 +261,12 @@
"allow_websocket_upgrade": {
"$ref": "#/definitions/allow_websocket_upgrade"
},
+ "enable_proxy_protocol": {
+ "$ref": "#/definitions/enable_proxy_protocol"
+ },
+ "load_balancer_ip": {
+ "$ref": "#/definitions/load_balancer_ip"
+ },
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
@@ -318,6 +340,12 @@
"allow_websocket_upgrade": {
"$ref": "#/definitions/allow_websocket_upgrade"
},
+ "enable_proxy_protocol": {
+ "$ref": "#/definitions/enable_proxy_protocol"
+ },
+ "load_balancer_ip": {
+ "$ref": "#/definitions/load_balancer_ip"
+ },
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf
index 730f3a7c4d..15f0c86592 100644
--- a/backend/templates/_listen.conf
+++ b/backend/templates/_listen.conf
@@ -1,15 +1,25 @@
+{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%}
+ listen 88 proxy_protocol;
+{% if ipv6 -%}
+ listen [::]:88 proxy_protocol;
+{% endif %}
+{% else -%}
listen 80;
{% if ipv6 -%}
listen [::]:80;
-{% else -%}
- #listen [::]:80;
+{% endif %}
{% endif %}
{% if certificate -%}
+{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%}
+ listen 444 ssl{% if http2_support %} http2{% endif %} proxy_protocol;
+{% if ipv6 -%}
+ listen [::]:444 ssl{% if http2_support %} http2{% endif %} proxy_protocol;
+{% endif %}
+{% else -%}
listen 443 ssl{% if http2_support %} http2{% endif %};
{% if ipv6 -%}
listen [::]:443 ssl{% if http2_support %} http2{% endif %};
-{% else -%}
- #listen [::]:443;
{% endif %}
{% endif %}
- server_name {{ domain_names | join: " " }};
+{% endif %}
+ server_name {{ domain_names | join: " " }};
\ No newline at end of file
diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf
new file mode 100644
index 0000000000..fa81494b72
--- /dev/null
+++ b/backend/templates/_proxy_protocol.conf
@@ -0,0 +1,6 @@
+{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %}
+{% if load_balancer_ip != '' %}
+ set_real_ip_from {{ load_balancer_ip }};
+ real_ip_header proxy_protocol;
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf
index ec30cca0da..d733c853a1 100644
--- a/backend/templates/proxy_host.conf
+++ b/backend/templates/proxy_host.conf
@@ -12,6 +12,7 @@ server {
{% include "_exploits.conf" %}
{% include "_hsts.conf" %}
{% include "_forced_ssl.conf" %}
+{% include "_proxy_protocol.conf" %}
{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
proxy_set_header Upgrade $http_upgrade;
diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs
index 56868f5528..9c30f13c49 100644
--- a/frontend/js/app/nginx/proxy/form.ejs
+++ b/frontend/js/app/nginx/proxy/form.ejs
@@ -72,7 +72,7 @@
-
+
+
+
@@ -360,7 +360,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
-
+ {/* */}
Date: Fri, 24 Apr 2026 04:34:00 -0700
Subject: [PATCH 09/33] Fill out missing schema
---
backend/schema/components/proxy-host-object.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json
index 2b281e20fa..61e943a4f6 100644
--- a/backend/schema/components/proxy-host-object.json
+++ b/backend/schema/components/proxy-host-object.json
@@ -92,9 +92,11 @@
"type": "boolean"
},
"load_balancer_ip": {
+ "description": "Load balancer or TCP proxy IP / CIDR range",
"type": "string",
"minLength": 0,
- "maxLength": 255
+ "maxLength": 255,
+ "example": "10.0.9.3"
},
"http2_support": {
"$ref": "../common.json#/properties/http2_support"
From 49bb74366cf8658b982288f518da6cc8c8136f2e Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Fri, 24 Apr 2026 04:34:10 -0700
Subject: [PATCH 10/33] Add PROXY protocol ports
---
docker/docker-compose.dev.yml | 2 ++
scripts/start-dev | 11 ++++++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml
index 4d519f8acd..8c316ac513 100644
--- a/docker/docker-compose.dev.yml
+++ b/docker/docker-compose.dev.yml
@@ -9,7 +9,9 @@ services:
ports:
- 3080:80
- 3081:81
+ - 3088:88
- 3443:443
+ - 3444:444
networks:
nginx_proxy_manager:
aliases:
diff --git a/scripts/start-dev b/scripts/start-dev
index c561ac9adf..0652bddc1f 100755
--- a/scripts/start-dev
+++ b/scripts/start-dev
@@ -45,9 +45,14 @@ if hash docker 2>/dev/null; then
bash "$DIR/wait-healthy" "$(docker compose ps --all -q fullstack)" 120
echo ""
- echo -e "${CYAN}Admin UI: http://127.0.0.1:3081${RESET}"
- echo -e "${CYAN}Nginx: http://127.0.0.1:3080${RESET}"
- echo -e "${CYAN}Swagger Doc: http://127.0.0.1:3001${RESET}"
+ echo -e "${CYAN}Admin UI: http://127.0.0.1:3081${RESET}"
+ echo -e "${CYAN}Nginx (HTTP): http://127.0.0.1:3080${RESET}"
+ echo -e "${CYAN}Nginx (HTTPS): http://127.0.0.1:3443${RESET}"
+ echo -e "${CYAN}Swagger Doc: http://127.0.0.1:3001${RESET}"
+ echo -e
+ echo -e "${CYAN}PROXY protocol:${RESET}"
+ echo -e "${CYAN}Nginx (HTTP): http://127.0.0.1:3088${RESET}"
+ echo -e "${CYAN}Nginx (HTTPS): http://127.0.0.1:3444${RESET}"
echo ""
if [ "$1" == "-f" ]; then
From d9990df2ae3d637f9a4850bbedb25a552ab424a2 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Fri, 24 Apr 2026 05:06:14 -0700
Subject: [PATCH 11/33] conditionally require and disable the load balancer ip
---
frontend/src/modals/ProxyHostModal.tsx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/frontend/src/modals/ProxyHostModal.tsx b/frontend/src/modals/ProxyHostModal.tsx
index 2c77dad1f1..f110c737e5 100644
--- a/frontend/src/modals/ProxyHostModal.tsx
+++ b/frontend/src/modals/ProxyHostModal.tsx
@@ -355,7 +355,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
-
+
{({ field, form }: any) => (
@@ -365,9 +365,10 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
{form.errors.loadBalancerIp ? (
From 6618f15558cfd3d1798be12c527a63e3f6cd24ba Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Fri, 24 Apr 2026 06:51:51 -0700
Subject: [PATCH 12/33] Fix lint errors
---
.../migrations/20220209144645_proxy_protocol.js | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js
index d27f9fe1d1..1f30054e09 100644
--- a/backend/migrations/20220209144645_proxy_protocol.js
+++ b/backend/migrations/20220209144645_proxy_protocol.js
@@ -7,17 +7,16 @@ import { migrate as logger } from "../logger.js";
* @see http://knexjs.org/#Schema
*
* @param {Object} knex
- * @param {Promise} Promise
* @returns {Promise}
*/
-const up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
+const up = (knex) => {
+ logger.info(`[${migrate_name}] Migrating Up...`);
- return knex.schema.table('proxy_host', function (proxy_host) {
+ return knex.schema.table('proxy_host', (proxy_host) => {
proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0);
proxy_host.string('load_balancer_ip').notNull().defaultTo('');
}).then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
+ logger.info(`[${migrate_name}] proxy_host Table altered`);
});
};
@@ -26,11 +25,10 @@ const up = function (knex/*, Promise*/) {
* Undo Migrate
*
* @param {Object} knex
- * @param {Promise} Promise
* @returns {Promise}
*/
-const down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
+const down = (_knex) => {
+ logger.warn(`[${migrate_name}] You can't migrate down this one.`);
return Promise.resolve(true);
};
From 857a35ea64a8ed295f809376fe3f8fe901394e30 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sat, 25 Apr 2026 01:49:42 -0700
Subject: [PATCH 13/33] Implement down migration and standardize on double
quotes
Make the variable name a little more generic
---
.../20220209144645_proxy_protocol.js | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js
index 1f30054e09..8113c4eb95 100644
--- a/backend/migrations/20220209144645_proxy_protocol.js
+++ b/backend/migrations/20220209144645_proxy_protocol.js
@@ -1,4 +1,4 @@
-const migrate_name = 'proxy_protocol';
+const migrate_name = "proxy_protocol";
import { migrate as logger } from "../logger.js";
/**
@@ -12,13 +12,12 @@ import { migrate as logger } from "../logger.js";
const up = (knex) => {
logger.info(`[${migrate_name}] Migrating Up...`);
- return knex.schema.table('proxy_host', (proxy_host) => {
- proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0);
- proxy_host.string('load_balancer_ip').notNull().defaultTo('');
+ return knex.schema.table("proxy_host", (table) => {
+ table.integer("enable_proxy_protocol").notNull().unsigned().defaultTo(0);
+ table.string("load_balancer_ip").notNull().defaultTo("");
}).then(() => {
logger.info(`[${migrate_name}] proxy_host Table altered`);
});
-
};
/**
@@ -28,8 +27,15 @@ const up = (knex) => {
* @returns {Promise}
*/
const down = (_knex) => {
- logger.warn(`[${migrate_name}] You can't migrate down this one.`);
- return Promise.resolve(true);
+ logger.info(`[${migrateName}] Migrating Down...`);
+
+ return knex.schema.table("proxy_host", (table) => {
+ table.dropColumn("enable_proxy_protocol");
+ table.dropColumn("load_balancer_ip");
+ })
+ .then(() => {
+ logger.info(`[${migrateName}] proxy_host Table altered`);
+ });
};
export { up, down };
From 5965a6c461ab1a5d1234b014473d10286e00f4d2 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sat, 25 Apr 2026 03:15:26 -0700
Subject: [PATCH 14/33] Add support for PROXY protocol for Streams
---
.../20260425014442_proxy_protocol_stream.js | 40 +++++++++++++++++++
backend/schema/components/stream-object.json | 8 +++-
backend/schema/paths/nginx/streams/get.json | 1 +
backend/schema/paths/nginx/streams/post.json | 5 +++
.../paths/nginx/streams/streamID/get.json | 1 +
.../paths/nginx/streams/streamID/put.json | 4 ++
backend/templates/stream.conf | 5 ++-
frontend/src/api/backend/models.ts | 1 +
frontend/src/hooks/useStream.ts | 1 +
frontend/src/modals/StreamModal.tsx | 30 ++++++++++++++
10 files changed, 93 insertions(+), 3 deletions(-)
create mode 100644 backend/migrations/20260425014442_proxy_protocol_stream.js
diff --git a/backend/migrations/20260425014442_proxy_protocol_stream.js b/backend/migrations/20260425014442_proxy_protocol_stream.js
new file mode 100644
index 0000000000..5099211bba
--- /dev/null
+++ b/backend/migrations/20260425014442_proxy_protocol_stream.js
@@ -0,0 +1,40 @@
+const migrate_name = "proxy_protocol_stream";
+import { migrate as logger } from "../logger.js";
+
+/**
+ * Migrate
+ *
+ * @see http://knexjs.org/#Schema
+ *
+ * @param {Object} knex
+ * @returns {Promise}
+ */
+const up = (knex) => {
+ logger.info(`[${migrate_name}] Migrating Up...`);
+
+ return knex.schema.table("stream", (table) => {
+ table.integer("enable_proxy_protocol").notNull().unsigned().defaultTo(0);
+ }).then(() => {
+ logger.info(`[${migrate_name}] stream Table altered`);
+ });
+
+};
+
+/**
+ * Undo Migrate
+ *
+ * @param {Object} knex
+ * @returns {Promise}
+ */
+const down = (_knex) => {
+ logger.info(`[${migrateName}] Migrating Down...`);
+
+ return knex.schema.table("stream", (table) => {
+ table.dropColumn("enable_proxy_protocol");
+ })
+ .then(() => {
+ logger.info(`[${migrateName}] stream Table altered`);
+ });
+};
+
+export { up, down };
diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json
index 602073ceca..42a2633933 100644
--- a/backend/schema/components/stream-object.json
+++ b/backend/schema/components/stream-object.json
@@ -12,7 +12,8 @@
"tcp_forwarding",
"udp_forwarding",
"enabled",
- "meta"
+ "meta",
+ "enable_proxy_protocol"
],
"additionalProperties": false,
"properties": {
@@ -70,6 +71,11 @@
"enabled": {
"$ref": "../common.json#/properties/enabled"
},
+ "enable_proxy_protocol": {
+ "description": "Enable PROXY Protocol support",
+ "type": "boolean",
+ "example": false
+ },
"certificate_id": {
"$ref": "../common.json#/properties/certificate_id"
},
diff --git a/backend/schema/paths/nginx/streams/get.json b/backend/schema/paths/nginx/streams/get.json
index 6dda8e346b..8243f9a918 100644
--- a/backend/schema/paths/nginx/streams/get.json
+++ b/backend/schema/paths/nginx/streams/get.json
@@ -41,6 +41,7 @@
"nginx_err": null
},
"enabled": true,
+ "enable_proxy_protocol": false,
"certificate_id": 0
}
]
diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json
index 0c986de8fa..06d5ad6924 100644
--- a/backend/schema/paths/nginx/streams/post.json
+++ b/backend/schema/paths/nginx/streams/post.json
@@ -41,6 +41,9 @@
"certificate_id": {
"$ref": "../../../components/stream-object.json#/properties/certificate_id"
},
+ "enable_proxy_protocol": {
+ "$ref": "../../../components/stream-object.json#/properties/enable_proxy_protocol",
+ },
"meta": {
"$ref": "../../../components/stream-object.json#/properties/meta"
},
@@ -56,6 +59,7 @@
"tcp_forwarding": true,
"udp_forwarding": false,
"certificate_id": 0,
+ "enable_proxy_protocol": false,
"meta": {}
}
}
@@ -83,6 +87,7 @@
"nginx_err": null
},
"enabled": true,
+ "enable_proxy_protocol": false,
"owner": {
"id": 1,
"created_on": "2024-10-09T02:33:16.000Z",
diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json
index 22fae8872b..c2094f98a3 100644
--- a/backend/schema/paths/nginx/streams/streamID/get.json
+++ b/backend/schema/paths/nginx/streams/streamID/get.json
@@ -42,6 +42,7 @@
"nginx_err": null
},
"enabled": true,
+ "enableProxyProtocol": false,
"certificate_id": 0
}
}
diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json
index 21ae71ef7a..cc52fe10d3 100644
--- a/backend/schema/paths/nginx/streams/streamID/put.json
+++ b/backend/schema/paths/nginx/streams/streamID/put.json
@@ -48,6 +48,9 @@
"certificate_id": {
"$ref": "../../../../components/stream-object.json#/properties/certificate_id"
},
+ "enable_proxy_protocol": {
+ "$ref": "../../../../components/stream-object.json#/properties/enable_proxy_protocol",
+ },
"meta": {
"$ref": "../../../../components/stream-object.json#/properties/meta"
}
@@ -78,6 +81,7 @@
"nginx_err": null
},
"enabled": true,
+ "enable_proxy_protocol": false,
"owner": {
"id": 1,
"created_on": "2024-10-09T02:33:16.000Z",
diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf
index 3a10387b27..d8af054e23 100644
--- a/backend/templates/stream.conf
+++ b/backend/templates/stream.conf
@@ -5,8 +5,9 @@
{% if enabled %}
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server {
- listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %};
- {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %};
+ listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
+ # {{ enable_proxy_protocol }}
+ {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
{%- include "_certificates_stream.conf" %}
diff --git a/frontend/src/api/backend/models.ts b/frontend/src/api/backend/models.ts
index d102b75557..832b7d45c7 100644
--- a/frontend/src/api/backend/models.ts
+++ b/frontend/src/api/backend/models.ts
@@ -191,6 +191,7 @@ export interface Stream {
udpForwarding: boolean;
meta: Record;
enabled: boolean;
+ enableProxyProtocol: boolean;
certificateId: number;
// Expansions:
owner?: User;
diff --git a/frontend/src/hooks/useStream.ts b/frontend/src/hooks/useStream.ts
index dfdddc1a08..ca8b0d5730 100644
--- a/frontend/src/hooks/useStream.ts
+++ b/frontend/src/hooks/useStream.ts
@@ -12,6 +12,7 @@ const fetchStream = (id: number | "new") => {
udpForwarding: false,
meta: {},
enabled: true,
+ enableProxyProtocol: false,
certificateId: 0,
} as Stream);
}
diff --git a/frontend/src/modals/StreamModal.tsx b/frontend/src/modals/StreamModal.tsx
index 6d55348896..29cd1e21a4 100644
--- a/frontend/src/modals/StreamModal.tsx
+++ b/frontend/src/modals/StreamModal.tsx
@@ -63,6 +63,7 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
tcpForwarding: data?.tcpForwarding,
udpForwarding: data?.udpForwarding,
certificateId: data?.certificateId,
+ enableProxyProtocol: data?.enableProxyProtocol,
meta: data?.meta || {},
} as any
}
@@ -278,6 +279,35 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
+
From 57c2fa376aa6861e61c59c563b16135f18129521 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sat, 25 Apr 2026 18:23:10 -0700
Subject: [PATCH 15/33] Fix streams tests
---
test/cypress/e2e/api/Streams.cy.js | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/test/cypress/e2e/api/Streams.cy.js b/test/cypress/e2e/api/Streams.cy.js
index 10809f8948..1cdac94942 100644
--- a/test/cypress/e2e/api/Streams.cy.js
+++ b/test/cypress/e2e/api/Streams.cy.js
@@ -45,7 +45,8 @@ describe('Streams', () => {
certificate_id: 0,
meta: {},
tcp_forwarding: true,
- udp_forwarding: false
+ udp_forwarding: false,
+ enable_proxy_protocol: false
}
}).then((data) => {
cy.validateSwaggerSchema('post', 201, '/nginx/streams', data);
@@ -54,6 +55,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
+ expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1500').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -73,7 +75,8 @@ describe('Streams', () => {
certificate_id: 0,
meta: {},
tcp_forwarding: false,
- udp_forwarding: true
+ udp_forwarding: true,
+ enable_proxy_protocol: false
}
}).then((data) => {
cy.validateSwaggerSchema('post', 201, '/nginx/streams', data);
@@ -82,6 +85,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', false);
expect(data).to.have.property('udp_forwarding', true);
+ expect(data).to.have.property('enable_proxy_protocol', false);
});
});
@@ -96,7 +100,8 @@ describe('Streams', () => {
certificate_id: 0,
meta: {},
tcp_forwarding: true,
- udp_forwarding: true
+ udp_forwarding: true,
+ enable_proxy_protocol: false
}
}).then((data) => {
cy.validateSwaggerSchema('post', 201, '/nginx/streams', data);
@@ -105,6 +110,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', true);
+ expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1502').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -153,7 +159,8 @@ describe('Streams', () => {
certificate_id: certID,
meta: {},
tcp_forwarding: true,
- udp_forwarding: false
+ udp_forwarding: false,
+ enable_proxy_protocol: false
}
}).then((data) => {
cy.validateSwaggerSchema('post', 201, '/nginx/streams', data);
@@ -163,6 +170,7 @@ describe('Streams', () => {
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
expect(data).to.have.property('certificate_id', certID);
+ expect(data).to.have.property('enable_proxy_protocol', false);
// Check the ssl termination
cy.task('log', '[testssl.sh] Running ...');
From b81951b94b31ad73111574ba4c52f9c697e6ed52 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sat, 25 Apr 2026 18:49:14 -0700
Subject: [PATCH 16/33] Remove the expects....?
---
test/cypress/e2e/api/Streams.cy.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/cypress/e2e/api/Streams.cy.js b/test/cypress/e2e/api/Streams.cy.js
index 1cdac94942..ce536ecc86 100644
--- a/test/cypress/e2e/api/Streams.cy.js
+++ b/test/cypress/e2e/api/Streams.cy.js
@@ -55,7 +55,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
- expect(data).to.have.property('enable_proxy_protocol', false);
+ // expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1500').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -85,7 +85,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', false);
expect(data).to.have.property('udp_forwarding', true);
- expect(data).to.have.property('enable_proxy_protocol', false);
+ // expect(data).to.have.property('enable_proxy_protocol', false);
});
});
@@ -110,7 +110,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', true);
- expect(data).to.have.property('enable_proxy_protocol', false);
+ // expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1502').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -170,7 +170,7 @@ describe('Streams', () => {
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
expect(data).to.have.property('certificate_id', certID);
- expect(data).to.have.property('enable_proxy_protocol', false);
+ // expect(data).to.have.property('enable_proxy_protocol', false);
// Check the ssl termination
cy.task('log', '[testssl.sh] Running ...');
From cb9d5cfaa24f281485103122aae86bd7fa4fda92 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sat, 25 Apr 2026 19:25:12 -0700
Subject: [PATCH 17/33] Add missing parameter to tests, not sure why ProxyHosts
test is working but Streams isn't...
---
test/cypress/e2e/api/ProxyHosts.cy.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/cypress/e2e/api/ProxyHosts.cy.js b/test/cypress/e2e/api/ProxyHosts.cy.js
index 5f437cf950..f86fd42ed8 100644
--- a/test/cypress/e2e/api/ProxyHosts.cy.js
+++ b/test/cypress/e2e/api/ProxyHosts.cy.js
@@ -29,6 +29,7 @@ describe('Proxy Hosts endpoints', () => {
block_exploits: false,
caching_enabled: false,
allow_websocket_upgrade: false,
+ enable_proxy_protocol: false,
http2_support: false,
hsts_enabled: false,
hsts_subdomains: false,
@@ -39,7 +40,7 @@ describe('Proxy Hosts endpoints', () => {
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
expect(data).to.have.property('enabled');
- expect(data).to.have.property("enabled", true);
+ expect(data).to.have.property('enabled', true);
expect(data).to.have.property('meta');
expect(typeof data.meta.nginx_online).to.be.equal('undefined');
});
From 7317102d7dd041bb330adc7ca0ef107623033a84 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Tue, 28 Apr 2026 22:03:32 -0700
Subject: [PATCH 18/33] This is a regex, it should be a pattern
---
backend/schema/components/stream-object.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json
index 42a2633933..d494c1d6bf 100644
--- a/backend/schema/components/stream-object.json
+++ b/backend/schema/components/stream-object.json
@@ -45,7 +45,7 @@
},
{
"type": "string",
- "format": "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"
+ "pattern": "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"
},
{
"type": "string",
From 548f3bd45f278a03593fb16696190860fd0bf53a Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Tue, 28 Apr 2026 23:35:48 -0700
Subject: [PATCH 19/33] Perhaps the problem is the onChange
---
frontend/src/modals/StreamModal.tsx | 6 ------
1 file changed, 6 deletions(-)
diff --git a/frontend/src/modals/StreamModal.tsx b/frontend/src/modals/StreamModal.tsx
index 29cd1e21a4..aea2a8e80c 100644
--- a/frontend/src/modals/StreamModal.tsx
+++ b/frontend/src/modals/StreamModal.tsx
@@ -294,12 +294,6 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
type="checkbox"
name={field.name}
checked={field.value}
- onChange={(e: any) => {
- setFieldValue(
- field.name,
- e.target.checked,
- );
- }}
/>
)}
From e72796199b5abb7085f5b3a7745604abd33b39f5 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Wed, 29 Apr 2026 00:32:29 -0700
Subject: [PATCH 20/33] Revert "Perhaps the problem is the onChange"
This reverts commit 548f3bd45f278a03593fb16696190860fd0bf53a.
---
frontend/src/modals/StreamModal.tsx | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/frontend/src/modals/StreamModal.tsx b/frontend/src/modals/StreamModal.tsx
index aea2a8e80c..29cd1e21a4 100644
--- a/frontend/src/modals/StreamModal.tsx
+++ b/frontend/src/modals/StreamModal.tsx
@@ -294,6 +294,12 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
type="checkbox"
name={field.name}
checked={field.value}
+ onChange={(e: any) => {
+ setFieldValue(
+ field.name,
+ e.target.checked,
+ );
+ }}
/>
)}
From 1a5f39a221a6161e8a421ca1e317fd192a3e068f Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Wed, 29 Apr 2026 00:32:37 -0700
Subject: [PATCH 21/33] Put back the expects
---
test/cypress/e2e/api/Streams.cy.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/cypress/e2e/api/Streams.cy.js b/test/cypress/e2e/api/Streams.cy.js
index ce536ecc86..1cdac94942 100644
--- a/test/cypress/e2e/api/Streams.cy.js
+++ b/test/cypress/e2e/api/Streams.cy.js
@@ -55,7 +55,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
- // expect(data).to.have.property('enable_proxy_protocol', false);
+ expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1500').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -85,7 +85,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', false);
expect(data).to.have.property('udp_forwarding', true);
- // expect(data).to.have.property('enable_proxy_protocol', false);
+ expect(data).to.have.property('enable_proxy_protocol', false);
});
});
@@ -110,7 +110,7 @@ describe('Streams', () => {
expect(data).to.have.property('enabled', true);
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', true);
- // expect(data).to.have.property('enable_proxy_protocol', false);
+ expect(data).to.have.property('enable_proxy_protocol', false);
cy.exec('curl --noproxy -- http://website1.example.com:1502').then((result) => {
expect(result.exitCode).to.eq(0);
@@ -170,7 +170,7 @@ describe('Streams', () => {
expect(data).to.have.property('tcp_forwarding', true);
expect(data).to.have.property('udp_forwarding', false);
expect(data).to.have.property('certificate_id', certID);
- // expect(data).to.have.property('enable_proxy_protocol', false);
+ expect(data).to.have.property('enable_proxy_protocol', false);
// Check the ssl termination
cy.task('log', '[testssl.sh] Running ...');
From efca9a8d80337139668422d2cf284f57fefb4f2c Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Wed, 29 Apr 2026 00:47:55 -0700
Subject: [PATCH 22/33] Let's also add a check to ProxyHosts tests to see if it
passes
---
test/cypress/e2e/api/ProxyHosts.cy.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/cypress/e2e/api/ProxyHosts.cy.js b/test/cypress/e2e/api/ProxyHosts.cy.js
index f86fd42ed8..03778b5fb2 100644
--- a/test/cypress/e2e/api/ProxyHosts.cy.js
+++ b/test/cypress/e2e/api/ProxyHosts.cy.js
@@ -41,6 +41,7 @@ describe('Proxy Hosts endpoints', () => {
expect(data.id).to.be.greaterThan(0);
expect(data).to.have.property('enabled');
expect(data).to.have.property('enabled', true);
+ expect(data).to.have.property('enable_proxy_protocol', false);
expect(data).to.have.property('meta');
expect(typeof data.meta.nginx_online).to.be.equal('undefined');
});
From a9e57299f705f930ca558e46ea4eac619ed9f038 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Wed, 29 Apr 2026 00:54:47 -0700
Subject: [PATCH 23/33] Aha! The magic boolean list didn't have
enable_proxy_protocol
---
backend/models/stream.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/backend/models/stream.js b/backend/models/stream.js
index 20a23a26f8..2df7ded047 100644
--- a/backend/models/stream.js
+++ b/backend/models/stream.js
@@ -7,7 +7,13 @@ import User from "./user.js";
Model.knex(db());
-const boolFields = ["is_deleted", "enabled", "tcp_forwarding", "udp_forwarding"];
+const boolFields = [
+ "is_deleted",
+ "enabled",
+ "tcp_forwarding",
+ "udp_forwarding",
+ "enable_proxy_protocol"
+];
class Stream extends Model {
$beforeInsert() {
From 4b58ca6d2c8ba4058ac82caccc914d1b888ab1c9 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Wed, 29 Apr 2026 01:12:05 -0700
Subject: [PATCH 24/33] Fix the name of the property here
---
backend/schema/paths/nginx/streams/streamID/get.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json
index c2094f98a3..3732df44b3 100644
--- a/backend/schema/paths/nginx/streams/streamID/get.json
+++ b/backend/schema/paths/nginx/streams/streamID/get.json
@@ -42,7 +42,7 @@
"nginx_err": null
},
"enabled": true,
- "enableProxyProtocol": false,
+ "enable_proxy_protocol": false,
"certificate_id": 0
}
}
From dcff928f8dfda53bff89ed4d4b0746025b87c558 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:14:09 -0700
Subject: [PATCH 25/33] Fix migration variable names
---
backend/migrations/20220209144645_proxy_protocol.js | 6 +++---
backend/migrations/20260425014442_proxy_protocol_stream.js | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20220209144645_proxy_protocol.js
index 8113c4eb95..e6d7e466bc 100644
--- a/backend/migrations/20220209144645_proxy_protocol.js
+++ b/backend/migrations/20220209144645_proxy_protocol.js
@@ -26,15 +26,15 @@ const up = (knex) => {
* @param {Object} knex
* @returns {Promise}
*/
-const down = (_knex) => {
- logger.info(`[${migrateName}] Migrating Down...`);
+const down = (knex) => {
+ logger.info(`[${migrate_name}] Migrating Down...`);
return knex.schema.table("proxy_host", (table) => {
table.dropColumn("enable_proxy_protocol");
table.dropColumn("load_balancer_ip");
})
.then(() => {
- logger.info(`[${migrateName}] proxy_host Table altered`);
+ logger.info(`[${migrate_name}] proxy_host Table altered`);
});
};
diff --git a/backend/migrations/20260425014442_proxy_protocol_stream.js b/backend/migrations/20260425014442_proxy_protocol_stream.js
index 5099211bba..b7f63b5a7b 100644
--- a/backend/migrations/20260425014442_proxy_protocol_stream.js
+++ b/backend/migrations/20260425014442_proxy_protocol_stream.js
@@ -26,14 +26,14 @@ const up = (knex) => {
* @param {Object} knex
* @returns {Promise}
*/
-const down = (_knex) => {
- logger.info(`[${migrateName}] Migrating Down...`);
+const down = (knex) => {
+ logger.info(`[${migrate_name}] Migrating Down...`);
return knex.schema.table("stream", (table) => {
table.dropColumn("enable_proxy_protocol");
})
.then(() => {
- logger.info(`[${migrateName}] stream Table altered`);
+ logger.info(`[${migrate_name}] stream Table altered`);
});
};
From 85502c0cc8af076a7c2264b9304d854b8a7bf295 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:16:09 -0700
Subject: [PATCH 26/33] Rename this migration that was inherited from the
four-year-old branch this was based on
---
...9144645_proxy_protocol.js => 20260425014441_proxy_protocol.js} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename backend/migrations/{20220209144645_proxy_protocol.js => 20260425014441_proxy_protocol.js} (100%)
diff --git a/backend/migrations/20220209144645_proxy_protocol.js b/backend/migrations/20260425014441_proxy_protocol.js
similarity index 100%
rename from backend/migrations/20220209144645_proxy_protocol.js
rename to backend/migrations/20260425014441_proxy_protocol.js
From affc8006f448fbf94adc77209d1400fc4c7cadca Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:17:21 -0700
Subject: [PATCH 27/33] Remove trailing commas from JSON
---
backend/schema/paths/nginx/streams/post.json | 2 +-
backend/schema/paths/nginx/streams/streamID/put.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json
index 06d5ad6924..0ddc8fddf0 100644
--- a/backend/schema/paths/nginx/streams/post.json
+++ b/backend/schema/paths/nginx/streams/post.json
@@ -42,7 +42,7 @@
"$ref": "../../../components/stream-object.json#/properties/certificate_id"
},
"enable_proxy_protocol": {
- "$ref": "../../../components/stream-object.json#/properties/enable_proxy_protocol",
+ "$ref": "../../../components/stream-object.json#/properties/enable_proxy_protocol"
},
"meta": {
"$ref": "../../../components/stream-object.json#/properties/meta"
diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json
index cc52fe10d3..cb09129c01 100644
--- a/backend/schema/paths/nginx/streams/streamID/put.json
+++ b/backend/schema/paths/nginx/streams/streamID/put.json
@@ -49,7 +49,7 @@
"$ref": "../../../../components/stream-object.json#/properties/certificate_id"
},
"enable_proxy_protocol": {
- "$ref": "../../../../components/stream-object.json#/properties/enable_proxy_protocol",
+ "$ref": "../../../../components/stream-object.json#/properties/enable_proxy_protocol"
},
"meta": {
"$ref": "../../../../components/stream-object.json#/properties/meta"
From fbeb4a5f626d67ab57702750a0645e40c0c1977b Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:20:22 -0700
Subject: [PATCH 28/33] Remove comment
---
backend/templates/stream.conf | 1 -
1 file changed, 1 deletion(-)
diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf
index d8af054e23..3ed96ffad4 100644
--- a/backend/templates/stream.conf
+++ b/backend/templates/stream.conf
@@ -6,7 +6,6 @@
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server {
listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
- # {{ enable_proxy_protocol }}
{% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
{%- include "_certificates_stream.conf" %}
From db737473efae8dc0bc0b5bb5a69d01c76ab5476b Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:20:44 -0700
Subject: [PATCH 29/33] Add "or enable_proxy_protocol == true" to make these
checks the same as the other template
---
backend/templates/stream.conf | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf
index 3ed96ffad4..dc65de5191 100644
--- a/backend/templates/stream.conf
+++ b/backend/templates/stream.conf
@@ -5,8 +5,8 @@
{% if enabled %}
{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
server {
- listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
- {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 %} proxy_protocol {%- endif %};
+ listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} proxy_protocol {%- endif %};
+ {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %} {%- if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} proxy_protocol {%- endif %};
{%- include "_certificates_stream.conf" %}
From f5adcf953f076d6cad41e05d61b51c135d34c3ab Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:22:09 -0700
Subject: [PATCH 30/33] load_balancer_ip is actually required
---
backend/templates/_proxy_protocol.conf | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf
index acba5e13b3..5e980f3c72 100644
--- a/backend/templates/_proxy_protocol.conf
+++ b/backend/templates/_proxy_protocol.conf
@@ -1,6 +1,4 @@
{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %}
-{% if load_balancer_ip != '' %}
- set_real_ip_from {{ load_balancer_ip }};
-{% endif %}
+set_real_ip_from {{ load_balancer_ip }};
real_ip_header proxy_protocol;
{% endif %}
From ae28cac323f2f2f0406b84023e935a6833d7a320 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:34:29 -0700
Subject: [PATCH 31/33] Remove commented code
---
frontend/src/modals/ProxyHostModal.tsx | 1 -
frontend/src/modals/StreamModal.tsx | 1 -
2 files changed, 2 deletions(-)
diff --git a/frontend/src/modals/ProxyHostModal.tsx b/frontend/src/modals/ProxyHostModal.tsx
index f110c737e5..a9b4e11a09 100644
--- a/frontend/src/modals/ProxyHostModal.tsx
+++ b/frontend/src/modals/ProxyHostModal.tsx
@@ -351,7 +351,6 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
)}
- {/* <%- i18n('proxy-hosts', 'enable-proxy-protocol') %> */}
diff --git a/frontend/src/modals/StreamModal.tsx b/frontend/src/modals/StreamModal.tsx
index 29cd1e21a4..9443126edd 100644
--- a/frontend/src/modals/StreamModal.tsx
+++ b/frontend/src/modals/StreamModal.tsx
@@ -305,7 +305,6 @@ const StreamModal = EasyModal.create(({ id, visible, remove }: Props) => {
)}
- {/*
<%- i18n('proxy-hosts', 'enable-proxy-protocol') %> */}
From f9c59d9742f26f5f56b23887b47f50eca0b84f16 Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 01:47:22 -0700
Subject: [PATCH 32/33] Add docs for PROXY protocol listeners
---
docs/src/advanced-config/index.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/docs/src/advanced-config/index.md b/docs/src/advanced-config/index.md
index 3ab04ce25b..b0eb155c1e 100644
--- a/docs/src/advanced-config/index.md
+++ b/docs/src/advanced-config/index.md
@@ -248,3 +248,16 @@ On startup, we generate a resolvers directive for Nginx unless this is defined:
In this configuration, all DNS queries performed by Nginx will fall to the `/etc/hosts` file
and then the `/etc/resolv.conf`.
+
+## Using PROXY protocol
+
+If you are using PROXY protocol support for any proxy host or stream you will need to expose ports `88` and `444` for HTTP and HTTPS listeners with PROXY protocol support.
+```yml
+ ports:
+ # Public HTTP Port with PROXY protocol:
+ - '88:88'
+ # Public HTTPS Port with PROXY protocol:
+ - '444:444'
+```
+
+NPM will still listen on ports `80` and `443` for proxy hosts and streams where the PROXY protocol option has not been enabled.
From bdcc1c3bcfb6a595adb6f2d5381cec195764e37f Mon Sep 17 00:00:00 2001
From: Julia V Rose
Date: Sun, 17 May 2026 02:02:18 -0700
Subject: [PATCH 33/33] Add a test for creating a steram with PROXY protocol
enabled
---
test/cypress/e2e/api/Streams.cy.js | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/test/cypress/e2e/api/Streams.cy.js b/test/cypress/e2e/api/Streams.cy.js
index 1cdac94942..bef02c56ac 100644
--- a/test/cypress/e2e/api/Streams.cy.js
+++ b/test/cypress/e2e/api/Streams.cy.js
@@ -119,6 +119,31 @@ describe('Streams', () => {
});
});
+ it('Should be able to enable PROXY protocol on a Stream', () => {
+ cy.task('backendApiPost', {
+ token: token,
+ path: '/api/nginx/streams',
+ data: {
+ incoming_port: 1502,
+ forwarding_host: '127.0.0.1',
+ forwarding_port: 80,
+ certificate_id: 0,
+ meta: {},
+ tcp_forwarding: true,
+ udp_forwarding: true,
+ enable_proxy_protocol: true
+ }
+ }).then((data) => {
+ cy.validateSwaggerSchema('post', 201, '/nginx/streams', data);
+ expect(data).to.have.property('id');
+ expect(data.id).to.be.greaterThan(0);
+ expect(data).to.have.property('enabled', true);
+ expect(data).to.have.property('tcp_forwarding', true);
+ expect(data).to.have.property('udp_forwarding', true);
+ expect(data).to.have.property('enable_proxy_protocol', true);
+ });
+ });
+
it('Should be able to create SSL TCP Stream', () => {
let certID = 0;