Skip to content

Commit c97e6ad

Browse files
committed
Support for upstream ssl proxy hosts
1 parent cd40ca7 commit c97e6ad

File tree

15 files changed

+155
-38
lines changed

15 files changed

+155
-38
lines changed

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ services:
1111
- NODE_ENV=development
1212
- FORCE_COLOR=1
1313
volumes:
14+
- ./data:/data
1415
- ./data/letsencrypt:/etc/letsencrypt
1516
- .:/app
1617
- ./rootfs/etc/nginx:/etc/nginx

rootfs/etc/nginx/conf.d/default.conf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ server {
88

99
include conf.d/include/block-exploits.conf;
1010

11-
set $server 127.0.0.1;
12-
set $port 81;
11+
set $forward_scheme http;
12+
set $server 127.0.0.1;
13+
set $port 81;
1314

1415
location /health {
1516
access_log off;

rootfs/etc/nginx/conf.d/include/proxy.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ proxy_set_header Host $host;
33
proxy_set_header X-Forwarded-Scheme $scheme;
44
proxy_set_header X-Forwarded-Proto $scheme;
55
proxy_set_header X-Forwarded-For $remote_addr;
6-
proxy_pass http://$server:$port;
6+
proxy_pass $forward_scheme://$server:$port;

rootfs/etc/nginx/nginx.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ http {
5454
# Dynamically generated resolvers file
5555
include /etc/nginx/conf.d/include/resolvers.conf;
5656

57+
# Default upstream scheme
58+
map $host $forward_scheme {
59+
default http;
60+
}
61+
5762
# Files generated by NPM
5863
include /etc/nginx/conf.d/*.conf;
5964
include /data/nginx/proxy_host/*.conf;

src/backend/internal/proxy-host.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ const internalProxyHost = {
4848
// At this point the domains should have been checked
4949
data.owner_user_id = access.token.getUserId(1);
5050

51+
// Ignoring upstream ssl errors only applies when upstream scheme is https
52+
if (data.forward_scheme === 'http') {
53+
data.ignore_invalid_upstream_ssl = false;
54+
}
55+
5156
return proxyHostModel
5257
.query()
5358
.omit(omissions())
@@ -163,7 +168,12 @@ const internalProxyHost = {
163168
// Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
164169
data = _.assign({}, {
165170
domain_names: row.domain_names
166-
},data);
171+
}, data);
172+
173+
// Ignoring upstream ssl errors only applies when upstream scheme is https
174+
if (typeof data.forward_scheme !== 'undefined' && data.forward_scheme === 'http') {
175+
data.ignore_invalid_upstream_ssl = false;
176+
}
167177

168178
return proxyHostModel
169179
.query()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
const migrate_name = 'forward_scheme';
4+
const logger = require('../logger').migrate;
5+
6+
/**
7+
* Migrate
8+
*
9+
* @see http://knexjs.org/#Schema
10+
*
11+
* @param {Object} knex
12+
* @param {Promise} Promise
13+
* @returns {Promise}
14+
*/
15+
exports.up = function (knex/*, Promise*/) {
16+
logger.info('[' + migrate_name + '] Migrating Up...');
17+
18+
return knex.schema.table('proxy_host', function (proxy_host) {
19+
proxy_host.string('forward_scheme').notNull().defaultTo('http');
20+
proxy_host.integer('ignore_invalid_upstream_ssl').notNull().unsigned().defaultTo(0);
21+
})
22+
.then(() => {
23+
logger.info('[' + migrate_name + '] proxy_host Table altered');
24+
});
25+
};
26+
27+
/**
28+
* Undo Migrate
29+
*
30+
* @param {Object} knex
31+
* @param {Promise} Promise
32+
* @returns {Promise}
33+
*/
34+
exports.down = function (knex, Promise) {
35+
logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
36+
return Promise.resolve(true);
37+
};

src/backend/schema/endpoints/proxy-hosts.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
"domain_names": {
1919
"$ref": "../definitions.json#/definitions/domain_names"
2020
},
21+
"forward_scheme": {
22+
"type": "string",
23+
"enum": ["http", "https"]
24+
},
2125
"forward_host": {
2226
"type": "string",
2327
"minLength": 1,
@@ -48,6 +52,11 @@
4852
"example": true,
4953
"type": "boolean"
5054
},
55+
"ignore_invalid_upstream_ssl": {
56+
"description": "Ignore invalid upstream SSL certificates",
57+
"example": true,
58+
"type": "boolean"
59+
},
5160
"access_list_id": {
5261
"$ref": "../definitions.json#/definitions/access_list_id"
5362
},
@@ -71,6 +80,9 @@
7180
"domain_names": {
7281
"$ref": "#/definitions/domain_names"
7382
},
83+
"forward_scheme": {
84+
"$ref": "#/definitions/forward_scheme"
85+
},
7486
"forward_host": {
7587
"$ref": "#/definitions/forward_host"
7688
},
@@ -95,6 +107,9 @@
95107
"allow_websocket_upgrade": {
96108
"$ref": "#/definitions/allow_websocket_upgrade"
97109
},
110+
"ignore_invalid_upstream_ssl": {
111+
"$ref": "#/definitions/ignore_invalid_upstream_ssl"
112+
},
98113
"access_list_id": {
99114
"$ref": "#/definitions/access_list_id"
100115
},
@@ -138,13 +153,17 @@
138153
"additionalProperties": false,
139154
"required": [
140155
"domain_names",
156+
"forward_scheme",
141157
"forward_host",
142158
"forward_port"
143159
],
144160
"properties": {
145161
"domain_names": {
146162
"$ref": "#/definitions/domain_names"
147163
},
164+
"forward_scheme": {
165+
"$ref": "#/definitions/forward_scheme"
166+
},
148167
"forward_host": {
149168
"$ref": "#/definitions/forward_host"
150169
},
@@ -169,6 +188,9 @@
169188
"allow_websocket_upgrade": {
170189
"$ref": "#/definitions/allow_websocket_upgrade"
171190
},
191+
"ignore_invalid_upstream_ssl": {
192+
"$ref": "#/definitions/ignore_invalid_upstream_ssl"
193+
},
172194
"access_list_id": {
173195
"$ref": "#/definitions/access_list_id"
174196
},
@@ -203,6 +225,9 @@
203225
"domain_names": {
204226
"$ref": "#/definitions/domain_names"
205227
},
228+
"forward_scheme": {
229+
"$ref": "#/definitions/forward_scheme"
230+
},
206231
"forward_host": {
207232
"$ref": "#/definitions/forward_host"
208233
},
@@ -227,6 +252,9 @@
227252
"allow_websocket_upgrade": {
228253
"$ref": "#/definitions/allow_websocket_upgrade"
229254
},
255+
"ignore_invalid_upstream_ssl": {
256+
"$ref": "#/definitions/ignore_invalid_upstream_ssl"
257+
},
230258
"access_list_id": {
231259
"$ref": "#/definitions/access_list_id"
232260
},

src/backend/templates/proxy_host.conf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{% include "_header_comment.conf" %}
22

33
server {
4-
set $server "{{ forward_host }}";
5-
set $port {{ forward_port }};
4+
set $forward_scheme {{ forward_scheme }};
5+
set $server "{{ forward_host }}";
6+
set $port {{ forward_port }};
67

78
{% include "_listen.conf" %}
89
{% include "_certificates.conf" %}

src/frontend/js/app/nginx/dead/form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ module.exports = Mn.View.extend({
8383

8484
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1';
8585
} else {
86-
data.certificate_id = parseInt(data.certificate_id, 0);
86+
data.certificate_id = parseInt(data.certificate_id, 10);
8787
}
8888

8989
let method = App.Api.Nginx.DeadHosts.create;

src/frontend/js/app/nginx/proxy/form.ejs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@
2020
<input type="text" name="domain_names" class="form-control" id="input-domains" value="<%- domain_names.join(',') %>" required>
2121
</div>
2222
</div>
23-
<div class="col-sm-8 col-md-8">
23+
<div class="col-sm-3 col-md-3">
24+
<div class="form-group">
25+
<label class="form-label"><%- i18n('proxy-hosts', 'forward-scheme') %><span class="form-required">*</span></label>
26+
<select name="forward_scheme" class="form-control custom-select" placeholder="http">
27+
<option value="http" <%- forward_scheme === 'http' ? 'selected' : '' %>>http</option>
28+
<option value="https" <%- forward_scheme === 'https' ? 'selected' : '' %>>https</option>
29+
</select>
30+
</div>
31+
</div>
32+
<div class="col-sm-5 col-md-5">
2433
<div class="form-group">
2534
<label class="form-label"><%- i18n('proxy-hosts', 'forward-host') %><span class="form-required">*</span></label>
2635
<input type="text" name="forward_host" class="form-control text-monospace" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="50" required>
@@ -50,7 +59,7 @@
5059
</label>
5160
</div>
5261
</div>
53-
<div class="col-sm-12 col-md-12">
62+
<div class="col-sm-6 col-md-6">
5463
<div class="form-group">
5564
<label class="custom-switch">
5665
<input type="checkbox" class="custom-switch-input" name="allow_websocket_upgrade" value="1"<%- allow_websocket_upgrade ? ' checked' : '' %>>
@@ -59,6 +68,17 @@
5968
</label>
6069
</div>
6170
</div>
71+
72+
<div class="col-sm-6 col-md-6">
73+
<div class="form-group">
74+
<label class="custom-switch">
75+
<input type="checkbox" class="custom-switch-input" name="ignore_invalid_upstream_ssl" value="1"<%- ignore_invalid_upstream_ssl ? ' checked' : '' %>>
76+
<span class="custom-switch-indicator"></span>
77+
<span class="custom-switch-description"><%- i18n('proxy-hosts', 'ignore-invalid-upstream-ssl') %></span>
78+
</label>
79+
</div>
80+
</div>
81+
6282
<div class="col-sm-12 col-md-12">
6383
<div class="form-group">
6484
<label class="form-label"><%- i18n('proxy-hosts', 'access-list') %></label>

src/frontend/js/app/nginx/proxy/form.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,20 @@ module.exports = Mn.View.extend({
2626
access_list_select: 'select[name="access_list_id"]',
2727
ssl_forced: 'input[name="ssl_forced"]',
2828
http2_support: 'input[name="http2_support"]',
29+
forward_scheme: 'select[name="forward_scheme"]',
30+
ignore_ssl: 'input[name="ignore_invalid_upstream_ssl"]',
2931
letsencrypt: '.letsencrypt'
3032
},
3133

3234
events: {
35+
'change @ui.forward_scheme': function () {
36+
let val = this.ui.forward_scheme.val();
37+
this.ui.ignore_ssl
38+
.prop('disabled', val === 'http')
39+
.parents('.form-group')
40+
.css('opacity', val === 'https' ? 1 : 0.5);
41+
},
42+
3343
'change @ui.certificate_select': function () {
3444
let id = this.ui.certificate_select.val();
3545
if (id === 'new') {
@@ -43,8 +53,6 @@ module.exports = Mn.View.extend({
4353
.prop('disabled', !enabled)
4454
.parents('.form-group')
4555
.css('opacity', enabled ? 1 : 0.5);
46-
47-
this.ui.http2_support.prop('disabled', !enabled);
4856
},
4957

5058
'click @ui.save': function (e) {
@@ -59,10 +67,11 @@ module.exports = Mn.View.extend({
5967
let data = this.ui.form.serializeJSON();
6068

6169
// Manipulate
62-
data.forward_port = parseInt(data.forward_port, 10);
63-
data.block_exploits = !!data.block_exploits;
64-
data.caching_enabled = !!data.caching_enabled;
65-
data.allow_websocket_upgrade = !!data.allow_websocket_upgrade;
70+
data.forward_port = parseInt(data.forward_port, 10);
71+
data.block_exploits = !!data.block_exploits;
72+
data.caching_enabled = !!data.caching_enabled;
73+
data.allow_websocket_upgrade = !!data.allow_websocket_upgrade;
74+
data.ignore_invalid_upstream_ssl = data.forward_scheme === 'https' ? !!data.ignore_invalid_upstream_ssl : false;
6675

6776
if (typeof data.ssl_forced !== 'undefined' && data.ssl_forced === '1') {
6877
data.ssl_forced = true;
@@ -92,7 +101,7 @@ module.exports = Mn.View.extend({
92101

93102
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1';
94103
} else {
95-
data.certificate_id = parseInt(data.certificate_id, 0);
104+
data.certificate_id = parseInt(data.certificate_id, 10);
96105
}
97106

98107
let method = App.Api.Nginx.ProxyHosts.create;
@@ -147,7 +156,6 @@ module.exports = Mn.View.extend({
147156
});
148157

149158
// Access Lists
150-
this.ui.letsencrypt.hide();
151159
this.ui.access_list_select.selectize({
152160
valueField: 'id',
153161
labelField: 'name',
@@ -207,6 +215,8 @@ module.exports = Mn.View.extend({
207215
view.ui.certificate_select[0].selectize.setValue(view.model.get('certificate_id'));
208216
}
209217
});
218+
219+
this.ui.forward_scheme.trigger('change');
210220
},
211221

212222
initialize: function (options) {

src/frontend/js/app/nginx/proxy/list/item.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</div>
2424
</td>
2525
<td>
26-
<div class="text-monospace"><%- forward_host %>:<%- forward_port %></div>
26+
<div class="text-monospace"><%- forward_scheme %>://<%- forward_host %>:<%- forward_port %></div>
2727
</td>
2828
<td>
2929
<div><%- certificate && certificate_id ? i18n('ssl', certificate.provider) : i18n('ssl', 'none') %></div>

src/frontend/js/app/nginx/redirection/form.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ module.exports = Mn.View.extend({
8686

8787
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree === '1';
8888
} else {
89-
data.certificate_id = parseInt(data.certificate_id, 0);
89+
data.certificate_id = parseInt(data.certificate_id, 10);
9090
}
9191

9292
let method = App.Api.Nginx.RedirectionHosts.create;

src/frontend/js/i18n/messages.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,16 @@
9393
"empty": "There are no Proxy Hosts",
9494
"add": "Add Proxy Host",
9595
"form-title": "{id, select, undefined{New} other{Edit}} Proxy Host",
96+
"forward-scheme": "Scheme",
9697
"forward-host": "Forward Hostname / IP",
9798
"forward-port": "Forward Port",
9899
"delete": "Delete Proxy Host",
99100
"delete-confirm": "Are you sure you want to delete the Proxy host for: <strong>{domains}</strong>?",
100101
"help-title": "What is a Proxy Host?",
101102
"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.",
102103
"access-list": "Access List",
103-
"allow-websocket-upgrade": "Allow Websocket HTTP Upgrades"
104+
"allow-websocket-upgrade": "Websockets Support",
105+
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL"
104106
},
105107
"redirection-hosts": {
106108
"title": "Redirection Hosts",

0 commit comments

Comments
 (0)