diff --git a/backend/internal/20220209144645_proxy_protocol.js b/backend/internal/20220209144645_proxy_protocol.js new file mode 100644 index 000000000..8c8099128 --- /dev/null +++ b/backend/internal/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/internal/nginx.js b/backend/internal/nginx.js index 77933e733..e5b62f140 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -154,7 +154,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}, {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 000000000..8c8099128 --- /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 9a3fff2fc..c74f655a2 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -58,6 +58,26 @@ "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 + }, + "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 +175,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 +271,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 +350,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 ad1c96ba0..e757d2ee3 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,15 +1,27 @@ +{% 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 -%} - listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %}; +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; {% if ipv6 -%} - listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %}; + listen [::]:444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; +{% endif %} {% else -%} - #listen [::]:443; + listen 443 ssl{% if http2_support %} http2{% endif %}; +{% endif %} +{% else -%} +{% if ipv6 -%} + listen [::]:443 ssl{% if http2_support %} http2{% endif %}; +{% endif %} {% endif %} {% endif %} - server_name {{ domain_names | join: " " }}; + 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 000000000..fa81494b7 --- /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 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/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 8e7a2a2df..1f236cee0 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 98f645669..31801bfa8 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', + enable_proxy_protocol: 'input[name="enable_proxy_protocol"]', + load_balancer_ip: 'input[name="load_balancer_ip"]' }, regions: { @@ -51,6 +53,14 @@ module.exports = Mn.View.extend({ }, events: { + 'change @ui.enable_proxy_protocol': function () { + let checked = this.ui.enable_proxy_protocol.prop('checked'); + this.ui.load_balancer_ip + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + }, + 'change @ui.certificate_select': function () { let id = this.ui.certificate_select.val(); if (id === 'new') { @@ -163,6 +173,7 @@ module.exports = Mn.View.extend({ data.block_exploits = !!data.block_exploits; data.caching_enabled = !!data.caching_enabled; data.allow_websocket_upgrade = !!data.allow_websocket_upgrade; + data.enable_proxy_protocol = !!data.enable_proxy_protocol; data.http2_support = !!data.http2_support; data.hsts_enabled = !!data.hsts_enabled; data.hsts_subdomains = !!data.hsts_subdomains; @@ -264,6 +275,7 @@ module.exports = Mn.View.extend({ onRender: function () { let view = this; + this.ui.enable_proxy_protocol.trigger('change'); this.ui.ssl_forced.trigger('change'); this.ui.hsts_enabled.trigger('change'); diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 0bbde4541..d7e0cf974 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -132,8 +132,10 @@ "access-list": "Access List", "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…" + "custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path", + "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", diff --git a/frontend/js/models/proxy-host.js b/frontend/js/models/proxy-host.js index b82d09fef..b1a80f541 100644 --- a/frontend/js/models/proxy-host.js +++ b/frontend/js/models/proxy-host.js @@ -19,6 +19,8 @@ const model = Backbone.Model.extend({ hsts_subdomains: false, caching_enabled: false, allow_websocket_upgrade: false, + enable_proxy_protocol: false, + load_balancer_ip: '', block_exploits: false, http2_support: false, advanced_config: '',