diff --git a/docker-compose.yml b/docker-compose.yml index ac0f64f9e..2ff821b21 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: - NODE_ENV=development - FORCE_COLOR=1 volumes: + - ./data:/data - ./data/letsencrypt:/etc/letsencrypt - .:/app - ./rootfs/etc/nginx:/etc/nginx diff --git a/rootfs/etc/nginx/conf.d/default.conf b/rootfs/etc/nginx/conf.d/default.conf index f24cbaf76..490e2868a 100644 --- a/rootfs/etc/nginx/conf.d/default.conf +++ b/rootfs/etc/nginx/conf.d/default.conf @@ -8,8 +8,9 @@ server { include conf.d/include/block-exploits.conf; - set $server 127.0.0.1; - set $port 81; + set $forward_scheme http; + set $server 127.0.0.1; + set $port 81; location /health { access_log off; diff --git a/rootfs/etc/nginx/conf.d/include/proxy.conf b/rootfs/etc/nginx/conf.d/include/proxy.conf index d02653aff..b84a45135 100644 --- a/rootfs/etc/nginx/conf.d/include/proxy.conf +++ b/rootfs/etc/nginx/conf.d/include/proxy.conf @@ -3,4 +3,4 @@ proxy_set_header Host $host; proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; -proxy_pass http://$server:$port; +proxy_pass $forward_scheme://$server:$port; diff --git a/rootfs/etc/nginx/nginx.conf b/rootfs/etc/nginx/nginx.conf index 1b6f4fd34..14efa598c 100644 --- a/rootfs/etc/nginx/nginx.conf +++ b/rootfs/etc/nginx/nginx.conf @@ -54,6 +54,11 @@ http { # Dynamically generated resolvers file include /etc/nginx/conf.d/include/resolvers.conf; + # Default upstream scheme + map $host $forward_scheme { + default http; + } + # Files generated by NPM include /etc/nginx/conf.d/*.conf; include /data/nginx/proxy_host/*.conf; diff --git a/src/backend/internal/proxy-host.js b/src/backend/internal/proxy-host.js index 7c627b7b8..407b01ae6 100644 --- a/src/backend/internal/proxy-host.js +++ b/src/backend/internal/proxy-host.js @@ -48,6 +48,11 @@ const internalProxyHost = { // At this point the domains should have been checked data.owner_user_id = access.token.getUserId(1); + // Ignoring upstream ssl errors only applies when upstream scheme is https + if (data.forward_scheme === 'http') { + data.ignore_invalid_upstream_ssl = false; + } + return proxyHostModel .query() .omit(omissions()) @@ -163,7 +168,12 @@ const internalProxyHost = { // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here. data = _.assign({}, { domain_names: row.domain_names - },data); + }, data); + + // Ignoring upstream ssl errors only applies when upstream scheme is https + if (typeof data.forward_scheme !== 'undefined' && data.forward_scheme === 'http') { + data.ignore_invalid_upstream_ssl = false; + } return proxyHostModel .query() diff --git a/src/backend/migrations/20181213013211_forward_scheme.js b/src/backend/migrations/20181213013211_forward_scheme.js new file mode 100644 index 000000000..6b74a4de5 --- /dev/null +++ b/src/backend/migrations/20181213013211_forward_scheme.js @@ -0,0 +1,37 @@ +'use strict'; + +const migrate_name = 'forward_scheme'; +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.string('forward_scheme').notNull().defaultTo('http'); + proxy_host.integer('ignore_invalid_upstream_ssl').notNull().unsigned().defaultTo(0); + }) + .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); +}; diff --git a/src/backend/schema/endpoints/proxy-hosts.json b/src/backend/schema/endpoints/proxy-hosts.json index 4cfb596fc..3f457ef7b 100644 --- a/src/backend/schema/endpoints/proxy-hosts.json +++ b/src/backend/schema/endpoints/proxy-hosts.json @@ -18,6 +18,10 @@ "domain_names": { "$ref": "../definitions.json#/definitions/domain_names" }, + "forward_scheme": { + "type": "string", + "enum": ["http", "https"] + }, "forward_host": { "type": "string", "minLength": 1, @@ -48,6 +52,11 @@ "example": true, "type": "boolean" }, + "ignore_invalid_upstream_ssl": { + "description": "Ignore invalid upstream SSL certificates", + "example": true, + "type": "boolean" + }, "access_list_id": { "$ref": "../definitions.json#/definitions/access_list_id" }, @@ -71,6 +80,9 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, + "forward_scheme": { + "$ref": "#/definitions/forward_scheme" + }, "forward_host": { "$ref": "#/definitions/forward_host" }, @@ -95,6 +107,9 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "ignore_invalid_upstream_ssl": { + "$ref": "#/definitions/ignore_invalid_upstream_ssl" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -138,6 +153,7 @@ "additionalProperties": false, "required": [ "domain_names", + "forward_scheme", "forward_host", "forward_port" ], @@ -145,6 +161,9 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, + "forward_scheme": { + "$ref": "#/definitions/forward_scheme" + }, "forward_host": { "$ref": "#/definitions/forward_host" }, @@ -169,6 +188,9 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "ignore_invalid_upstream_ssl": { + "$ref": "#/definitions/ignore_invalid_upstream_ssl" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -203,6 +225,9 @@ "domain_names": { "$ref": "#/definitions/domain_names" }, + "forward_scheme": { + "$ref": "#/definitions/forward_scheme" + }, "forward_host": { "$ref": "#/definitions/forward_host" }, @@ -227,6 +252,9 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "ignore_invalid_upstream_ssl": { + "$ref": "#/definitions/ignore_invalid_upstream_ssl" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, diff --git a/src/backend/templates/proxy_host.conf b/src/backend/templates/proxy_host.conf index b8a301d70..911fb3cc7 100644 --- a/src/backend/templates/proxy_host.conf +++ b/src/backend/templates/proxy_host.conf @@ -1,8 +1,9 @@ {% include "_header_comment.conf" %} server { - set $server "{{ forward_host }}"; - set $port {{ forward_port }}; + set $forward_scheme {{ forward_scheme }}; + set $server "{{ forward_host }}"; + set $port {{ forward_port }}; {% include "_listen.conf" %} {% include "_certificates.conf" %} diff --git a/src/frontend/js/app/nginx/dead/form.js b/src/frontend/js/app/nginx/dead/form.js index 39d08e839..881778e5c 100644 --- a/src/frontend/js/app/nginx/dead/form.js +++ b/src/frontend/js/app/nginx/dead/form.js @@ -83,7 +83,7 @@ module.exports = Mn.View.extend({ data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1'; } else { - data.certificate_id = parseInt(data.certificate_id, 0); + data.certificate_id = parseInt(data.certificate_id, 10); } let method = App.Api.Nginx.DeadHosts.create; diff --git a/src/frontend/js/app/nginx/proxy/form.ejs b/src/frontend/js/app/nginx/proxy/form.ejs index eca0ca6d5..6cda34fad 100644 --- a/src/frontend/js/app/nginx/proxy/form.ejs +++ b/src/frontend/js/app/nginx/proxy/form.ejs @@ -20,7 +20,16 @@ -
+
+
+ + +
+
+
@@ -50,7 +59,7 @@
-
+
+ +
+
+ +
+
+
diff --git a/src/frontend/js/app/nginx/proxy/form.js b/src/frontend/js/app/nginx/proxy/form.js index 378b9b6f9..89410e349 100644 --- a/src/frontend/js/app/nginx/proxy/form.js +++ b/src/frontend/js/app/nginx/proxy/form.js @@ -26,10 +26,20 @@ module.exports = Mn.View.extend({ access_list_select: 'select[name="access_list_id"]', ssl_forced: 'input[name="ssl_forced"]', http2_support: 'input[name="http2_support"]', + forward_scheme: 'select[name="forward_scheme"]', + ignore_ssl: 'input[name="ignore_invalid_upstream_ssl"]', letsencrypt: '.letsencrypt' }, events: { + 'change @ui.forward_scheme': function () { + let val = this.ui.forward_scheme.val(); + this.ui.ignore_ssl + .prop('disabled', val === 'http') + .parents('.form-group') + .css('opacity', val === 'https' ? 1 : 0.5); + }, + 'change @ui.certificate_select': function () { let id = this.ui.certificate_select.val(); if (id === 'new') { @@ -43,8 +53,6 @@ module.exports = Mn.View.extend({ .prop('disabled', !enabled) .parents('.form-group') .css('opacity', enabled ? 1 : 0.5); - - this.ui.http2_support.prop('disabled', !enabled); }, 'click @ui.save': function (e) { @@ -59,10 +67,11 @@ module.exports = Mn.View.extend({ let data = this.ui.form.serializeJSON(); // Manipulate - data.forward_port = parseInt(data.forward_port, 10); - data.block_exploits = !!data.block_exploits; - data.caching_enabled = !!data.caching_enabled; - data.allow_websocket_upgrade = !!data.allow_websocket_upgrade; + data.forward_port = parseInt(data.forward_port, 10); + data.block_exploits = !!data.block_exploits; + data.caching_enabled = !!data.caching_enabled; + data.allow_websocket_upgrade = !!data.allow_websocket_upgrade; + data.ignore_invalid_upstream_ssl = data.forward_scheme === 'https' ? !!data.ignore_invalid_upstream_ssl : false; if (typeof data.ssl_forced !== 'undefined' && data.ssl_forced === '1') { data.ssl_forced = true; @@ -92,7 +101,7 @@ module.exports = Mn.View.extend({ data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1'; } else { - data.certificate_id = parseInt(data.certificate_id, 0); + data.certificate_id = parseInt(data.certificate_id, 10); } let method = App.Api.Nginx.ProxyHosts.create; @@ -147,7 +156,6 @@ module.exports = Mn.View.extend({ }); // Access Lists - this.ui.letsencrypt.hide(); this.ui.access_list_select.selectize({ valueField: 'id', labelField: 'name', @@ -207,6 +215,8 @@ module.exports = Mn.View.extend({ view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id')); } }); + + this.ui.forward_scheme.trigger('change'); }, initialize: function (options) { diff --git a/src/frontend/js/app/nginx/proxy/list/item.ejs b/src/frontend/js/app/nginx/proxy/list/item.ejs index d6252ddbf..d91a598bd 100644 --- a/src/frontend/js/app/nginx/proxy/list/item.ejs +++ b/src/frontend/js/app/nginx/proxy/list/item.ejs @@ -23,7 +23,7 @@
-
<%- forward_host %>:<%- forward_port %>
+
<%- forward_scheme %>://<%- forward_host %>:<%- forward_port %>
<%- certificate && certificate_id ? i18n('ssl', certificate.provider) : i18n('ssl', 'none') %>
diff --git a/src/frontend/js/app/nginx/redirection/form.js b/src/frontend/js/app/nginx/redirection/form.js index 971082e05..182ebf686 100644 --- a/src/frontend/js/app/nginx/redirection/form.js +++ b/src/frontend/js/app/nginx/redirection/form.js @@ -86,7 +86,7 @@ module.exports = Mn.View.extend({ data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1'; } else { - data.certificate_id = parseInt(data.certificate_id, 0); + data.certificate_id = parseInt(data.certificate_id, 10); } let method = App.Api.Nginx.RedirectionHosts.create; diff --git a/src/frontend/js/i18n/messages.json b/src/frontend/js/i18n/messages.json index f96c300ae..c091439d9 100644 --- a/src/frontend/js/i18n/messages.json +++ b/src/frontend/js/i18n/messages.json @@ -93,6 +93,7 @@ "empty": "There are no Proxy Hosts", "add": "Add Proxy Host", "form-title": "{id, select, undefined{New} other{Edit}} Proxy Host", + "forward-scheme": "Scheme", "forward-host": "Forward Hostname / IP", "forward-port": "Forward Port", "delete": "Delete Proxy Host", @@ -100,7 +101,8 @@ "help-title": "What is a Proxy Host?", "help-content": "A Proxy Host is the incoming endpoint for a web service that you want to forward.\nIt provides optional SSL termination for your service that might not have SSL support built in.\nProxy Hosts are the most common use for the Nginx Proxy Manager.", "access-list": "Access List", - "allow-websocket-upgrade": "Allow Websocket HTTP Upgrades" + "allow-websocket-upgrade": "Websockets Support", + "ignore-invalid-upstream-ssl": "Ignore Invalid SSL" }, "redirection-hosts": { "title": "Redirection Hosts", diff --git a/src/frontend/js/models/proxy-host.js b/src/frontend/js/models/proxy-host.js index 2fe7d0015..41e45d057 100644 --- a/src/frontend/js/models/proxy-host.js +++ b/src/frontend/js/models/proxy-host.js @@ -7,25 +7,27 @@ const model = Backbone.Model.extend({ defaults: function () { return { - id: undefined, - created_on: null, - modified_on: null, - domain_names: [], - forward_host: '', - forward_port: null, - access_list_id: 0, - certificate_id: 0, - ssl_forced: false, - caching_enabled: false, - allow_websocket_upgrade: false, - block_exploits: false, - http2_support: false, - advanced_config: '', - meta: {}, + id: undefined, + created_on: null, + modified_on: null, + domain_names: [], + forward_scheme: 'http', + forward_host: '', + forward_port: null, + access_list_id: 0, + certificate_id: 0, + ssl_forced: false, + caching_enabled: false, + allow_websocket_upgrade: false, + block_exploits: false, + http2_support: false, + ignore_invalid_upstream_ssl: false, + advanced_config: '', + meta: {}, // The following are expansions: - owner: null, - access_list: null, - certificate: null + owner: null, + access_list: null, + certificate: null }; } });