Finished importer, advanced nginx config for hosts, custom certs used in nginx templates

This commit is contained in:
Jamie Curnow 2018-08-22 14:31:03 +10:00
parent d092d4bbe7
commit c543a1dc34
20 changed files with 174 additions and 72 deletions

View File

@ -2,14 +2,12 @@
In order of importance, somewhat..
- v1 Importer
- ssl certificates
- nginx advanced config
- Redirection host preserve path nginx configuration
- Custom ssl certificate saving to disk and usage in nginx configs
- Nginx config output:
- Redirection host preserve path nginx configuration
- Dashboard stats are caching instead of querying
- UI Log tail
- Custom Nginx Config Editor
- Enable/Disable a config
Testing:

View File

@ -3,6 +3,7 @@
mkdir -p /tmp/nginx/body \
/var/log/nginx \
/data/nginx \
/data/custom_ssl \
/data/logs \
/data/access \
/data/nginx/proxy_host \

View File

@ -186,8 +186,6 @@ module.exports = function () {
// 2. rename archive folder name
new_archive_path = new_archive_path + 'npm-' + certificate.id;
//logger.debug('Renaming archive folder:', full_archive_path, '->', new_archive_path);
fs.renameSync(full_archive_path, new_archive_path);
return certificate;
@ -195,9 +193,6 @@ module.exports = function () {
.then(certificate => {
// 3. rename live folder name
new_live_path = new_live_path + 'npm-' + certificate.id;
//logger.debug('Renaming live folder:', full_live_path, '->', new_live_path);
fs.renameSync(full_live_path, new_live_path);
// and also update the symlinks in this folder:
@ -211,8 +206,6 @@ module.exports = function () {
];
names.map(function (name) {
//logger.debug('Live Link:', name);
// remove symlink
try {
fs.unlinkSync(new_live_path + '/' + name[0]);
@ -221,7 +214,6 @@ module.exports = function () {
logger.error(err);
}
//logger.debug('Creating Link:', '../../archive/npm-' + certificate.id + '/' + name[1]);
// create new symlink
fs.symlinkSync('../../archive/npm-' + certificate.id + '/' + name[1], name[0]);
});
@ -356,8 +348,6 @@ module.exports = function () {
certificate_id = certificate_map[host.hostname];
}
// TODO: Advanced nginx config
return proxyHostModel
.query()
.insertAndFetch({
@ -370,6 +360,7 @@ module.exports = function () {
ssl_forced: host.force_ssl || false,
caching_enabled: host.asset_caching || false,
block_exploits: host.block_exploits || false,
advanced_config: host.advanced || '',
meta: meta
})
.then(row => {
@ -405,16 +396,15 @@ module.exports = function () {
certificate_id = certificate_map[host.hostname];
}
// TODO: Advanced nginx config
return deadHostModel
.query()
.insertAndFetch({
owner_user_id: 1,
domain_names: [host.hostname],
certificate_id: certificate_id,
ssl_forced: host.force_ssl || false,
meta: meta
owner_user_id: 1,
domain_names: [host.hostname],
certificate_id: certificate_id,
ssl_forced: host.force_ssl || false,
advanced_config: host.advanced || '',
meta: meta
})
.then(row => {
// re-fetch with cert
@ -449,8 +439,6 @@ module.exports = function () {
certificate_id = certificate_map[host.hostname];
}
// TODO: Advanced nginx config
return redirectionHostModel
.query()
.insertAndFetch({
@ -460,6 +448,7 @@ module.exports = function () {
block_exploits: host.block_exploits || false,
certificate_id: certificate_id,
ssl_forced: host.force_ssl || false,
advanced_config: host.advanced || '',
meta: meta
})
.then(row => {
@ -483,8 +472,6 @@ module.exports = function () {
const importStream = function (access, host) {
logger.info('Creating Stream: ' + host.incoming_port);
// TODO: Advanced nginx config
return streamModel
.query()
.insertAndFetch({
@ -537,7 +524,7 @@ module.exports = function () {
})
.then(() => {
// Write the /config/v2-imported file so we don't import again
fs.writeFile('/config/v2-imported', 'true', function(err) {
fs.writeFile('/config/v2-imported', 'true', function (err) {
if (err) {
logger.err(err);
}

View File

@ -183,7 +183,10 @@ const internalCertificate = {
});
});
} else {
return certificate;
return internalCertificate.writeCustomCert(certificate)
.then(() => {
return certificate;
});
}
}).then(certificate => {
@ -401,6 +404,54 @@ const internalCertificate = {
});
},
/**
* @param {Object} certificate
* @returns {Promise}
*/
writeCustomCert: certificate => {
return new Promise((resolve, reject) => {
let dir = '/data/custom_ssl/npm-' + certificate.id;
if (certificate.provider === 'letsencrypt') {
reject(new Error('Refusing to write letsencrypt certs here'));
return;
}
let cert_data = certificate.meta.certificate;
if (typeof certificate.meta.intermediate_certificate !== 'undefined') {
cert_data = cert_data + "\n" + certificate.meta.intermediate_certificate;
}
try {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
} catch (err) {
reject(err);
return;
}
fs.writeFile(dir + '/fullchain.pem', cert_data, function (err) {
if (err) {
reject(err);
} else {
resolve();
}
});
})
.then(() => {
return new Promise((resolve, reject) => {
fs.writeFile(dir + '/privkey.pem', certificate.meta.certificate_key, function (err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
});
},
/**
* @param {Access} access
* @param {Object} data

View File

@ -76,6 +76,7 @@ exports.up = function (knex/*, Promise*/) {
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.integer('caching_enabled').notNull().unsigned().defaultTo(0);
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull().defaultTo('{}');
});
})
@ -94,6 +95,7 @@ exports.up = function (knex/*, Promise*/) {
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull().defaultTo('{}');
});
})
@ -109,6 +111,7 @@ exports.up = function (knex/*, Promise*/) {
table.json('domain_names').notNull();
table.integer('certificate_id').notNull().unsigned().defaultTo(0);
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
table.text('advanced_config').notNull().defaultTo('');
table.json('meta').notNull().defaultTo('{}');
});
})

View File

@ -24,18 +24,11 @@
"ssl_forced": {
"$ref": "../definitions.json#/definitions/ssl_forced"
},
"advanced_config": {
"type": "string"
},
"meta": {
"type": "object",
"additionalProperties": false,
"properties": {
"letsencrypt_email": {
"type": "string",
"format": "email"
},
"letsencrypt_agree": {
"type": "boolean"
}
}
"type": "object"
}
},
"properties": {
@ -57,6 +50,9 @@
"ssl_forced": {
"$ref": "#/definitions/ssl_forced"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -105,6 +101,9 @@
"ssl_forced": {
"$ref": "#/definitions/ssl_forced"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -139,6 +138,9 @@
"ssl_forced": {
"$ref": "#/definitions/ssl_forced"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}

View File

@ -42,6 +42,9 @@
"access_list_id": {
"$ref": "../definitions.json#/definitions/access_list_id"
},
"advanced_config": {
"type": "string"
},
"meta": {
"type": "object"
}
@ -80,6 +83,9 @@
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -145,6 +151,9 @@
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -194,6 +203,9 @@
"access_list_id": {
"$ref": "#/definitions/access_list_id"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}

View File

@ -35,18 +35,11 @@
"block_exploits": {
"$ref": "../definitions.json#/definitions/block_exploits"
},
"advanced_config": {
"type": "string"
},
"meta": {
"type": "object",
"additionalProperties": false,
"properties": {
"letsencrypt_email": {
"type": "string",
"format": "email"
},
"letsencrypt_agree": {
"type": "boolean"
}
}
"type": "object"
}
},
"properties": {
@ -77,6 +70,9 @@
"block_exploits": {
"$ref": "#/definitions/block_exploits"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -135,6 +131,9 @@
"block_exploits": {
"$ref": "#/definitions/block_exploits"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}
@ -178,6 +177,9 @@
"block_exploits": {
"$ref": "#/definitions/block_exploits"
},
"advanced_config": {
"$ref": "#/definitions/advanced_config"
},
"meta": {
"$ref": "#/definitions/meta"
}

View File

@ -6,5 +6,6 @@
ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
{% endif %}
# TODO: Custom SSL paths
{% endif %}
ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem;
ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem;
{% endif %}

View File

@ -6,7 +6,7 @@ server {
access_log /data/logs/dead_host-{{ id }}.log proxy;
# TODO: Advanced config options
{{ advanced_config }}
return 404;
}

View File

@ -11,7 +11,7 @@ server {
access_log /data/logs/proxy_host-{{ id }}.log proxy;
# TODO: Advanced config options
{{ advanced_config }}
location / {
{%- if access_list_id > 0 -%}

View File

@ -8,7 +8,7 @@ server {
access_log /data/logs/redirection_host-{{ id }}.log proxy;
# TODO: Advanced config options
{{ advanced_config }}
# TODO: Preserve Path Option

View File

@ -8,6 +8,7 @@
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
<li role="presentation" class="nav-item"><a href="#advanced" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('all-hosts', 'advanced') %></a></li>
</ul>
<div class="tab-content">
<!-- Details -->
@ -63,9 +64,19 @@
</div>
</div>
</div>
<!-- Advanced -->
<div role="tabpanel" class="tab-pane" id="advanced">
<div class="row">
<div class="col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('all-hosts', 'advanced-config') %></label>
<textarea name="advanced_config" rows="8" class="form-control text-monospace" placeholder="# <%- i18n('all-hosts', 'advanced-warning') %>"><%- advanced_config %></textarea>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">

View File

@ -8,12 +8,12 @@
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
<li role="presentation" class="nav-item"><a href="#advanced" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('all-hosts', 'advanced') %></a></li>
</ul>
<div class="tab-content">
<!-- Details -->
<div role="tabpanel" class="tab-pane active" id="details">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label class="form-label"><%- i18n('all-hosts', 'domain-names') %> <span class="form-required">*</span></label>
@ -101,9 +101,19 @@
</div>
</div>
</div>
<!-- Advanced -->
<div role="tabpanel" class="tab-pane" id="advanced">
<div class="row">
<div class="col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('all-hosts', 'advanced-config') %></label>
<textarea name="advanced_config" rows="8" class="form-control text-monospace" placeholder="# <%- i18n('all-hosts', 'advanced-warning') %>"><%- advanced_config %></textarea>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">

View File

@ -8,6 +8,7 @@
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="nav-item"><a href="#details" aria-controls="tab1" role="tab" data-toggle="tab" class="nav-link active"><i class="fe fe-zap"></i> <%- i18n('all-hosts', 'details') %></a></li>
<li role="presentation" class="nav-item"><a href="#ssl-options" aria-controls="tab2" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-shield"></i> <%- i18n('str', 'ssl') %></a></li>
<li role="presentation" class="nav-item"><a href="#advanced" aria-controls="tab3" role="tab" data-toggle="tab" class="nav-link"><i class="fe fe-settings"></i> <%- i18n('all-hosts', 'advanced') %></a></li>
</ul>
<div class="tab-content">
<!-- Details -->
@ -87,9 +88,19 @@
</div>
</div>
</div>
<!-- Advanced -->
<div role="tabpanel" class="tab-pane" id="advanced">
<div class="row">
<div class="col-md-12">
<div class="form-group mb-0">
<label class="form-label"><%- i18n('all-hosts', 'advanced-config') %></label>
<textarea name="advanced_config" rows="8" class="form-control text-monospace" placeholder="# <%- i18n('all-hosts', 'advanced-warning') %>"><%- advanced_config %></textarea>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">

View File

@ -73,7 +73,10 @@
"none": "None",
"new-cert": "Request a new SSL Certificate",
"with-le": "with Let's Encrypt",
"no-ssl": "This host will not use HTTPS"
"no-ssl": "This host will not use HTTPS",
"advanced": "Advanced",
"advanced-warning": "Enter your custom Nginx configuration here at your own risk!",
"advanced-config": "Custom Nginx Configuration"
},
"ssl": {
"letsencrypt": "Let's Encrypt",

View File

@ -7,16 +7,17 @@ const model = Backbone.Model.extend({
defaults: function () {
return {
id: undefined,
created_on: null,
modified_on: null,
domain_names: [],
certificate_id: 0,
ssl_forced: false,
meta: {},
id: undefined,
created_on: null,
modified_on: null,
domain_names: [],
certificate_id: 0,
ssl_forced: false,
meta: {},
advanced_config: '',
// The following are expansions:
owner: null,
certificate: null
owner: null,
certificate: null
};
}
});

View File

@ -18,6 +18,7 @@ const model = Backbone.Model.extend({
ssl_forced: false,
caching_enabled: false,
block_exploits: false,
advanced_config: '',
meta: {},
// The following are expansions:
owner: null,

View File

@ -16,6 +16,7 @@ const model = Backbone.Model.extend({
certificate_id: 0,
ssl_forced: false,
block_exploits: false,
advanced_config: '',
meta: {},
// The following are expansions:
owner: null,

View File

@ -116,3 +116,10 @@ $pink: #f66d9b;
margin: 1.75rem auto;
}
}
/* Form mod */
textarea.form-control.text-monospace {
font-size: 12px;
}