diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 5f802c004..b847222a5 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -156,7 +156,8 @@ const internalNginx = { {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}, {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list}, - {certificate: host.certificate}, host.locations[i]); + {certificate: host.certificate}, {proxy_protocol_enabled: host.proxy_protocol_enabled}, + {loadbalancer_address: host.loadbalancer_address}, host.locations[i]); if (locationCopy.forward_host.indexOf('/') > -1) { const splitted = locationCopy.forward_host.split('/'); diff --git a/backend/migrations/20241022221324_proxy_protocol.js b/backend/migrations/20241022221324_proxy_protocol.js new file mode 100644 index 000000000..fa1bd196e --- /dev/null +++ b/backend/migrations/20241022221324_proxy_protocol.js @@ -0,0 +1,56 @@ +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('proxy_protocol_enabled').notNull().defaultTo(0); + proxy_host.string('loadbalancer_address').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered'); + + return knex.schema.table('stream', function (stream) { + stream.integer('proxy_protocol_enabled').notNull().defaultTo(0); + stream.string('loadbalancer_address').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered'); + }); + }); + +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex/*, Promise*/) { + return knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.dropColumn('proxy_protocol_enabled'); + proxy_host.dropColumn('loadbalancer_address'); + }) + .then(function () { + logger.info('[' + migrate_name + '] proxy_host Table altered'); + return knex.schema.table('stream', function (stream) { + stream.dropColumn('proxy_protocol_enabled'); + stream.dropColumn('loadbalancer_address'); + }) + .then(function () { + logger.info('[' + migrate_name + '] stream Table altered'); + }); + }); +}; \ No newline at end of file diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js index 07aa5dd3c..d45acf02c 100644 --- a/backend/models/proxy_host.js +++ b/backend/models/proxy_host.js @@ -21,6 +21,7 @@ const boolFields = [ 'enabled', 'hsts_enabled', 'hsts_subdomains', + 'proxy_protocol_enabled', ]; class ProxyHost extends Model { diff --git a/backend/models/stream.js b/backend/models/stream.js index b96ca5a17..efc18f0ad 100644 --- a/backend/models/stream.js +++ b/backend/models/stream.js @@ -13,6 +13,7 @@ const boolFields = [ 'is_deleted', 'tcp_forwarding', 'udp_forwarding', + 'proxy_protocol_enabled', ]; class Stream extends Model { diff --git a/backend/schema/common.json b/backend/schema/common.json index 83de0143c..dee65224f 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -110,6 +110,16 @@ "caching_enabled": { "description": "Should we cache assets", "type": "boolean" + }, + "proxy_protocol_enabled": { + "description": "Should the proxy_procotol be enabled", + "type": "boolean" + }, + "loadbalancer_address": { + "description": "Hostname, IP or CIDR range of the load balancer", + "type": "string", + "minLength": 0, + "maxLength": 255 } } } diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json index 5098802b1..195c85a48 100644 --- a/backend/schema/components/proxy-host-object.json +++ b/backend/schema/components/proxy-host-object.json @@ -23,7 +23,9 @@ "locations", "hsts_enabled", "hsts_subdomains", - "certificate" + "certificate", + "proxy_protocol_enabled", + "loadbalancer_address" ], "additionalProperties": false, "properties": { @@ -137,6 +139,12 @@ } ] }, + "proxy_protocol_enabled": { + "$ref": "../common.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../common.json#/properties/loadbalancer_address" + }, "owner": { "$ref": "./user-object.json" }, diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json index 516c7f891..0d087c155 100644 --- a/backend/schema/components/stream-object.json +++ b/backend/schema/components/stream-object.json @@ -1,7 +1,7 @@ { "type": "object", "description": "Stream object", - "required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta"], + "required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta", "proxy_protocol_enabled", "loadbalancer_address"], "additionalProperties": false, "properties": { "id": { @@ -55,6 +55,12 @@ }, "meta": { "type": "object" + }, + "proxy_protocol_enabled": { + "$ref": "../common.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../common.json#/properties/loadbalancer_address" } } } diff --git a/backend/schema/paths/nginx/proxy-hosts/get.json b/backend/schema/paths/nginx/proxy-hosts/get.json index 1d9f63351..64e1b1877 100644 --- a/backend/schema/paths/nginx/proxy-hosts/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/get.json @@ -50,7 +50,9 @@ "enabled": true, "locations": null, "hsts_enabled": false, - "hsts_subdomains": false + "hsts_subdomains": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "" } ] } diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json index 5e10a9cfd..6d0562e32 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json @@ -50,7 +50,9 @@ "enabled": true, "locations": null, "hsts_enabled": false, - "hsts_subdomains": false + "hsts_subdomains": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "" } } }, diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json index 5cab6e752..997e6ff1a 100644 --- a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json +++ b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json @@ -79,6 +79,12 @@ }, "locations": { "$ref": "../../../../components/proxy-host-object.json#/properties/locations" + }, + "proxy_protocol_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../../../../components/proxy-host-object.json#/properties/loadbalancer_address" } } } @@ -116,6 +122,8 @@ "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", diff --git a/backend/schema/paths/nginx/proxy-hosts/post.json b/backend/schema/paths/nginx/proxy-hosts/post.json index 85455fb6b..340731a47 100644 --- a/backend/schema/paths/nginx/proxy-hosts/post.json +++ b/backend/schema/paths/nginx/proxy-hosts/post.json @@ -67,6 +67,12 @@ }, "locations": { "$ref": "../../../components/proxy-host-object.json#/properties/locations" + }, + "proxy_protocol_enabled": { + "$ref": "../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../../../components/proxy-host-object.json#/properties/loadbalancer_address" } } } @@ -101,6 +107,8 @@ "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "certificate": null, "owner": { "id": 1, diff --git a/backend/schema/paths/nginx/streams/get.json b/backend/schema/paths/nginx/streams/get.json index 596afc6e7..04c68a3b6 100644 --- a/backend/schema/paths/nginx/streams/get.json +++ b/backend/schema/paths/nginx/streams/get.json @@ -36,6 +36,8 @@ "forwarding_port": 80, "tcp_forwarding": true, "udp_forwarding": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "meta": { "nginx_online": true, "nginx_err": null diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json index 9f3514e0f..02a46a0c5 100644 --- a/backend/schema/paths/nginx/streams/post.json +++ b/backend/schema/paths/nginx/streams/post.json @@ -32,6 +32,12 @@ "udp_forwarding": { "$ref": "../../../components/stream-object.json#/properties/udp_forwarding" }, + "proxy_protocol_enabled": { + "$ref": "../../../components/stream-object.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../../../components/stream-object.json#/properties/loadbalancer_address" + }, "meta": { "$ref": "../../../components/stream-object.json#/properties/meta" } @@ -57,6 +63,8 @@ "forwarding_port": 80, "tcp_forwarding": true, "udp_forwarding": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "meta": { "nginx_online": true, "nginx_err": null diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json index 6547656df..9329def07 100644 --- a/backend/schema/paths/nginx/streams/streamID/get.json +++ b/backend/schema/paths/nginx/streams/streamID/get.json @@ -36,6 +36,8 @@ "forwarding_port": 80, "tcp_forwarding": true, "udp_forwarding": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "meta": { "nginx_online": true, "nginx_err": null diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json index fbfdc901b..ac2cd8856 100644 --- a/backend/schema/paths/nginx/streams/streamID/put.json +++ b/backend/schema/paths/nginx/streams/streamID/put.json @@ -79,6 +79,12 @@ }, "locations": { "$ref": "../../../../components/proxy-host-object.json#/properties/locations" + }, + "proxy_protocol_enabled": { + "$ref": "../../../../components/proxy-host-object.json#/properties/proxy_protocol_enabled" + }, + "loadbalancer_address": { + "$ref": "../../../../components/proxy-host-object.json#/properties/loadbalancer_address" } } } @@ -116,6 +122,8 @@ "enabled": true, "hsts_enabled": false, "hsts_subdomains": false, + "proxy_protocol_enabled": false, + "loadbalancer_address": "", "owner": { "id": 1, "created_on": "2024-10-07T22:43:55.000Z", diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 34a808e6a..45bd156a1 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,20 +1,34 @@ - listen 80; + +{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%} +{% assign port_number_http = "88" -%} +{% assign port_number_https = "444" -%} +{% assign listen_extra_args = "proxy_protocol" -%} +{% else -%} +{% assign port_number_http = "80" -%} +{% assign port_number_https = "443" -%} +{% assign listen_extra_args = "" -%} +{% endif -%} + + listen {{ port_number_http }} {{ listen_extra_args }}; {% if ipv6 -%} - listen [::]:80; + listen [::]:{{ port_number_http }} {{ listen_extra_args }}; {% else -%} - #listen [::]:80; -{% endif %} + #listen [::]:{{ port_number_http }} {{ listen_extra_args }}; +{% endif -%} + {% if certificate -%} - listen 443 ssl; +{% capture listen_extra_args_https %}ssl {{ listen_extra_args }}{% endcapture -%} + listen {{ port_number_https }} {{ listen_extra_args_https }}; {% if ipv6 -%} - listen [::]:443 ssl; + listen [::]:{{ port_number_https }} {{ listen_extra_args_https }}; {% else -%} - #listen [::]:443; -{% endif %} -{% endif %} + #listen [::]:{{ port_number_https }} {{ listen_extra_args_https }}; +{% endif -%} +{% endif -%} + server_name {{ domain_names | join: " " }}; {% if http2_support == 1 or http2_support == true %} http2 on; {% else -%} http2 off; -{% endif %} \ No newline at end of file +{% endif %} diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf new file mode 100644 index 000000000..96d615c18 --- /dev/null +++ b/backend/templates/_proxy_protocol.conf @@ -0,0 +1,6 @@ +{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true %} +{% if loadbalancer_address != '' %} + set_real_ip_from {{ loadbalancer_address }}; + 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 d23ca46fa..e753b6dde 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -15,6 +15,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/backend/templates/stream.conf b/backend/templates/stream.conf index 76159a646..72b7242da 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -1,31 +1,38 @@ # ------------------------------------------------------------ # {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }} # ------------------------------------------------------------ +{% if proxy_protocol_enabled == 1 or proxy_protocol_enabled == true -%} +{% capture listen_extra_args %}proxy_protocol{% endcapture -%} +{% endif -%} {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { - listen {{ incoming_port }}; + listen {{ incoming_port }} {{ listen_extra_args }}; {% if ipv6 -%} - listen [::]:{{ incoming_port }}; + listen [::]:{{ incoming_port }} {{ listen_extra_args }}; {% else -%} - #listen [::]:{{ incoming_port }}; + #listen [::]:{{ incoming_port }}{{ listen_extra_args }}; {% endif %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; +{% include '_proxy_protocol.conf' %} + # Custom include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream_tcp[.]conf; } {% endif %} {% if udp_forwarding == 1 or udp_forwarding == true %} +{% # Proxy Protocol is not supported for UDP %} +{% assign listen_extra_args = "" %} server { - listen {{ incoming_port }} udp; + listen {{ incoming_port }} udp {{ listen_extra_args }}; {% if ipv6 -%} - listen [::]:{{ incoming_port }} udp; + listen [::]:{{ incoming_port }} udp {{ listen_extra_args }}; {% else -%} - #listen [::]:{{ incoming_port }} udp; + #listen [::]:{{ incoming_port }} udp {{ listen_extra_args }}; {% endif %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; diff --git a/docker/Dockerfile b/docker/Dockerfile index 0603e2ded..ad84aa077 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,7 +35,8 @@ RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \ COPY docker/scripts/install-s6 /tmp/install-s6 RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6 -EXPOSE 80 81 443 +# http admin_ui http_proxy_protocol https https_proxy_protocol +EXPOSE 80 81 88 443 444 COPY backend /app COPY frontend/dist /app/frontend diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index bb4ac6d44..5b89e863c 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -35,5 +35,6 @@ RUN rm -f /etc/nginx/conf.d/production.conf \ COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt -EXPOSE 80 81 443 +# http admin_ui http_proxy_protocol https https_proxy_protocol +EXPOSE 80 81 88 443 444 ENTRYPOINT [ "/init" ] diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 2bfa2b798..d7a8b5638 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -10,7 +10,9 @@ services: ports: - 3080:80 - 3081:81 + - 3088:88 - 3443:443 + - 3444:444 networks: nginx_proxy_manager: aliases: diff --git a/docs/src/advanced-config/index.md b/docs/src/advanced-config/index.md index efeaefec3..82e183a18 100644 --- a/docs/src/advanced-config/index.md +++ b/docs/src/advanced-config/index.md @@ -222,3 +222,27 @@ To enable the geoip2 module, you can create the custom configuration file `/data load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so; load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so; ``` + +## Enabling PROXY protocol for Proxy Hosts + +When running NPM behind a load balancer, you might want to use the [PROXY procotol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) to receive client information such as the source IP address (useful for banning IPs). + +When configuring the PROXY protocol for proxy hosts, NPM uses the ports 88 for http and 444 for https traffic to allow you to decide on a per host basis whether to use the PROSY protocol. + +To enable the PROXY protocol for your hosts you need to perform the following steps: + +1. Expose the ports `88` (and `444` is applicable) by adjusting your `docker-compose.yml` +2. Edit your proxy hosts to enable the PROXY protocol +3. Edit your upstream load balancer to redirect traffic to the port `88`/`444` and enable the PROXY protocol + +## Enabling PROXY protocol for Streams + +When running NPM behind a load balancer, you might want to use the [PROXY procotol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) to receive client information such as the source IP address (useful for banning IPs). + +Keep in mind that the PROXY procotol cannot be enabled for udp endpoints. + +To enable the PROXY protocol for streams: + +1. Expose the desired port by adjusting you `docker-compose.yml` +2. Edit the Stream to enable the PROXY protocol +3. Edit your upstream load balancer to enable the PROXY protocol diff --git a/docs/src/setup/index.md b/docs/src/setup/index.md index ee8e9903d..6dd58418c 100644 --- a/docs/src/setup/index.md +++ b/docs/src/setup/index.md @@ -19,6 +19,8 @@ services: - '80:80' # Public HTTP Port - '443:443' # Public HTTPS Port - '81:81' # Admin Web Port + # - '88:88' # Public HTTP Port with proxy_protocol enabled + # - '444:444' # Public HTTPS Port with proxy_protocol enabled # Add any other Stream port you want to expose # - '21:21' # FTP diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 8e7a2a2df..33b4c682f 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -72,7 +72,7 @@ -
+
+
+
+ +
+
+ +
+
+ + > +
+
diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 4437a6ddd..c6089f727 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -43,7 +43,9 @@ module.exports = Mn.View.extend({ dns_provider_credentials: 'textarea[name="meta[dns_provider_credentials]"]', propagation_seconds: 'input[name="meta[propagation_seconds]"]', forward_scheme: 'select[name="forward_scheme"]', - letsencrypt: '.letsencrypt' + letsencrypt: '.letsencrypt', + proxy_protocol_enabled: 'input[name="proxy_protocol_enabled"]', + loadbalancer_address: 'input[name="loadbalancer_address"]', }, regions: { @@ -101,6 +103,14 @@ module.exports = Mn.View.extend({ } }, + 'change @ui.proxy_protocol_enabled': function () { + let checked = this.ui.proxy_protocol_enabled.prop('checked'); + this.ui.loadbalancer_address + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, + 'change @ui.dns_challenge_switch': function () { const checked = this.ui.dns_challenge_switch.prop('checked'); if (checked) { @@ -167,6 +177,7 @@ module.exports = Mn.View.extend({ data.hsts_enabled = !!data.hsts_enabled; data.hsts_subdomains = !!data.hsts_subdomains; data.ssl_forced = !!data.ssl_forced; + data.proxy_protocol_enabled = !!data.proxy_protocol_enabled; if (typeof data.meta === 'undefined') data.meta = {}; data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1; @@ -266,6 +277,7 @@ module.exports = Mn.View.extend({ this.ui.ssl_forced.trigger('change'); this.ui.hsts_enabled.trigger('change'); + this.ui.proxy_protocol_enabled.trigger('change'); // Domain names this.ui.domain_names.selectize({ diff --git a/frontend/js/app/nginx/stream/form.ejs b/frontend/js/app/nginx/stream/form.ejs index 1fc4f1342..11d5e2d22 100644 --- a/frontend/js/app/nginx/stream/form.ejs +++ b/frontend/js/app/nginx/stream/form.ejs @@ -42,6 +42,24 @@
+
+
+ +
+
+ +
+
+ + > +
+
<%- i18n('streams', 'forward-type-error') %>
diff --git a/frontend/js/app/nginx/stream/form.js b/frontend/js/app/nginx/stream/form.js index be8fc8bc2..2843fcb54 100644 --- a/frontend/js/app/nginx/stream/form.js +++ b/frontend/js/app/nginx/stream/form.js @@ -14,6 +14,8 @@ module.exports = Mn.View.extend({ ui: { form: 'form', forwarding_host: 'input[name="forwarding_host"]', + proxy_protocol_enabled: 'input[name="proxy_protocol_enabled"]', + loadbalancer_address: 'input[name="loadbalancer_address"]', type_error: '.forward-type-error', buttons: '.modal-footer button', switches: '.custom-switch-input', @@ -25,6 +27,13 @@ module.exports = Mn.View.extend({ 'change @ui.switches': function () { this.ui.type_error.hide(); }, + 'change @ui.proxy_protocol_enabled': function () { + let checked = this.ui.proxy_protocol_enabled.prop('checked'); + this.ui.loadbalancer_address + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, 'click @ui.save': function (e) { e.preventDefault(); @@ -47,6 +56,7 @@ module.exports = Mn.View.extend({ data.forwarding_port = parseInt(data.forwarding_port, 10); data.tcp_forwarding = !!data.tcp_forwarding; data.udp_forwarding = !!data.udp_forwarding; + data.proxy_protocol_enabled = !!data.proxy_protocol_enabled; let method = App.Api.Nginx.Streams.create; let is_new = true; @@ -76,6 +86,10 @@ module.exports = Mn.View.extend({ } }, + onRender: function () { + this.ui.proxy_protocol_enabled.trigger('change'); + }, + initialize: function (options) { if (typeof options.model === 'undefined' || !options.model) { this.model = new StreamModel.Model(); diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 0bbde4541..b4c44152c 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -133,7 +133,9 @@ "allow-websocket-upgrade": "Websockets Support", "ignore-invalid-upstream-ssl": "Ignore Invalid SSL", "custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/", - "search": "Search Host…" + "search": "Search Host…", + "enable-proxy-protocol": "Enable Proxy Protocol", + "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range" }, "redirection-hosts": { "title": "Redirection Hosts", @@ -179,7 +181,9 @@ "delete-confirm": "Are you sure you want to delete this Stream?", "help-title": "What is a Stream?", "help-content": "A relatively new feature for Nginx, a Stream will serve to forward TCP/UDP traffic directly to another computer on the network.\nIf you're running game servers, FTP or SSH servers this can come in handy.", - "search": "Search Incoming Port…" + "search": "Search Incoming Port…", + "enable-proxy-protocol": "Enable Proxy Protocol", + "load-balancer-ip": "Load balancer or TCP proxy IP / CIDR range" }, "certificates": { "title": "SSL Certificates", diff --git a/frontend/js/models/proxy-host.js b/frontend/js/models/proxy-host.js index b82d09fef..88a7e2481 100644 --- a/frontend/js/models/proxy-host.js +++ b/frontend/js/models/proxy-host.js @@ -21,6 +21,8 @@ const model = Backbone.Model.extend({ allow_websocket_upgrade: false, block_exploits: false, http2_support: false, + proxy_protocol_enabled: false, + loadbalancer_address: '', advanced_config: '', enabled: true, meta: {}, diff --git a/frontend/js/models/stream.js b/frontend/js/models/stream.js index ba035429a..1fb84590d 100644 --- a/frontend/js/models/stream.js +++ b/frontend/js/models/stream.js @@ -13,6 +13,8 @@ const model = Backbone.Model.extend({ forwarding_port: null, tcp_forwarding: true, udp_forwarding: false, + proxy_protocol_enabled: false, + loadbalancer_address: "", enabled: true, meta: {}, // The following are expansions: diff --git a/test/cypress/e2e/api/ProxyHosts.cy.js b/test/cypress/e2e/api/ProxyHosts.cy.js index 5bc645800..e4afd0faf 100644 --- a/test/cypress/e2e/api/ProxyHosts.cy.js +++ b/test/cypress/e2e/api/ProxyHosts.cy.js @@ -32,7 +32,9 @@ describe('Proxy Hosts endpoints', () => { http2_support: false, hsts_enabled: false, hsts_subdomains: false, - ssl_forced: false + ssl_forced: false, + proxy_protocol_enabled: false, + loadbalancer_address: '', } }).then((data) => { cy.validateSwaggerSchema('post', 201, '/nginx/proxy-hosts', data);