mirror of
https://github.com/jc21/nginx-proxy-manager.git
synced 2024-08-30 18:22:48 +00:00
WIP: complete control of new passthrough host type
This commit is contained in:
parent
5b1f0cead1
commit
5a2548c89d
@ -74,12 +74,10 @@ app.use(function (err, req, res, next) {
|
||||
}
|
||||
|
||||
// Not every error is worth logging - but this is good for now until it gets annoying.
|
||||
if (typeof err.stack !== 'undefined' && err.stack) {
|
||||
if (process.env.NODE_ENV === 'development' || process.env.DEBUG) {
|
||||
log.debug(err.stack);
|
||||
} else if (typeof err.public == 'undefined' || !err.public) {
|
||||
log.warn(err.message);
|
||||
}
|
||||
if (process.env.NODE_ENV === 'development' || process.env.DEBUG) {
|
||||
log.debug(err);
|
||||
} else if (typeof err.stack !== 'undefined' && err.stack && (typeof err.public == 'undefined' || !err.public)) {
|
||||
log.warn(err.message);
|
||||
}
|
||||
|
||||
res
|
||||
|
@ -206,14 +206,21 @@ const internalHost = {
|
||||
|
||||
if (existing_rows && existing_rows.length) {
|
||||
existing_rows.map(function (existing_row) {
|
||||
existing_row.domain_names.map(function (existing_hostname) {
|
||||
|
||||
function checkHostname(existing_hostname) {
|
||||
// Does this domain match?
|
||||
if (existing_hostname.toLowerCase() === hostname.toLowerCase()) {
|
||||
if (!ignore_id || ignore_id !== existing_row.id) {
|
||||
is_taken = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (existing_row.domain_names) {
|
||||
existing_row.domain_names.map(checkHostname);
|
||||
} else if (existing_row.domain_name) {
|
||||
checkHostname(existing_row.domain_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -236,8 +236,8 @@ const internalNginx = {
|
||||
host = {
|
||||
all_passthrough_hosts: allHosts.map((host) => {
|
||||
// Replace dots in domain
|
||||
host.escaped_name = host.domain_name.replace(/\./, '_');
|
||||
host.forwarding_host = internalNginx.addIpv6Brackets(host.forwarding_host);
|
||||
return host;
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
|
@ -19,20 +19,12 @@ const internalPassthroughHost = {
|
||||
create: (access, data) => {
|
||||
return access.can('ssl_passthrough_hosts:create', data)
|
||||
.then(() => {
|
||||
// Get a list of the domain names and check each of them against existing records
|
||||
let domain_name_check_promises = [];
|
||||
|
||||
data.domain_names.map(function (domain_name) {
|
||||
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
|
||||
});
|
||||
|
||||
return Promise.all(domain_name_check_promises)
|
||||
.then((check_results) => {
|
||||
check_results.map(function (result) {
|
||||
if (result.is_taken) {
|
||||
throw new error.ValidationError(result.hostname + ' is already in use');
|
||||
}
|
||||
});
|
||||
// Get the domain name and check it against existing records
|
||||
return internalHost.isHostnameTaken(data.domain_name)
|
||||
.then((result) => {
|
||||
if (result.is_taken) {
|
||||
throw new error.ValidationError(result.hostname + ' is already in use');
|
||||
}
|
||||
});
|
||||
}).then((/*access_data*/) => {
|
||||
data.owner_user_id = access.token.getUserId(1);
|
||||
@ -57,7 +49,7 @@ const internalPassthroughHost = {
|
||||
// Add to audit log
|
||||
return internalAuditLog.add(access, {
|
||||
action: 'created',
|
||||
object_type: 'ssl_passthrough_host',
|
||||
object_type: 'ssl-passthrough-host',
|
||||
object_id: row.id,
|
||||
meta: data
|
||||
})
|
||||
@ -76,21 +68,13 @@ const internalPassthroughHost = {
|
||||
update: (access, data) => {
|
||||
return access.can('ssl_passthrough_hosts:update', data.id)
|
||||
.then((/*access_data*/) => {
|
||||
// Get a list of the domain names and check each of them against existing records
|
||||
let domain_name_check_promises = [];
|
||||
|
||||
if (typeof data.domain_names !== 'undefined') {
|
||||
data.domain_names.map(function (domain_name) {
|
||||
domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'ssl_passthrough', data.id));
|
||||
});
|
||||
|
||||
return Promise.all(domain_name_check_promises)
|
||||
.then((check_results) => {
|
||||
check_results.map(function (result) {
|
||||
if (result.is_taken) {
|
||||
throw new error.ValidationError(result.hostname + ' is already in use');
|
||||
}
|
||||
});
|
||||
// Get the domain name and check it against existing records
|
||||
if (typeof data.domain_name !== 'undefined') {
|
||||
return internalHost.isHostnameTaken(data.domain_name, 'ssl_passthrough', data.id)
|
||||
.then((result) => {
|
||||
if (result.is_taken) {
|
||||
throw new error.ValidationError(result.hostname + ' is already in use');
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then((/*access_data*/) => {
|
||||
@ -116,7 +100,7 @@ const internalPassthroughHost = {
|
||||
// Add to audit log
|
||||
return internalAuditLog.add(access, {
|
||||
action: 'updated',
|
||||
object_type: 'ssl_passthrough_host',
|
||||
object_type: 'ssl-passthrough-host',
|
||||
object_id: row.id,
|
||||
meta: data
|
||||
})
|
||||
@ -207,7 +191,7 @@ const internalPassthroughHost = {
|
||||
// Add to audit log
|
||||
return internalAuditLog.add(access, {
|
||||
action: 'deleted',
|
||||
object_type: 'ssl_passthrough_host',
|
||||
object_type: 'ssl-passthrough-host',
|
||||
object_id: row.id,
|
||||
meta: _.omit(row, omissions())
|
||||
});
|
||||
@ -256,7 +240,7 @@ const internalPassthroughHost = {
|
||||
// Add to audit log
|
||||
return internalAuditLog.add(access, {
|
||||
action: 'enabled',
|
||||
object_type: 'ssl_passthrough_host',
|
||||
object_type: 'ssl-passthrough-host',
|
||||
object_id: row.id,
|
||||
meta: _.omit(row, omissions())
|
||||
});
|
||||
@ -305,7 +289,7 @@ const internalPassthroughHost = {
|
||||
// Add to audit log
|
||||
return internalAuditLog.add(access, {
|
||||
action: 'disabled',
|
||||
object_type: 'ssl_passthrough_host',
|
||||
object_type: 'ssl-passthrough-host',
|
||||
object_id: row.id,
|
||||
meta: _.omit(row, omissions())
|
||||
});
|
||||
|
@ -20,13 +20,30 @@ exports.up = function (knex/*, Promise*/) {
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.string('domain_name').notNull();
|
||||
table.string('forward_ip').notNull();
|
||||
table.string('forwarding_host').notNull();
|
||||
table.integer('forwarding_port').notNull().unsigned();
|
||||
table.integer('enabled').notNull().unsigned().defaultTo(1);
|
||||
table.json('meta').notNull();
|
||||
}).then(() => {
|
||||
logger.info('[' + migrate_name + '] Table created');
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] Table created');
|
||||
});
|
||||
.then(() => {
|
||||
return knex.schema.table('user_permission', (table) => {
|
||||
table.string('ssl_passthrough_hosts').notNull();
|
||||
})
|
||||
.then(() => {
|
||||
return knex('user_permission').update('ssl_passthrough_hosts', knex.ref('streams'));
|
||||
})
|
||||
.then(() => {
|
||||
return knex.schema.alterTable('user_permission', (table) => {
|
||||
table.string('ssl_passthrough_hosts').notNullable().alter();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] permissions updated');
|
||||
});
|
||||
})
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -39,8 +56,12 @@ exports.up = function (knex/*, Promise*/) {
|
||||
exports.down = function (knex/*, Promise*/) {
|
||||
logger.info('[' + migrate_name + '] Migrating Down...');
|
||||
|
||||
return knex.schema.dropTable('stream')
|
||||
return knex.schema.dropTable('stream').then(() => {
|
||||
return knex.schema.table('user_permission', (table) => {
|
||||
table.dropColumn('ssl_passthrough_hosts');
|
||||
})
|
||||
})
|
||||
.then(function () {
|
||||
logger.info('[' + migrate_name + '] Table altered');
|
||||
logger.info('[' + migrate_name + '] Table altered and permissions updated');
|
||||
});
|
||||
};
|
||||
|
@ -73,7 +73,7 @@ router
|
||||
* /api/nginx/ssl-passthrough-hosts/123
|
||||
*/
|
||||
router
|
||||
.route('/:ssl_passthrough_host_id')
|
||||
.route('/:host_id')
|
||||
.options((req, res) => {
|
||||
res.sendStatus(204);
|
||||
})
|
||||
@ -86,7 +86,7 @@ router
|
||||
*/
|
||||
.get((req, res, next) => {
|
||||
validator({
|
||||
required: ['ssl_passthrough_host_id'],
|
||||
required: ['host_id'],
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
host_id: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "endpoints/ssl-passthough-hosts",
|
||||
"$id": "endpoints/ssl-passthrough-hosts",
|
||||
"title": "SSL Passthrough Hosts",
|
||||
"description": "Endpoints relating to SSL Passthrough Hosts",
|
||||
"stability": "stable",
|
||||
|
@ -107,14 +107,15 @@ const setupDefaultUser = () => {
|
||||
})
|
||||
.then(() => {
|
||||
return userPermissionModel.query().insert({
|
||||
user_id: user.id,
|
||||
visibility: 'all',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
access_lists: 'manage',
|
||||
certificates: 'manage',
|
||||
user_id: user.id,
|
||||
visibility: 'all',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
ssl_passthrough_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
access_lists: 'manage',
|
||||
certificates: 'manage',
|
||||
});
|
||||
});
|
||||
})
|
||||
@ -229,7 +230,7 @@ const setupLogrotation = () => {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const setupSslPassthrough = () => {
|
||||
return internalNginx.configure(passthroughHostModel, 'ssl_passthrough_host', {});
|
||||
return internalNginx.configure(passthroughHostModel, 'ssl_passthrough_host', {}).then(() => internalNginx.reload());
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
|
@ -4,16 +4,16 @@
|
||||
|
||||
map $ssl_preread_server_name $name {
|
||||
{% for host in all_passthrough_hosts %}
|
||||
{% if enabled %}
|
||||
{{ host.domain_name }} ssl_passthrough_{{ host.escaped_name }}
|
||||
{% if host.enabled %}
|
||||
{{ host.domain_name }} ssl_passthrough_{{ host.domain_name }};
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
default https_default_backend;
|
||||
}
|
||||
|
||||
{% for host in all_passthrough_hosts %}
|
||||
{% if enabled %}
|
||||
upstream ssl_passthrough_{{ host.escaped_name }} {
|
||||
{% if host.enabled %}
|
||||
upstream ssl_passthrough_{{ host.domain_name }} {
|
||||
server {{host.forwarding_host}}:{{host.forwarding_port}};
|
||||
}
|
||||
{% endif %}
|
||||
@ -34,6 +34,8 @@ server {
|
||||
proxy_pass $name;
|
||||
ssl_preread on;
|
||||
|
||||
error_log /data/logs/ssl-passthrough-hosts_error.log warn;
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_ssl_passthrough[.]conf;
|
||||
}
|
@ -23,7 +23,7 @@ services:
|
||||
DB_MYSQL_USER: "npm"
|
||||
DB_MYSQL_PASSWORD: "npm"
|
||||
DB_MYSQL_NAME: "npm"
|
||||
ENABLE_SSL_PASSTHROUGH: "true"
|
||||
# ENABLE_SSL_PASSTHROUGH: "true"
|
||||
# DB_SQLITE_FILE: "/data/database.sqlite"
|
||||
# DISABLE_IPV6: "true"
|
||||
volumes:
|
||||
@ -41,6 +41,8 @@ services:
|
||||
container_name: npm_db
|
||||
networks:
|
||||
- nginx_proxy_manager
|
||||
ports:
|
||||
- 33306:3306
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "npm"
|
||||
MYSQL_DATABASE: "npm"
|
||||
|
@ -516,6 +516,15 @@ module.exports = {
|
||||
},
|
||||
|
||||
SslPassthroughHosts: {
|
||||
/**
|
||||
* @param {Array} [expand]
|
||||
* @param {String} [query]
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getFeatureEnabled: function () {
|
||||
return fetch('get', 'ssl-passthrough-enabled');
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array} [expand]
|
||||
* @param {String} [query]
|
||||
|
@ -21,7 +21,7 @@
|
||||
<div class="col-sm-4 col-md-4">
|
||||
<div class="form-group">
|
||||
<label class="form-label"><%- i18n('ssl-passthrough-hosts', 'forwarding-port') %> <span class="form-required">*</span></label>
|
||||
<input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 80" value="<%- forwarding_port %>" required>
|
||||
<input name="forwarding_port" type="number" class="form-control text-monospace" placeholder="eg: 443" value="<%- forwarding_port %>" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,9 +14,7 @@ module.exports = Mn.View.extend({
|
||||
ui: {
|
||||
form: 'form',
|
||||
forwarding_host: 'input[name="forwarding_host"]',
|
||||
type_error: '.forward-type-error',
|
||||
buttons: '.modal-footer button',
|
||||
switches: '.custom-switch-input',
|
||||
cancel: 'button.cancel',
|
||||
save: 'button.save'
|
||||
},
|
||||
@ -38,7 +36,6 @@ module.exports = Mn.View.extend({
|
||||
let data = this.ui.form.serializeJSON();
|
||||
|
||||
// Manipulate
|
||||
data.incoming_port = parseInt(data.incoming_port, 10);
|
||||
data.forwarding_port = parseInt(data.forwarding_port, 10);
|
||||
|
||||
let method = App.Api.Nginx.SslPassthroughHosts.create;
|
||||
|
@ -10,6 +10,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body no-padding min-100">
|
||||
<div id="ssl-passthrough-disabled-info">
|
||||
Disabled
|
||||
</div>
|
||||
<div class="dimmer active">
|
||||
<div class="loader"></div>
|
||||
<div class="dimmer-content list-region">
|
||||
|
@ -11,10 +11,11 @@ module.exports = Mn.View.extend({
|
||||
template: template,
|
||||
|
||||
ui: {
|
||||
list_region: '.list-region',
|
||||
add: '.add-item',
|
||||
help: '.help',
|
||||
dimmer: '.dimmer'
|
||||
list_region: '.list-region',
|
||||
add: '.add-item',
|
||||
help: '.help',
|
||||
dimmer: '.dimmer',
|
||||
disabled_info: '#ssl-passthrough-disabled-info'
|
||||
},
|
||||
|
||||
regions: {
|
||||
@ -39,6 +40,16 @@ module.exports = Mn.View.extend({
|
||||
|
||||
onRender: function () {
|
||||
let view = this;
|
||||
view.ui.disabled_info.hide();
|
||||
|
||||
App.Api.Nginx.SslPassthroughHosts.getFeatureEnabled().then((response) => {
|
||||
console.debug(response)
|
||||
if (response.ssl_passthrough_enabled === false) {
|
||||
view.ui.disabled_info.show();
|
||||
} else {
|
||||
view.ui.disabled_info.hide();
|
||||
}
|
||||
});
|
||||
|
||||
App.Api.Nginx.SslPassthroughHosts.getAll(['owner'])
|
||||
.then(response => {
|
||||
@ -53,7 +64,7 @@ module.exports = Mn.View.extend({
|
||||
view.showChildView('list_region', new EmptyView({
|
||||
title: App.i18n('ssl-passthrough-hosts', 'empty'),
|
||||
subtitle: App.i18n('all-hosts', 'empty-subtitle', {manage: manage}),
|
||||
link: manage ? App.i18n('ssl_passthrough_hosts', 'add') : null,
|
||||
link: manage ? App.i18n('ssl-passthrough-hosts', 'add') : null,
|
||||
btn_color: 'blue',
|
||||
permission: 'ssl-passthrough-hosts',
|
||||
action: function () {
|
||||
|
@ -20,6 +20,10 @@
|
||||
<a href="/nginx/stream" class="dropdown-item "><%- i18n('streams', 'title') %></a>
|
||||
<% } %>
|
||||
|
||||
<% if (canShow('ssl_passthrough_hosts')) { %>
|
||||
<a href="/nginx/ssl-passthrough" class="dropdown-item "><%- i18n('ssl-passthrough-hosts', 'title') %></a>
|
||||
<% } %>
|
||||
|
||||
<% if (canShow('dead_hosts')) { %>
|
||||
<a href="/nginx/404" class="dropdown-item "><%- i18n('dead-hosts', 'title') %></a>
|
||||
<% } %>
|
||||
|
@ -31,9 +31,9 @@
|
||||
</div>
|
||||
|
||||
<%
|
||||
var list = ['proxy-hosts', 'redirection-hosts', 'dead-hosts', 'streams', 'access-lists', 'certificates'];
|
||||
var list = ['proxy-hosts', 'redirection-hosts', 'dead-hosts', 'streams', 'ssl-passthrough-hosts', 'access-lists', 'certificates'];
|
||||
list.map(function(item) {
|
||||
var perm = item.replace('-', '_');
|
||||
var perm = item.replace(/-/g, '_');
|
||||
%>
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
|
@ -29,12 +29,13 @@ module.exports = Mn.View.extend({
|
||||
if (view.model.isAdmin()) {
|
||||
// Force some attributes for admin
|
||||
data = _.assign({}, data, {
|
||||
access_lists: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
certificates: 'manage'
|
||||
access_lists: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
ssl_passthrough_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
certificates: 'manage'
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,7 @@
|
||||
"enable-ssl": "Enable SSL",
|
||||
"force-ssl": "Force SSL",
|
||||
"http2-support": "HTTP/2 Support",
|
||||
"domain-name": "Domain Name",
|
||||
"domain-names": "Domain Names",
|
||||
"cert-provider": "Certificate Provider",
|
||||
"block-exploits": "Block Common Exploits",
|
||||
@ -125,8 +126,8 @@
|
||||
"forwarding-port": "Forward Port",
|
||||
"delete": "Delete SSL Passthrough Host",
|
||||
"delete-confirm": "Are you sure you want to delete this SSL Passthrough Host?",
|
||||
"help-title": "What is a SSL Passthrough Host?",
|
||||
"help-content": "An SSL Passthrough Host will allow you to proxy a server without SSL termination. This means the SSL encryption of the server will be passed right through the proxy, retaining the upstream certificates.\nThough this also means the proxy does not know anything about the traffic, and it just relies on an SSL feature called Server Name Indication, to know where to send this packet. This also means, if the client does not provide this additional information, accessing the site through the proxy won't be possible. However most modern browsers include this information in HTTP requests.\n\nHowever using SSL Passthrough comes with a performance penalty, since all hosts (including normal proxy hosts) now have to pass through this additional step of checking the destination. If you do not need your service to be available on port 443, it is recommended to use a stream host instead."
|
||||
"help-title": "What is an SSL Passthrough Host?",
|
||||
"help-content": "An SSL Passthrough Host will allow you to proxy a server without SSL termination. This means the SSL encryption of the server will be passed right through the proxy, retaining the upstream certificate.\n Because of the SSL encryption the proxy does not know anything about the traffic, and it just relies on an SSL feature called Server Name Indication to know where to send this packet. This also means if the client does not provide this additional information, accessing the site through the proxy won't be possible. But most modern browsers include this information in HTTP requests.\n\nDue to nginx constraints using SSL Passthrough comes with a performance penalty for other hosts, since all hosts (including normal proxy hosts) now have to pass through this additional step and basically being proxied twice. If you want to retain the upstream SSL certificate but do not need your service to be available on port 443, it is recommended to use a stream host instead."
|
||||
},
|
||||
"proxy-hosts": {
|
||||
"title": "Proxy Hosts",
|
||||
|
Loading…
Reference in New Issue
Block a user