From 29bebcc73eba4c3bef76e7f4cab6d516adb40cdd Mon Sep 17 00:00:00 2001 From: jc21 Date: Mon, 25 Feb 2019 10:34:55 +1000 Subject: [PATCH 01/22] Ignore default location when defined in advanced config (#79) --- src/backend/internal/nginx.js | 19 ++++++++++++++++--- src/backend/templates/dead_host.conf | 3 +++ src/backend/templates/proxy_host.conf | 3 +++ src/backend/templates/redirection_host.conf | 3 +++ src/frontend/js/app/nginx/proxy/form.ejs | 6 ++++++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/backend/internal/nginx.js b/src/backend/internal/nginx.js index a0d84998..fd8fe165 100644 --- a/src/backend/internal/nginx.js +++ b/src/backend/internal/nginx.js @@ -1,5 +1,3 @@ -'use strict'; - const _ = require('lodash'); const fs = require('fs'); const Liquid = require('liquidjs'); @@ -92,7 +90,7 @@ const internalNginx = { }) .then(() => { return combined_meta; - }) + }); }, /** @@ -146,6 +144,7 @@ const internalNginx = { return new Promise((resolve, reject) => { let template = null; let filename = internalNginx.getConfigName(host_type, host.id); + try { template = fs.readFileSync(__dirname + '/../templates/' + host_type + '.conf', {encoding: 'utf8'}); } catch (err) { @@ -153,6 +152,12 @@ const internalNginx = { return; } + // Manipulate the data a bit before sending it to the template + host.use_default_location = true; + if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { + host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); + } + renderEngine .parseAndRender(template, host) .then(config_text => { @@ -312,6 +317,14 @@ const internalNginx = { }); return Promise.all(promises); + }, + + /** + * @param {string} config + * @returns {boolean} + */ + advancedConfigHasDefaultLocation: function (config) { + return !!config.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im); } }; diff --git a/src/backend/templates/dead_host.conf b/src/backend/templates/dead_host.conf index 8d3534ab..da282a12 100644 --- a/src/backend/templates/dead_host.conf +++ b/src/backend/templates/dead_host.conf @@ -10,10 +10,13 @@ server { {{ advanced_config }} +{% if use_default_location %} location / { {% include "_forced_ssl.conf" %} {% include "_hsts.conf" %} return 404; } +{% endif %} + } {% endif %} diff --git a/src/backend/templates/proxy_host.conf b/src/backend/templates/proxy_host.conf index 52e70583..95f850a9 100644 --- a/src/backend/templates/proxy_host.conf +++ b/src/backend/templates/proxy_host.conf @@ -16,6 +16,7 @@ server { {{ advanced_config }} +{% if use_default_location %} location / { {%- if access_list_id > 0 -%} # Access List @@ -35,5 +36,7 @@ server { # Proxy! include conf.d/include/proxy.conf; } +{% endif %} + } {% endif %} diff --git a/src/backend/templates/redirection_host.conf b/src/backend/templates/redirection_host.conf index 7f55e91b..3e6c2b44 100644 --- a/src/backend/templates/redirection_host.conf +++ b/src/backend/templates/redirection_host.conf @@ -12,6 +12,7 @@ server { {{ advanced_config }} +{% if use_default_location %} location / { {% include "_forced_ssl.conf" %} {% include "_hsts.conf" %} @@ -22,5 +23,7 @@ server { return 301 $scheme://{{ forward_domain_name }}; {% endif %} } +{% endif %} + } {% endif %} diff --git a/src/frontend/js/app/nginx/proxy/form.ejs b/src/frontend/js/app/nginx/proxy/form.ejs index 0962916f..ef9b95b4 100644 --- a/src/frontend/js/app/nginx/proxy/form.ejs +++ b/src/frontend/js/app/nginx/proxy/form.ejs @@ -152,6 +152,12 @@
+

Nginx variables available to you are:

+
    +
  • $server # Host/IP
  • +
  • $port # Port Number
  • +
  • $forward_scheme # http or https
  • +
From e7379e36831b80e1b589b45001b25f3ec12faab6 Mon Sep 17 00:00:00 2001 From: jc21 Date: Mon, 25 Feb 2019 10:42:16 +1000 Subject: [PATCH 02/22] Ignore default location when defined in advanced config (#79) From 418899d4256dfdde46dea1d375fd327db3c31845 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Wed, 27 Feb 2019 17:52:30 +1000 Subject: [PATCH 03/22] Version bump --- README.md | 2 +- doc/DOCKERHUB.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 38d3c664..d417ff2a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.9-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.10-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) diff --git a/doc/DOCKERHUB.md b/doc/DOCKERHUB.md index b7f017ca..911a0837 100644 --- a/doc/DOCKERHUB.md +++ b/doc/DOCKERHUB.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.9-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.10-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) diff --git a/package.json b/package.json index 3db398eb..5b0533a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nginx-proxy-manager", - "version": "2.0.9", + "version": "2.0.10", "description": "A beautiful interface for creating Nginx endpoints", "main": "src/backend/index.js", "devDependencies": { From 5a9a716ca6f99aed02bbd4ba4da8528758d08428 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 1 Mar 2019 20:12:49 +1000 Subject: [PATCH 04/22] CI: Prevent having to spin up resources when not Master branch --- Jenkinsfile | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c31f7e01..d4e0da0c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -81,11 +81,11 @@ pipeline { } } stage('Build Master') { + when { + branch 'master' + } parallel { stage('x86_64') { - when { - branch 'master' - } steps { ansiColor('xterm') { // Codebase @@ -127,9 +127,6 @@ pipeline { } } stage('armhf') { - when { - branch 'master' - } agent { label 'armhf' } @@ -173,9 +170,6 @@ pipeline { } } stage('arm64') { - when { - branch 'master' - } agent { label 'arm64' } From 0acec1105bb2c29e1e03a81cfb05a6426b3e2a20 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 1 Mar 2019 20:12:49 +1000 Subject: [PATCH 05/22] CI: Prevent having to spin up resources when not Master branch --- Jenkinsfile | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c31f7e01..d76d275e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -81,11 +81,11 @@ pipeline { } } stage('Build Master') { + when { + branch: 'master' + } parallel { stage('x86_64') { - when { - branch 'master' - } steps { ansiColor('xterm') { // Codebase @@ -127,9 +127,6 @@ pipeline { } } stage('armhf') { - when { - branch 'master' - } agent { label 'armhf' } @@ -173,9 +170,6 @@ pipeline { } } stage('arm64') { - when { - branch 'master' - } agent { label 'arm64' } From aad9ecde6bf7be183fe598b10d7cb50569ca914e Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 1 Mar 2019 20:12:49 +1000 Subject: [PATCH 06/22] CI: Prevent having to spin up resources when not Master branch --- Jenkinsfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index abd3db30..d4e0da0c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -82,11 +82,7 @@ pipeline { } stage('Build Master') { when { -<<<<<<< HEAD branch 'master' -======= - branch: 'master' ->>>>>>> 0acec1105bb2c29e1e03a81cfb05a6426b3e2a20 } parallel { stage('x86_64') { From 6f1d38a0e2c27cbb117782503abea133e20be806 Mon Sep 17 00:00:00 2001 From: jc21 Date: Mon, 4 Mar 2019 10:16:46 +1000 Subject: [PATCH 07/22] Fixes #88 - Allow specifying X-FRAME-OPTIONS with an environment variable (#89) --- doc/INSTALL.md | 20 ++++++++++++++++++++ src/backend/app.js | 8 +++++++- src/backend/index.js | 2 -- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/INSTALL.md b/doc/INSTALL.md index b7e16056..3b06e410 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -143,3 +143,23 @@ Password: changeme ``` Immediately after logging in with this default user you will be asked to modify your details and change your password. + + +### Advanced Options + +#### X-FRAME-OPTIONS Header + +You can configure the [`X-FRAME-OPTIONS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) header +value by specifying it as a Docker environment variable. The default if not specified is `deny`. + +```yml + ... + environment: + X_FRAME_OPTIONS: "sameorigin" + ... +``` + +``` +... -e "X_FRAME_OPTIONS=sameorigin" ... +``` + diff --git a/src/backend/app.js b/src/backend/app.js index e433013a..59802755 100644 --- a/src/backend/app.js +++ b/src/backend/app.js @@ -40,11 +40,17 @@ app.use(require('./lib/express/cors')); // General security/cache related headers + server header app.use(function (req, res, next) { + let x_frame_options = 'DENY'; + + if (typeof process.env.X_FRAME_OPTIONS !== 'undefined' && process.env.X_FRAME_OPTIONS) { + x_frame_options = process.env.X_FRAME_OPTIONS; + } + res.set({ 'Strict-Transport-Security': 'includeSubDomains; max-age=631138519; preload', 'X-XSS-Protection': '0', 'X-Content-Type-Options': 'nosniff', - 'X-Frame-Options': 'DENY', + 'X-Frame-Options': x_frame_options, 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', Pragma: 'no-cache', Expires: 0 diff --git a/src/backend/index.js b/src/backend/index.js index cd0a7818..d97450e4 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -1,7 +1,5 @@ #!/usr/bin/env node -'use strict'; - const logger = require('./logger').global; function appStart () { From 133d66c2fe77f6a96a401c01865cedd2cbcc4ec1 Mon Sep 17 00:00:00 2001 From: jc21 Date: Mon, 4 Mar 2019 21:19:36 +1000 Subject: [PATCH 08/22] Default Site customisation and new Settings space (#91) --- rootfs/etc/nginx/conf.d/default.conf | 10 +- rootfs/etc/nginx/nginx.conf | 1 + rootfs/etc/services.d/nginx/run | 2 + src/backend/internal/nginx.js | 23 +-- src/backend/internal/proxy-host.js | 2 +- src/backend/internal/setting.js | 133 ++++++++++++++++++ src/backend/lib/access/settings-get.json | 7 + src/backend/lib/access/settings-list.json | 7 + src/backend/lib/access/settings-update.json | 7 + .../migrations/20190227065017_settings.js | 54 +++++++ src/backend/models/setting.js | 30 ++++ src/backend/routes/api/main.js | 1 + src/backend/routes/api/settings.js | 96 +++++++++++++ src/backend/schema/definitions.json | 7 + src/backend/schema/endpoints/settings.json | 99 +++++++++++++ src/backend/schema/index.json | 3 + src/backend/templates/default.conf | 32 +++++ src/frontend/js/app/api.js | 29 ++++ src/frontend/js/app/controller.js | 30 ++++ src/frontend/js/app/router.js | 1 + .../js/app/settings/default-site/main.ejs | 77 ++++++++++ .../js/app/settings/default-site/main.js | 71 ++++++++++ src/frontend/js/app/settings/list/item.ejs | 21 +++ src/frontend/js/app/settings/list/item.js | 25 ++++ src/frontend/js/app/settings/list/main.ejs | 8 ++ src/frontend/js/app/settings/list/main.js | 29 ++++ src/frontend/js/app/settings/main.ejs | 14 ++ src/frontend/js/app/settings/main.js | 50 +++++++ src/frontend/js/app/ui/menu/main.ejs | 3 + src/frontend/js/i18n/messages.json | 11 +- src/frontend/js/models/setting.js | 25 ++++ 31 files changed, 893 insertions(+), 15 deletions(-) create mode 100644 src/backend/internal/setting.js create mode 100644 src/backend/lib/access/settings-get.json create mode 100644 src/backend/lib/access/settings-list.json create mode 100644 src/backend/lib/access/settings-update.json create mode 100644 src/backend/migrations/20190227065017_settings.js create mode 100644 src/backend/models/setting.js create mode 100644 src/backend/routes/api/settings.js create mode 100644 src/backend/schema/endpoints/settings.json create mode 100644 src/backend/templates/default.conf create mode 100644 src/frontend/js/app/settings/default-site/main.ejs create mode 100644 src/frontend/js/app/settings/default-site/main.js create mode 100644 src/frontend/js/app/settings/list/item.ejs create mode 100644 src/frontend/js/app/settings/list/item.js create mode 100644 src/frontend/js/app/settings/list/main.ejs create mode 100644 src/frontend/js/app/settings/list/main.js create mode 100644 src/frontend/js/app/settings/main.ejs create mode 100644 src/frontend/js/app/settings/main.js create mode 100644 src/frontend/js/models/setting.js diff --git a/rootfs/etc/nginx/conf.d/default.conf b/rootfs/etc/nginx/conf.d/default.conf index 490e2868..2530ec2e 100644 --- a/rootfs/etc/nginx/conf.d/default.conf +++ b/rootfs/etc/nginx/conf.d/default.conf @@ -22,10 +22,10 @@ server { } } -# Default 80 Host, which shows a "You are not configured" page +# "You are not configured" page, which is the default if another default doesn't exist server { - listen 80 default; - server_name localhost; + listen 80; + server_name localhost-nginx-proxy-manager; access_log /data/logs/default.log proxy; @@ -38,9 +38,9 @@ server { } } -# Default 443 Host +# First 443 Host, which is the default if another default doesn't exist server { - listen 443 ssl default; + listen 443 ssl; server_name localhost; access_log /data/logs/default.log proxy; diff --git a/rootfs/etc/nginx/nginx.conf b/rootfs/etc/nginx/nginx.conf index ad51c873..7d068736 100644 --- a/rootfs/etc/nginx/nginx.conf +++ b/rootfs/etc/nginx/nginx.conf @@ -70,6 +70,7 @@ http { # Files generated by NPM include /etc/nginx/conf.d/*.conf; + include /data/nginx/default_host/*.conf; include /data/nginx/proxy_host/*.conf; include /data/nginx/redirection_host/*.conf; include /data/nginx/dead_host/*.conf; diff --git a/rootfs/etc/services.d/nginx/run b/rootfs/etc/services.d/nginx/run index c7b6181e..f6b59fd6 100755 --- a/rootfs/etc/services.d/nginx/run +++ b/rootfs/etc/services.d/nginx/run @@ -7,6 +7,8 @@ mkdir -p /tmp/nginx/body \ /data/custom_ssl \ /data/logs \ /data/access \ + /data/nginx/default_host \ + /data/nginx/default_www \ /data/nginx/proxy_host \ /data/nginx/redirection_host \ /data/nginx/stream \ diff --git a/src/backend/internal/nginx.js b/src/backend/internal/nginx.js index fd8fe165..1e992992 100644 --- a/src/backend/internal/nginx.js +++ b/src/backend/internal/nginx.js @@ -17,9 +17,9 @@ const internalNginx = { * - IF BAD: update the meta with offline status and remove the config entirely * - then reload nginx * - * @param {Object} model - * @param {String} host_type - * @param {Object} host + * @param {Object|String} model + * @param {String} host_type + * @param {Object} host * @returns {Promise} */ configure: (model, host_type, host) => { @@ -122,6 +122,11 @@ const internalNginx = { */ getConfigName: (host_type, host_id) => { host_type = host_type.replace(new RegExp('-', 'g'), '_'); + + if (host_type === 'default') { + return '/data/nginx/default_host/site.conf'; + } + return '/data/nginx/' + host_type + '/' + host_id + '.conf'; }, @@ -153,9 +158,11 @@ const internalNginx = { } // Manipulate the data a bit before sending it to the template - host.use_default_location = true; - if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { - host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); + if (host_type !== 'default') { + host.use_default_location = true; + if (typeof host.advanced_config !== 'undefined' && host.advanced_config) { + host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config); + } } renderEngine @@ -260,7 +267,7 @@ const internalNginx = { /** * @param {String} host_type - * @param {Object} host + * @param {Object} [host] * @param {Boolean} [throw_errors] * @returns {Promise} */ @@ -269,7 +276,7 @@ const internalNginx = { return new Promise((resolve, reject) => { try { - let config_file = internalNginx.getConfigName(host_type, host.id); + let config_file = internalNginx.getConfigName(host_type, typeof host === 'undefined' ? 0 : host.id); if (debug_mode) { logger.warn('Deleting nginx config: ' + config_file); diff --git a/src/backend/internal/proxy-host.js b/src/backend/internal/proxy-host.js index 882d6ddd..9f1d9be8 100644 --- a/src/backend/internal/proxy-host.js +++ b/src/backend/internal/proxy-host.js @@ -108,7 +108,7 @@ const internalProxyHost = { */ update: (access, data) => { let create_certificate = data.certificate_id === 'new'; -console.log('PH UPDATE:', data); + if (create_certificate) { delete data.certificate_id; } diff --git a/src/backend/internal/setting.js b/src/backend/internal/setting.js new file mode 100644 index 00000000..eedb7d3b --- /dev/null +++ b/src/backend/internal/setting.js @@ -0,0 +1,133 @@ +const fs = require('fs'); +const error = require('../lib/error'); +const settingModel = require('../models/setting'); +const internalNginx = require('./nginx'); + +const internalSetting = { + + /** + * @param {Access} access + * @param {Object} data + * @param {String} data.id + * @return {Promise} + */ + update: (access, data) => { + return access.can('settings:update', data.id) + .then(access_data => { + return internalSetting.get(access, {id: data.id}); + }) + .then(row => { + if (row.id !== data.id) { + // Sanity check that something crazy hasn't happened + throw new error.InternalValidationError('Setting could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id); + } + + return settingModel + .query() + .where({id: data.id}) + .patch(data); + }) + .then(() => { + return internalSetting.get(access, { + id: data.id + }); + }) + .then(row => { + if (row.id === 'default-site') { + // write the html if we need to + if (row.value === 'html') { + fs.writeFileSync('/data/nginx/default_www/index.html', row.meta.html, {encoding: 'utf8'}); + } + + // Configure nginx + return internalNginx.deleteConfig('default') + .then(() => { + return internalNginx.generateConfig('default', row); + }) + .then(() => { + return internalNginx.test(); + }) + .then(() => { + return internalNginx.reload(); + }) + .then(() => { + return row; + }) + .catch((err) => { + internalNginx.deleteConfig('default') + .then(() => { + return internalNginx.test(); + }) + .then(() => { + return internalNginx.reload(); + }) + .then(() => { + // I'm being slack here I know.. + throw new error.ValidationError('Could not reconfigure Nginx. Please check logs.'); + }) + }); + } else { + return row; + } + }); + }, + + /** + * @param {Access} access + * @param {Object} data + * @param {String} data.id + * @return {Promise} + */ + get: (access, data) => { + return access.can('settings:get', data.id) + .then(() => { + return settingModel + .query() + .where('id', data.id) + .first(); + }) + .then(row => { + if (row) { + return row; + } else { + throw new error.ItemNotFoundError(data.id); + } + }); + }, + + /** + * This will only count the settings + * + * @param {Access} access + * @returns {*} + */ + getCount: (access) => { + return access.can('settings:list') + .then(() => { + return settingModel + .query() + .count('id as count') + .first(); + }) + .then(row => { + return parseInt(row.count, 10); + }); + }, + + /** + * All settings + * + * @param {Access} access + * @returns {Promise} + */ + getAll: (access) => { + return access.can('settings:list') + .then(() => { + return settingModel + .query() + .orderBy('description', 'ASC'); + }); + } +}; + +module.exports = internalSetting; diff --git a/src/backend/lib/access/settings-get.json b/src/backend/lib/access/settings-get.json new file mode 100644 index 00000000..d2709fd8 --- /dev/null +++ b/src/backend/lib/access/settings-get.json @@ -0,0 +1,7 @@ +{ + "anyOf": [ + { + "$ref": "roles#/definitions/admin" + } + ] +} diff --git a/src/backend/lib/access/settings-list.json b/src/backend/lib/access/settings-list.json new file mode 100644 index 00000000..d2709fd8 --- /dev/null +++ b/src/backend/lib/access/settings-list.json @@ -0,0 +1,7 @@ +{ + "anyOf": [ + { + "$ref": "roles#/definitions/admin" + } + ] +} diff --git a/src/backend/lib/access/settings-update.json b/src/backend/lib/access/settings-update.json new file mode 100644 index 00000000..d2709fd8 --- /dev/null +++ b/src/backend/lib/access/settings-update.json @@ -0,0 +1,7 @@ +{ + "anyOf": [ + { + "$ref": "roles#/definitions/admin" + } + ] +} diff --git a/src/backend/migrations/20190227065017_settings.js b/src/backend/migrations/20190227065017_settings.js new file mode 100644 index 00000000..6ba3653f --- /dev/null +++ b/src/backend/migrations/20190227065017_settings.js @@ -0,0 +1,54 @@ +const migrate_name = 'settings'; +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.createTable('setting', table => { + table.string('id').notNull().primary(); + table.string('name', 100).notNull(); + table.string('description', 255).notNull(); + table.string('value', 255).notNull(); + table.json('meta').notNull(); + }) + .then(() => { + logger.info('[' + migrate_name + '] setting Table created'); + + // TODO: add settings + let settingModel = require('../models/setting'); + + return settingModel + .query() + .insert({ + id: 'default-site', + name: 'Default Site', + description: 'What to show when Nginx is hit with an unknown Host', + value: 'congratulations', + meta: {} + }); + }) + .then(() => { + logger.info('[' + migrate_name + '] Default settings added'); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex, Promise) { + logger.warn('[' + migrate_name + '] You can\'t migrate down the initial data.'); + return Promise.resolve(true); +}; diff --git a/src/backend/models/setting.js b/src/backend/models/setting.js new file mode 100644 index 00000000..2c3e57ee --- /dev/null +++ b/src/backend/models/setting.js @@ -0,0 +1,30 @@ +// Objection Docs: +// http://vincit.github.io/objection.js/ + +const db = require('../db'); +const Model = require('objection').Model; + +Model.knex(db); + +class Setting extends Model { + $beforeInsert () { + // Default for meta + if (typeof this.meta === 'undefined') { + this.meta = {}; + } + } + + static get name () { + return 'Setting'; + } + + static get tableName () { + return 'setting'; + } + + static get jsonAttributes () { + return ['meta']; + } +} + +module.exports = Setting; diff --git a/src/backend/routes/api/main.js b/src/backend/routes/api/main.js index cbc352ed..a9c885c4 100644 --- a/src/backend/routes/api/main.js +++ b/src/backend/routes/api/main.js @@ -31,6 +31,7 @@ router.use('/tokens', require('./tokens')); router.use('/users', require('./users')); router.use('/audit-log', require('./audit-log')); router.use('/reports', require('./reports')); +router.use('/settings', require('./settings')); router.use('/nginx/proxy-hosts', require('./nginx/proxy_hosts')); router.use('/nginx/redirection-hosts', require('./nginx/redirection_hosts')); router.use('/nginx/dead-hosts', require('./nginx/dead_hosts')); diff --git a/src/backend/routes/api/settings.js b/src/backend/routes/api/settings.js new file mode 100644 index 00000000..cc56db8f --- /dev/null +++ b/src/backend/routes/api/settings.js @@ -0,0 +1,96 @@ +const express = require('express'); +const validator = require('../../lib/validator'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const internalSetting = require('../../internal/setting'); +const apiValidator = require('../../lib/validator/api'); + +let router = express.Router({ + caseSensitive: true, + strict: true, + mergeParams: true +}); + +/** + * /api/settings + */ +router + .route('/') + .options((req, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /api/settings + * + * Retrieve all settings + */ + .get((req, res, next) => { + internalSetting.getAll(res.locals.access) + .then(rows => { + res.status(200) + .send(rows); + }) + .catch(next); + }); + +/** + * Specific setting + * + * /api/settings/something + */ +router + .route('/:setting_id') + .options((req, res) => { + res.sendStatus(204); + }) + .all(jwtdecode()) + + /** + * GET /settings/something + * + * Retrieve a specific setting + */ + .get((req, res, next) => { + validator({ + required: ['setting_id'], + additionalProperties: false, + properties: { + setting_id: { + $ref: 'definitions#/definitions/setting_id' + } + } + }, { + setting_id: req.params.setting_id + }) + .then(data => { + return internalSetting.get(res.locals.access, { + id: data.setting_id + }); + }) + .then(row => { + res.status(200) + .send(row); + }) + .catch(next); + }) + + /** + * PUT /api/settings/something + * + * Update and existing setting + */ + .put((req, res, next) => { + apiValidator({$ref: 'endpoints/settings#/links/1/schema'}, req.body) + .then(payload => { + payload.id = req.params.setting_id; + return internalSetting.update(res.locals.access, payload); + }) + .then(result => { + res.status(200) + .send(result); + }) + .catch(next); + }); + +module.exports = router; diff --git a/src/backend/schema/definitions.json b/src/backend/schema/definitions.json index eaf55958..2aa538b2 100644 --- a/src/backend/schema/definitions.json +++ b/src/backend/schema/definitions.json @@ -9,6 +9,13 @@ "type": "integer", "minimum": 1 }, + "setting_id": { + "description": "Unique identifier for a Setting", + "example": "default-site", + "readOnly": true, + "type": "string", + "minLength": 2 + }, "token": { "type": "string", "minLength": 10 diff --git a/src/backend/schema/endpoints/settings.json b/src/backend/schema/endpoints/settings.json new file mode 100644 index 00000000..29e2865a --- /dev/null +++ b/src/backend/schema/endpoints/settings.json @@ -0,0 +1,99 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "endpoints/settings", + "title": "Settings", + "description": "Endpoints relating to Settings", + "stability": "stable", + "type": "object", + "definitions": { + "id": { + "$ref": "../definitions.json#/definitions/setting_id" + }, + "name": { + "description": "Name", + "example": "Default Site", + "type": "string", + "minLength": 2, + "maxLength": 100 + }, + "description": { + "description": "Description", + "example": "Default Site", + "type": "string", + "minLength": 2, + "maxLength": 255 + }, + "value": { + "description": "Value", + "example": "404", + "type": "string", + "maxLength": 255 + }, + "meta": { + "type": "object" + } + }, + "links": [ + { + "title": "List", + "description": "Returns a list of Settings", + "href": "/settings", + "access": "private", + "method": "GET", + "rel": "self", + "http_header": { + "$ref": "../examples.json#/definitions/auth_header" + }, + "targetSchema": { + "type": "array", + "items": { + "$ref": "#/properties" + } + } + }, + { + "title": "Update", + "description": "Updates a existing Setting", + "href": "/settings/{definitions.identity.example}", + "access": "private", + "method": "PUT", + "rel": "update", + "http_header": { + "$ref": "../examples.json#/definitions/auth_header" + }, + "schema": { + "type": "object", + "properties": { + "value": { + "$ref": "#/definitions/value" + }, + "meta": { + "$ref": "#/definitions/meta" + } + } + }, + "targetSchema": { + "properties": { + "$ref": "#/properties" + } + } + } + ], + "properties": { + "id": { + "$ref": "#/definitions/id" + }, + "name": { + "$ref": "#/definitions/description" + }, + "description": { + "$ref": "#/definitions/description" + }, + "value": { + "$ref": "#/definitions/value" + }, + "meta": { + "$ref": "#/definitions/meta" + } + } +} diff --git a/src/backend/schema/index.json b/src/backend/schema/index.json index b61509bd..6e7d1c8a 100644 --- a/src/backend/schema/index.json +++ b/src/backend/schema/index.json @@ -34,6 +34,9 @@ }, "access-lists": { "$ref": "endpoints/access-lists.json" + }, + "settings": { + "$ref": "endpoints/settings.json" } } } diff --git a/src/backend/templates/default.conf b/src/backend/templates/default.conf new file mode 100644 index 00000000..8660e5bc --- /dev/null +++ b/src/backend/templates/default.conf @@ -0,0 +1,32 @@ +# ------------------------------------------------------------ +# Default Site +# ------------------------------------------------------------ +{% if value == "congratulations" %} +# Skipping output, congratulations page configration is baked in. +{%- else %} +server { + listen 80 default; + server_name default-host.localhost; + access_log /data/logs/default_host.log combined; +{% include "_exploits.conf" %} + +{%- if value == "404" %} + location / { + return 404; + } +{% endif %} + +{%- if value == "redirect" %} + location / { + return 301 {{ meta.redirect }}; + } +{%- endif %} + +{%- if value == "html" %} + root /data/nginx/default_www; + location / { + try_files $uri /index.html ={{ meta.http_code }}; + } +{%- endif %} +} +{% endif %} diff --git a/src/frontend/js/app/api.js b/src/frontend/js/app/api.js index cc3b5ce6..c8d57193 100644 --- a/src/frontend/js/app/api.js +++ b/src/frontend/js/app/api.js @@ -662,5 +662,34 @@ module.exports = { getHostStats: function () { return fetch('get', 'reports/hosts'); } + }, + + Settings: { + + /** + * @param {String} setting_id + * @returns {Promise} + */ + getById: function (setting_id) { + return fetch('get', 'settings/' + setting_id); + }, + + /** + * @returns {Promise} + */ + getAll: function () { + return getAllObjects('settings'); + }, + + /** + * @param {Object} data + * @param {Number} data.id + * @returns {Promise} + */ + update: function (data) { + let id = data.id; + delete data.id; + return fetch('put', 'settings/' + id, data); + } } }; diff --git a/src/frontend/js/app/controller.js b/src/frontend/js/app/controller.js index 3f894748..7e516434 100644 --- a/src/frontend/js/app/controller.js +++ b/src/frontend/js/app/controller.js @@ -383,6 +383,36 @@ module.exports = { } }, + /** + * Settings + */ + showSettings: function () { + let controller = this; + if (Cache.User.isAdmin()) { + require(['./main', './settings/main'], (App, View) => { + controller.navigate('/settings'); + App.UI.showAppContent(new View()); + }); + } else { + this.showDashboard(); + } + }, + + /** + * Settings Item Form + * + * @param model + */ + showSettingForm: function (model) { + if (Cache.User.isAdmin()) { + if (model.get('id') === 'default-site') { + require(['./main', './settings/default-site/main'], function (App, View) { + App.UI.showModalDialog(new View({model: model})); + }); + } + } + }, + /** * Logout */ diff --git a/src/frontend/js/app/router.js b/src/frontend/js/app/router.js index f6b686f2..790ef817 100644 --- a/src/frontend/js/app/router.js +++ b/src/frontend/js/app/router.js @@ -15,6 +15,7 @@ module.exports = AppRouter.default.extend({ 'nginx/access': 'showNginxAccess', 'nginx/certificates': 'showNginxCertificates', 'audit-log': 'showAuditLog', + 'settings': 'showSettings', '*default': 'showDashboard' } }); diff --git a/src/frontend/js/app/settings/default-site/main.ejs b/src/frontend/js/app/settings/default-site/main.ejs new file mode 100644 index 00000000..d434c905 --- /dev/null +++ b/src/frontend/js/app/settings/default-site/main.ejs @@ -0,0 +1,77 @@ + diff --git a/src/frontend/js/app/settings/default-site/main.js b/src/frontend/js/app/settings/default-site/main.js new file mode 100644 index 00000000..4bd14e5c --- /dev/null +++ b/src/frontend/js/app/settings/default-site/main.js @@ -0,0 +1,71 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const App = require('../../main'); +const template = require('./main.ejs'); + +require('jquery-serializejson'); +require('selectize'); + +module.exports = Mn.View.extend({ + template: template, + className: 'modal-dialog', + + ui: { + form: 'form', + buttons: '.modal-footer button', + cancel: 'button.cancel', + save: 'button.save', + options: '.option-item', + value: 'input[name="value"]', + redirect: '.redirect-input', + html: '.html-content' + }, + + events: { + 'change @ui.value': function (e) { + let val = this.ui.value.filter(':checked').val(); + this.ui.options.hide(); + this.ui.options.filter('.option-' + val).show(); + }, + + 'click @ui.save': function (e) { + e.preventDefault(); + + let val = this.ui.value.filter(':checked').val(); + + // Clear redirect field before validation + if (val !== 'redirect') { + this.ui.redirect.val('').attr('required', false); + } else { + this.ui.redirect.attr('required', true); + } + + this.ui.html.attr('required', val === 'html'); + + if (!this.ui.form[0].checkValidity()) { + $('').hide().appendTo(this.ui.form).click().remove(); + return; + } + + let view = this; + let data = this.ui.form.serializeJSON(); + data.id = this.model.get('id'); + + this.ui.buttons.prop('disabled', true).addClass('btn-disabled'); + App.Api.Settings.update(data) + .then(result => { + view.model.set(result); + App.UI.closeModal(); + }) + .catch(err => { + alert(err.message); + this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); + }); + } + }, + + onRender: function () { + this.ui.value.trigger('change'); + } +}); diff --git a/src/frontend/js/app/settings/list/item.ejs b/src/frontend/js/app/settings/list/item.ejs new file mode 100644 index 00000000..4f81b450 --- /dev/null +++ b/src/frontend/js/app/settings/list/item.ejs @@ -0,0 +1,21 @@ + +
<%- name %>
+
+ <%- description %> +
+ + +
+ <% if (id === 'default-site') { %> + <%- i18n('settings', 'default-site-' + value) %> + <% } %> +
+ + + + \ No newline at end of file diff --git a/src/frontend/js/app/settings/list/item.js b/src/frontend/js/app/settings/list/item.js new file mode 100644 index 00000000..c79b73b2 --- /dev/null +++ b/src/frontend/js/app/settings/list/item.js @@ -0,0 +1,25 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const App = require('../../main'); +const template = require('./item.ejs'); + +module.exports = Mn.View.extend({ + template: template, + tagName: 'tr', + + ui: { + edit: 'a.edit' + }, + + events: { + 'click @ui.edit': function (e) { + e.preventDefault(); + App.Controller.showSettingForm(this.model); + } + }, + + initialize: function () { + this.listenTo(this.model, 'change', this.render); + } +}); diff --git a/src/frontend/js/app/settings/list/main.ejs b/src/frontend/js/app/settings/list/main.ejs new file mode 100644 index 00000000..c96e923a --- /dev/null +++ b/src/frontend/js/app/settings/list/main.ejs @@ -0,0 +1,8 @@ + + <%- i18n('str', 'name') %> + <%- i18n('str', 'value') %> +   + + + + diff --git a/src/frontend/js/app/settings/list/main.js b/src/frontend/js/app/settings/list/main.js new file mode 100644 index 00000000..bbe75beb --- /dev/null +++ b/src/frontend/js/app/settings/list/main.js @@ -0,0 +1,29 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const ItemView = require('./item'); +const template = require('./main.ejs'); + +const TableBody = Mn.CollectionView.extend({ + tagName: 'tbody', + childView: ItemView +}); + +module.exports = Mn.View.extend({ + tagName: 'table', + className: 'table table-hover table-outline table-vcenter text-nowrap card-table', + template: template, + + regions: { + body: { + el: 'tbody', + replaceElement: true + } + }, + + onRender: function () { + this.showChildView('body', new TableBody({ + collection: this.collection + })); + } +}); diff --git a/src/frontend/js/app/settings/main.ejs b/src/frontend/js/app/settings/main.ejs new file mode 100644 index 00000000..2b02769f --- /dev/null +++ b/src/frontend/js/app/settings/main.ejs @@ -0,0 +1,14 @@ +
+
+
+

<%- i18n('settings', 'title') %>

+
+
+
+
+
+ +
+
+
+
diff --git a/src/frontend/js/app/settings/main.js b/src/frontend/js/app/settings/main.js new file mode 100644 index 00000000..348f467f --- /dev/null +++ b/src/frontend/js/app/settings/main.js @@ -0,0 +1,50 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const App = require('../main'); +const SettingModel = require('../../models/setting'); +const ListView = require('./list/main'); +const ErrorView = require('../error/main'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + id: 'settings', + template: template, + + ui: { + list_region: '.list-region', + add: '.add-item', + dimmer: '.dimmer' + }, + + regions: { + list_region: '@ui.list_region' + }, + + onRender: function () { + let view = this; + + App.Api.Settings.getAll() + .then(response => { + if (!view.isDestroyed() && response && response.length) { + view.showChildView('list_region', new ListView({ + collection: new SettingModel.Collection(response) + })); + } + }) + .catch(err => { + view.showChildView('list_region', new ErrorView({ + code: err.code, + message: err.message, + retry: function () { + App.Controller.showSettings(); + } + })); + + console.error(err); + }) + .then(() => { + view.ui.dimmer.removeClass('active'); + }); + } +}); diff --git a/src/frontend/js/app/ui/menu/main.ejs b/src/frontend/js/app/ui/menu/main.ejs index 3363640c..671b4e3b 100644 --- a/src/frontend/js/app/ui/menu/main.ejs +++ b/src/frontend/js/app/ui/menu/main.ejs @@ -42,6 +42,9 @@ + <% } %>
diff --git a/src/frontend/js/i18n/messages.json b/src/frontend/js/i18n/messages.json index 8c0dcdfb..f4695f75 100644 --- a/src/frontend/js/i18n/messages.json +++ b/src/frontend/js/i18n/messages.json @@ -31,7 +31,8 @@ "online": "Online", "offline": "Offline", "unknown": "Unknown", - "expires": "Expires" + "expires": "Expires", + "value": "Value" }, "login": { "title": "Login to your account" @@ -222,6 +223,14 @@ "meta-title": "Details for Event", "view-meta": "View Details", "date": "Date" + }, + "settings": { + "title": "Settings", + "default-site": "Default Site", + "default-site-congratulations": "Congratulations Page", + "default-site-404": "404 Page", + "default-site-html": "Custom Page", + "default-site-redirect": "Redirect" } } } diff --git a/src/frontend/js/models/setting.js b/src/frontend/js/models/setting.js new file mode 100644 index 00000000..4ee198df --- /dev/null +++ b/src/frontend/js/models/setting.js @@ -0,0 +1,25 @@ +'use strict'; + +const _ = require('underscore'); +const Backbone = require('backbone'); + +const model = Backbone.Model.extend({ + idAttribute: 'id', + + defaults: function () { + return { + id: undefined, + name: '', + description: '', + value: null, + meta: [] + }; + } +}); + +module.exports = { + Model: model, + Collection: Backbone.Collection.extend({ + model: model + }) +}; From 71dfd5d8f83ff8393d74edba6785d99cf5371ac1 Mon Sep 17 00:00:00 2001 From: kolbii <47610371+kolbii@users.noreply.github.com> Date: Mon, 4 Mar 2019 23:21:02 +0100 Subject: [PATCH 09/22] Feature/custom locations (#74) * New feature: custom locations * Custom locations: exteding config generator * Custom locations: refactoring * Fixing proxy_host table on small screens * Custom locations: translations * Custom locations bugfix * Custom locations bugfix * PR #74 fixes --- src/backend/internal/nginx.js | 80 +++++++++++++++---- .../20190215115310_customlocations.js | 37 +++++++++ src/backend/models/proxy_host.js | 2 +- src/backend/schema/endpoints/proxy-hosts.json | 44 ++++++++++ src/backend/templates/_location.conf | 8 ++ src/backend/templates/proxy_host.conf | 3 + src/frontend/js/app/nginx/proxy/form.ejs | 12 +++ src/frontend/js/app/nginx/proxy/form.js | 43 ++++++++++ .../js/app/nginx/proxy/location-item.ejs | 63 +++++++++++++++ src/frontend/js/app/nginx/proxy/location.js | 54 +++++++++++++ src/frontend/js/i18n/messages.json | 9 ++- src/frontend/js/models/proxy-host-location.js | 37 +++++++++ 12 files changed, 373 insertions(+), 19 deletions(-) create mode 100644 src/backend/migrations/20190215115310_customlocations.js create mode 100644 src/backend/templates/_location.conf create mode 100644 src/frontend/js/app/nginx/proxy/location-item.ejs create mode 100644 src/frontend/js/app/nginx/proxy/location.js create mode 100644 src/frontend/js/models/proxy-host-location.js diff --git a/src/backend/internal/nginx.js b/src/backend/internal/nginx.js index 1e992992..89c43a54 100644 --- a/src/backend/internal/nginx.js +++ b/src/backend/internal/nginx.js @@ -130,6 +130,35 @@ const internalNginx = { return '/data/nginx/' + host_type + '/' + host_id + '.conf'; }, + /** + * Generates custom locations + * @param {Object} host + * @returns {Promise} + */ + renderLocations: (host) => { + return new Promise((resolve, reject) => { + let template; + + try { + template = fs.readFileSync(__dirname + '/../templates/_location.conf', {encoding: 'utf8'}); + } catch (err) { + reject(new error.ConfigurationError(err.message)); + return; + } + + let renderer = new Liquid(); + let renderedLocations = ''; + + const locationRendering = async () => { + for (let i = 0; i < host.locations.length; i++) { + renderedLocations += await renderer.parseAndRender(template, host.locations[i]); + } + } + + locationRendering().then(() => resolve(renderedLocations)); + }); + }, + /** * @param {String} host_type * @param {Object} host @@ -157,6 +186,9 @@ const internalNginx = { return; } + let locationsPromise; + let origLocations; + // Manipulate the data a bit before sending it to the template if (host_type !== 'default') { host.use_default_location = true; @@ -165,24 +197,38 @@ const internalNginx = { } } - renderEngine - .parseAndRender(template, host) - .then(config_text => { - fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); - - if (debug_mode) { - logger.success('Wrote config:', filename, config_text); - } - - resolve(true); - }) - .catch(err => { - if (debug_mode) { - logger.warn('Could not write ' + filename + ':', err.message); - } - - reject(new error.ConfigurationError(err.message)); + if (host.locations) { + origLocations = [].concat(host.locations); + locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => { + host.locations = renderedLocations; }); + } else { + locationsPromise = Promise.resolve(); + } + + locationsPromise.then(() => { + renderEngine + .parseAndRender(template, host) + .then(config_text => { + fs.writeFileSync(filename, config_text, {encoding: 'utf8'}); + + if (debug_mode) { + logger.success('Wrote config:', filename, config_text); + } + + // Restore locations array + host.locations = origLocations; + + resolve(true); + }) + .catch(err => { + if (debug_mode) { + logger.warn('Could not write ' + filename + ':', err.message); + } + + reject(new error.ConfigurationError(err.message)); + }); + }); }); }, diff --git a/src/backend/migrations/20190215115310_customlocations.js b/src/backend/migrations/20190215115310_customlocations.js new file mode 100644 index 00000000..5b55dd5e --- /dev/null +++ b/src/backend/migrations/20190215115310_customlocations.js @@ -0,0 +1,37 @@ +'use strict'; + +const migrate_name = 'custom_locations'; +const logger = require('../logger').migrate; + +/** + * Migrate + * Extends proxy_host table with locations field + * + * @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.json('locations'); + }) + .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/models/proxy_host.js b/src/backend/models/proxy_host.js index a1217236..faa5d068 100644 --- a/src/backend/models/proxy_host.js +++ b/src/backend/models/proxy_host.js @@ -47,7 +47,7 @@ class ProxyHost extends Model { } static get jsonAttributes () { - return ['domain_names', 'meta']; + return ['domain_names', 'meta', 'locations']; } static get relationMappings () { diff --git a/src/backend/schema/endpoints/proxy-hosts.json b/src/backend/schema/endpoints/proxy-hosts.json index df7cb119..cd98355f 100644 --- a/src/backend/schema/endpoints/proxy-hosts.json +++ b/src/backend/schema/endpoints/proxy-hosts.json @@ -69,6 +69,41 @@ }, "meta": { "type": "object" + }, + "locations": { + "type": "array", + "minItems": 0, + "items": { + "type": "object", + "required": [ + "forward_scheme", + "forward_host", + "forward_port", + "path" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": ["integer", "null"] + }, + "path": { + "type": "string", + "minLength": 1 + }, + "forward_scheme": { + "$ref": "#/definitions/forward_scheme" + }, + "forward_host": { + "$ref": "#/definitions/forward_host" + }, + "forward_port": { + "$ref": "#/definitions/forward_port" + }, + "advanced_config": { + "type": "string" + } + } + } } }, "properties": { @@ -128,6 +163,9 @@ }, "meta": { "$ref": "#/definitions/meta" + }, + "locations": { + "$ref": "#/definitions/locations" } }, "links": [ @@ -215,6 +253,9 @@ }, "meta": { "$ref": "#/definitions/meta" + }, + "locations": { + "$ref": "#/definitions/locations" } } }, @@ -285,6 +326,9 @@ }, "meta": { "$ref": "#/definitions/meta" + }, + "locations": { + "$ref": "#/definitions/locations" } } }, diff --git a/src/backend/templates/_location.conf b/src/backend/templates/_location.conf new file mode 100644 index 00000000..d31befe8 --- /dev/null +++ b/src/backend/templates/_location.conf @@ -0,0 +1,8 @@ + location {{ path }} { + 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 {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}; + {{ advanced_config }} + } \ No newline at end of file diff --git a/src/backend/templates/proxy_host.conf b/src/backend/templates/proxy_host.conf index 95f850a9..fc58a43b 100644 --- a/src/backend/templates/proxy_host.conf +++ b/src/backend/templates/proxy_host.conf @@ -16,7 +16,10 @@ server { {{ advanced_config }} +{{ locations }} + {% if use_default_location %} + location / { {%- if access_list_id > 0 -%} # Access List diff --git a/src/frontend/js/app/nginx/proxy/form.ejs b/src/frontend/js/app/nginx/proxy/form.ejs index ef9b95b4..3f940f12 100644 --- a/src/frontend/js/app/nginx/proxy/form.ejs +++ b/src/frontend/js/app/nginx/proxy/form.ejs @@ -7,10 +7,22 @@
+ + +
+
+
+ +
+
+
+
+
diff --git a/src/frontend/js/app/nginx/proxy/form.js b/src/frontend/js/app/nginx/proxy/form.js index fcc394de..1e26bcf5 100644 --- a/src/frontend/js/app/nginx/proxy/form.js +++ b/src/frontend/js/app/nginx/proxy/form.js @@ -3,11 +3,14 @@ const Mn = require('backbone.marionette'); const App = require('../../main'); const ProxyHostModel = require('../../../models/proxy-host'); +const ProxyLocationModel = require('../../../models/proxy-host-location'); const template = require('./form.ejs'); const certListItemTemplate = require('../certificates-list-item.ejs'); const accessListItemTemplate = require('./access-list-item.ejs'); +const CustomLocation = require('./location'); const Helpers = require('../../../lib/helpers'); + require('jquery-serializejson'); require('selectize'); @@ -15,6 +18,8 @@ module.exports = Mn.View.extend({ template: template, className: 'modal-dialog', + locationsCollection: new ProxyLocationModel.Collection(), + ui: { form: 'form', domain_names: 'input[name="domain_names"]', @@ -22,6 +27,8 @@ module.exports = Mn.View.extend({ buttons: '.modal-footer button', cancel: 'button.cancel', save: 'button.save', + add_location_btn: 'button.add_location', + locations_container:'.locations_container', certificate_select: 'select[name="certificate_id"]', access_list_select: 'select[name="access_list_id"]', ssl_forced: 'input[name="ssl_forced"]', @@ -32,6 +39,10 @@ module.exports = Mn.View.extend({ letsencrypt: '.letsencrypt' }, + regions: { + locations_regions: '@ui.locations_container' + }, + events: { 'change @ui.certificate_select': function () { let id = this.ui.certificate_select.val(); @@ -82,6 +93,13 @@ module.exports = Mn.View.extend({ } }, + 'click @ui.add_location_btn': function (e) { + e.preventDefault(); + + const model = new ProxyLocationModel.Model(); + this.locationsCollection.add(model); + }, + 'click @ui.save': function (e) { e.preventDefault(); @@ -93,6 +111,16 @@ module.exports = Mn.View.extend({ let view = this; let data = this.ui.form.serializeJSON(); + // Add locations + data.locations = []; + this.locationsCollection.models.forEach((location) => { + data.locations.push(location.toJSON()); + }); + + // Serialize collects path from custom locations + // This field must be removed from root object + delete data.path; + // Manipulate data.forward_port = parseInt(data.forward_port, 10); data.block_exploits = !!data.block_exploits; @@ -246,5 +274,20 @@ module.exports = Mn.View.extend({ if (typeof options.model === 'undefined' || !options.model) { this.model = new ProxyHostModel.Model(); } + + this.locationsCollection = new ProxyLocationModel.Collection(); + + // Custom locations + this.showChildView('locations_regions', new CustomLocation.LocationCollectionView({ + collection: this.locationsCollection + })); + + // Check wether there are any location defined + if (options.model && Array.isArray(options.model.attributes.locations)) { + options.model.attributes.locations.forEach((location) => { + let m = new ProxyLocationModel.Model(location); + this.locationsCollection.add(m); + }); + } } }); diff --git a/src/frontend/js/app/nginx/proxy/location-item.ejs b/src/frontend/js/app/nginx/proxy/location-item.ejs new file mode 100644 index 00000000..66e97c4c --- /dev/null +++ b/src/frontend/js/app/nginx/proxy/location-item.ejs @@ -0,0 +1,63 @@ +
+
+
+
+
+ +
+
+
+ + location + + +
+
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ +
+
+
+ + + <%- i18n('locations', 'delete') %> + +
+
\ No newline at end of file diff --git a/src/frontend/js/app/nginx/proxy/location.js b/src/frontend/js/app/nginx/proxy/location.js new file mode 100644 index 00000000..e9513a48 --- /dev/null +++ b/src/frontend/js/app/nginx/proxy/location.js @@ -0,0 +1,54 @@ +const locationItemTemplate = require('./location-item.ejs'); +const Mn = require('backbone.marionette'); +const App = require('../../main'); + +const LocationView = Mn.View.extend({ + template: locationItemTemplate, + className: 'location_block', + + ui: { + toggle: 'input[type="checkbox"]', + config: '.config', + delete: '.location-delete' + }, + + events: { + 'change @ui.toggle': function(el) { + if (el.target.checked) { + this.ui.config.show(); + } else { + this.ui.config.hide(); + } + }, + + 'change .model': function (e) { + const map = {}; + map[e.target.name] = e.target.value; + this.model.set(map); + }, + + 'click @ui.delete': function () { + this.model.destroy(); + } + }, + + onRender: function() { + $(this.ui.config).hide(); + }, + + templateContext: function() { + return { + i18n: App.i18n + } + } +}); + +const LocationCollectionView = Mn.CollectionView.extend({ + className: 'locations_container', + childView: LocationView +}); + +module.exports = { + LocationCollectionView, + LocationView +} \ No newline at end of file diff --git a/src/frontend/js/i18n/messages.json b/src/frontend/js/i18n/messages.json index f4695f75..c2da571e 100644 --- a/src/frontend/js/i18n/messages.json +++ b/src/frontend/js/i18n/messages.json @@ -82,7 +82,14 @@ "advanced-warning": "Enter your custom Nginx configuration here at your own risk!", "advanced-config": "Custom Nginx Configuration", "hsts-enabled": "HSTS Enabled", - "hsts-subdomains": "HSTS Subdomains" + "hsts-subdomains": "HSTS Subdomains", + "locations": "Custom locations" + }, + "locations": { + "new_location": "Add location", + "path": "/path", + "location_label": "Define location", + "delete": "Delete" }, "ssl": { "letsencrypt": "Let's Encrypt", diff --git a/src/frontend/js/models/proxy-host-location.js b/src/frontend/js/models/proxy-host-location.js new file mode 100644 index 00000000..08459138 --- /dev/null +++ b/src/frontend/js/models/proxy-host-location.js @@ -0,0 +1,37 @@ +'use strict'; + +const Backbone = require('backbone'); + +const model = Backbone.Model.extend({ + idAttribute: 'id', + + defaults: function() { + return { + opened: false, + path: '', + advanced_config: '', + forward_scheme: 'http', + forward_host: '', + forward_port: '80' + } + }, + + toJSON() { + const r = Object.assign({}, this.attributes); + delete r.opened; + return r; + }, + + toggleVisibility: function () { + this.save({ + opened: !this.get('opened') + }); + } +}) + +module.exports = { + Model: model, + Collection: Backbone.Collection.extend({ + model + }) +} \ No newline at end of file From d04b7a0d8805277634da804791662104c2aa0f1f Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Tue, 5 Mar 2019 08:25:12 +1000 Subject: [PATCH 10/22] Bug fixes --- src/backend/templates/_location.conf | 3 ++- src/backend/templates/default.conf | 2 +- .../js/app/settings/default-site/main.ejs | 24 ------------------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/backend/templates/_location.conf b/src/backend/templates/_location.conf index d31befe8..4a1ca91b 100644 --- a/src/backend/templates/_location.conf +++ b/src/backend/templates/_location.conf @@ -5,4 +5,5 @@ proxy_set_header X-Forwarded-For $remote_addr; proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}; {{ advanced_config }} - } \ No newline at end of file + } + diff --git a/src/backend/templates/default.conf b/src/backend/templates/default.conf index 8660e5bc..7ed1af97 100644 --- a/src/backend/templates/default.conf +++ b/src/backend/templates/default.conf @@ -25,7 +25,7 @@ server { {%- if value == "html" %} root /data/nginx/default_www; location / { - try_files $uri /index.html ={{ meta.http_code }}; + try_files $uri /index.html; } {%- endif %} } diff --git a/src/frontend/js/app/settings/default-site/main.ejs b/src/frontend/js/app/settings/default-site/main.ejs index d434c905..126c9d0a 100644 --- a/src/frontend/js/app/settings/default-site/main.ejs +++ b/src/frontend/js/app/settings/default-site/main.ejs @@ -38,30 +38,6 @@
-
- - <% - var code = meta && typeof meta.http_code !== 'undefined' ? parseInt(meta.http_code, 10) : 200; - var codes = [ - [200, 'OK'], - [204, 'No Content'], - [400, 'Bad Request'], - [401, 'Unauthorized'], - [403, 'Forbidden'], - [404, 'Not Found'], - [418, 'I\'m a Teapot'], - [500, 'Internal Server Error'], - [501, 'Not Implemented'], - [502, 'Bad Gateway'], - [503, 'Service Unavailable'] - ]; - %> - -
HTML Content
From f3e6f64c0cdba814920a99833132cad355581b18 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Tue, 5 Mar 2019 08:25:12 +1000 Subject: [PATCH 11/22] Version Bump --- README.md | 20 +------------------- doc/DOCKERHUB.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index d417ff2a..b769cbcd 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.10-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.11-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) @@ -57,24 +57,6 @@ Please consult the [installation instructions](doc/INSTALL.md) for a complete gu if you just want to get up and running in the quickest time possible, grab all the files in the `doc/example/` folder and run `docker-compose up -d` -## Importing from Version 1? - -Here's a [guide for you to migrate your configuration](doc/IMPORTING.md). You should definitely read the [installation instructions](doc/INSTALL.md) first though. - -**Why should I?** - -Version 2 has the following improvements: - -- Management security and multiple user access -- User permissions and visibility -- Custom SSL certificate support -- Audit log of changes -- Broken nginx config detection -- Multiple domains in Let's Encrypt certificates -- Wildcard domain name support (not available with a Let's Encrypt certificate though) -- It's super sexy - - ## Administration When your docker container is running, connect to it on port `81` for the admin interface. diff --git a/doc/DOCKERHUB.md b/doc/DOCKERHUB.md index 911a0837..d07e7b06 100644 --- a/doc/DOCKERHUB.md +++ b/doc/DOCKERHUB.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.10-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.11-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) diff --git a/package.json b/package.json index 5b0533a9..0107fb3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nginx-proxy-manager", - "version": "2.0.10", + "version": "2.0.11", "description": "A beautiful interface for creating Nginx endpoints", "main": "src/backend/index.js", "devDependencies": { From 2280a61c2b3bb33cf1a9d8f59f057fb768db58ec Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Tue, 5 Mar 2019 08:25:12 +1000 Subject: [PATCH 12/22] CI Fix for arm64 --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index d4e0da0c..b17906c3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -211,7 +211,7 @@ pipeline { sh 'docker rmi ${TEMP_IMAGE_ARM64}' // Hack to clean up ec2 instance for next build - sh 'sudo chown -R ec2-user:ec2-user *' + sh 'sudo chown -R ec2-user:ec2-user * || echo "Skipping ec2 ownership"' } } } From 14e62a0830a93385000a5edde1a1b7ce153e414e Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 7 Mar 2019 09:45:01 +1000 Subject: [PATCH 13/22] CI Changes, docker image tag changes and manifests --- Jenkinsfile | 360 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 252 insertions(+), 108 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b17906c3..14047cfc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -8,11 +8,14 @@ pipeline { IMAGE = "nginx-proxy-manager" BASE_IMAGE = "jc21/nginx-proxy-manager-base" TEMP_IMAGE = "nginx-proxy-manager-build_${BUILD_NUMBER}" - TEMP_IMAGE_ARM = "nginx-proxy-manager-arm-build_${BUILD_NUMBER}" - TEMP_IMAGE_ARM64 = "nginx-proxy-manager-arm64-build_${BUILD_NUMBER}" TAG_VERSION = getPackageVersion() MAJOR_VERSION = "2" BRANCH_LOWER = "${BRANCH_NAME.toLowerCase()}" + // Architectures: + AMD64_TAG = "amd64" + ARMV6_TAG = "armv6l" + ARMV7_TAG = "armv7l" + ARM64_TAG = "aarch64" } stages { stage('Build PR') { @@ -29,19 +32,19 @@ pipeline { sh 'docker run --rm -v $(pwd):/data ${DOCKER_CI_TOOLS} node-prune' // Docker Build - sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE} .' + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${AMD64_TAG} .' // Dockerhub - sh 'docker tag ${TEMP_IMAGE} docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}' + sh 'docker tag ${TEMP_IMAGE}-${AMD64_TAG} docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { sh "docker login -u '${duser}' -p '${dpass}'" - sh 'docker push docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}' + sh 'docker push docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' } - sh 'docker rmi ${TEMP_IMAGE}' + sh 'docker rmi ${TEMP_IMAGE}-${AMD64_TAG}' script { - def comment = pullRequest.comment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`") + def comment = pullRequest.comment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}`") } } } @@ -60,23 +63,16 @@ pipeline { sh 'docker run --rm -v $(pwd):/data ${DOCKER_CI_TOOLS} node-prune' // Docker Build - sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE} .' + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${AMD64_TAG} .' // Dockerhub - sh 'docker tag ${TEMP_IMAGE} docker.io/jc21/${IMAGE}:develop' + sh 'docker tag ${TEMP_IMAGE}-${AMD64_TAG} docker.io/jc21/${IMAGE}:develop-${AMD64_TAG}' withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { sh "docker login -u '${duser}' -p '${dpass}'" - sh 'docker push docker.io/jc21/${IMAGE}:develop' + sh 'docker push docker.io/jc21/${IMAGE}:develop-${AMD64_TAG}' } - // Private Registry - sh 'docker tag ${TEMP_IMAGE} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:develop' - withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh "docker login -u '${duser}' -p '${dpass}' ${DOCKER_PRIVATE_REGISTRY}" - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:develop' - } - - sh 'docker rmi ${TEMP_IMAGE}' + sh 'docker rmi ${TEMP_IMAGE}-${AMD64_TAG}' } } } @@ -85,7 +81,13 @@ pipeline { branch 'master' } parallel { - stage('x86_64') { + // ======================== + // amd64 + // ======================== + stage('amd64') { + agent { + label 'amd64' + } steps { ansiColor('xterm') { // Codebase @@ -96,125 +98,268 @@ pipeline { sh 'docker run --rm -v $(pwd):/data ${DOCKER_CI_TOOLS} node-prune' // Docker Build - sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE} .' + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${AMD64_TAG} .' // Dockerhub - sh 'docker tag ${TEMP_IMAGE} docker.io/jc21/${IMAGE}:${TAG_VERSION}' - sh 'docker tag ${TEMP_IMAGE} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}' - sh 'docker tag ${TEMP_IMAGE} docker.io/jc21/${IMAGE}:latest' + sh 'docker tag ${TEMP_IMAGE}-${AMD64_TAG} docker.io/jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${AMD64_TAG} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${AMD64_TAG} docker.io/jc21/${IMAGE}:latest-${AMD64_TAG}' withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { sh "docker login -u '${duser}' -p '${dpass}'" - sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}' - sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}' - sh 'docker push docker.io/jc21/${IMAGE}:latest' + sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:latest-${AMD64_TAG}' } - // Private Registry - sh 'docker tag ${TEMP_IMAGE} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}' - sh 'docker tag ${TEMP_IMAGE} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}' - sh 'docker tag ${TEMP_IMAGE} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest' - - withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh "docker login -u '${duser}' -p '${dpass}' ${DOCKER_PRIVATE_REGISTRY}" - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest' - } - - sh 'docker rmi ${TEMP_IMAGE}' + sh 'docker rmi ${TEMP_IMAGE}-${AMD64_TAG}' } } } - stage('armhf') { + // ======================== + // aarch64 + // ======================== + stage('aarch64') { agent { - label 'armhf' + label 'aarch64' } steps { ansiColor('xterm') { // Codebase - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:armhf yarn install' - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:armhf npm run-script build' - sh 'rm -rf node_modules' - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:armhf yarn install --prod' - - // Docker Build - sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE_ARM} -f Dockerfile.armhf .' - - // Dockerhub - sh 'docker tag ${TEMP_IMAGE_ARM} docker.io/jc21/${IMAGE}:${TAG_VERSION}-armhf' - sh 'docker tag ${TEMP_IMAGE_ARM} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-armhf' - sh 'docker tag ${TEMP_IMAGE_ARM} docker.io/jc21/${IMAGE}:latest-armhf' - - withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh "docker login -u '${duser}' -p '${dpass}'" - sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-armhf' - sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-armhf' - sh 'docker push docker.io/jc21/${IMAGE}:latest-armhf' - } - - // Private Registry - sh 'docker tag ${TEMP_IMAGE_ARM} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}-armhf' - sh 'docker tag ${TEMP_IMAGE_ARM} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}-armhf' - sh 'docker tag ${TEMP_IMAGE_ARM} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest-armhf' - - withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh "docker login -u '${duser}' -p '${dpass}' ${DOCKER_PRIVATE_REGISTRY}" - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}-armhf' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}-armhf' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest-armhf' - } - - sh 'docker rmi ${TEMP_IMAGE_ARM}' - } - } - } - stage('arm64') { - agent { - label 'arm64' - } - steps { - ansiColor('xterm') { - // Codebase - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:arm64 yarn install' - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:arm64 npm run-script build' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} npm run-script build' sh 'sudo rm -rf node_modules' - sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE}:arm64 yarn install --prod' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install --prod' // Docker Build - sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE_ARM64} -f Dockerfile.arm64 .' + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${ARM64_TAG} -f Dockerfile.${ARM64_TAG} .' // Dockerhub - sh 'docker tag ${TEMP_IMAGE_ARM64} docker.io/jc21/${IMAGE}:${TAG_VERSION}-arm64' - sh 'docker tag ${TEMP_IMAGE_ARM64} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-arm64' - sh 'docker tag ${TEMP_IMAGE_ARM64} docker.io/jc21/${IMAGE}:latest-arm64' + sh 'docker tag ${TEMP_IMAGE}-${ARM64_TAG} docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARM64_TAG} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARM64_TAG} docker.io/jc21/${IMAGE}:latest-${ARM64_TAG}' withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { sh "docker login -u '${duser}' -p '${dpass}'" - sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-arm64' - sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-arm64' - sh 'docker push docker.io/jc21/${IMAGE}:latest-arm64' + sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:latest-${ARM64_TAG}' } - // Private Registry - sh 'docker tag ${TEMP_IMAGE_ARM64} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}-arm64' - sh 'docker tag ${TEMP_IMAGE_ARM64} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}-arm64' - sh 'docker tag ${TEMP_IMAGE_ARM64} ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest-arm64' - - withCredentials([usernamePassword(credentialsId: 'jc21-private-registry', passwordVariable: 'dpass', usernameVariable: 'duser')]) { - sh "docker login -u '${duser}' -p '${dpass}' ${DOCKER_PRIVATE_REGISTRY}" - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${TAG_VERSION}-arm64' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:${MAJOR_VERSION}-arm64' - sh 'docker push ${DOCKER_PRIVATE_REGISTRY}/${IMAGE}:latest-arm64' - } - - sh 'docker rmi ${TEMP_IMAGE_ARM64}' + sh 'docker rmi ${TEMP_IMAGE}-${ARM64_TAG}' // Hack to clean up ec2 instance for next build sh 'sudo chown -R ec2-user:ec2-user * || echo "Skipping ec2 ownership"' } } } + // ======================== + // armv7l + // ======================== + stage('armv7l') { + agent { + label 'armv7l' + } + steps { + ansiColor('xterm') { + // Codebase + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} npm run-script build' + sh 'rm -rf node_modules' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install --prod' + + // Docker Build + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${ARMV7_TAG} -f Dockerfile.${ARMV7_TAG} .' + + // Dockerhub + sh 'docker tag ${TEMP_IMAGE}-${ARMV7_TAG} docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARMV7_TAG} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARMV7_TAG} docker.io/jc21/${IMAGE}:latest-${ARMV7_TAG}' + + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { + sh "docker login -u '${duser}' -p '${dpass}'" + sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:latest-${ARMV7_TAG}' + } + + sh 'docker rmi ${TEMP_IMAGE}-${ARMV7_TAG}' + } + } + } + // ======================== + // armv6l - Disabled for the time being + // ======================== + /* + stage('armv6l') { + agent { + label 'armv6l' + } + steps { + ansiColor('xterm') { + // Codebase + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} npm run-script build' + sh 'rm -rf node_modules' + sh 'docker run --rm -v $(pwd):/app -w /app ${BASE_IMAGE} yarn install --prod' + + // Docker Build + sh 'docker build --pull --no-cache --squash --compress -t ${TEMP_IMAGE}-${ARMV6_TAG} -f Dockerfile.${ARMV6_TAG} .' + + // Dockerhub + sh 'docker tag ${TEMP_IMAGE}-${ARMV6_TAG} docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARMV6_TAG} docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG}' + sh 'docker tag ${TEMP_IMAGE}-${ARMV6_TAG} docker.io/jc21/${IMAGE}:latest-${ARMV6_TAG}' + + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { + sh "docker login -u '${duser}' -p '${dpass}'" + sh 'docker push docker.io/jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG}' + sh 'docker push docker.io/jc21/${IMAGE}:latest-${ARMV6_TAG}' + } + + sh 'docker rmi ${TEMP_IMAGE}-${ARMV6_TAG}' + } + } + } + */ + } + } + // ======================== + // latest manifest + // ======================== + stage('Manifest: latest') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker pull jc21/${IMAGE}:latest-${AMD64_TAG}' + sh 'docker pull jc21/${IMAGE}:latest-${ARM64_TAG}' + sh 'docker pull jc21/${IMAGE}:latest-${ARMV7_TAG}' + //sh 'docker pull jc21/${IMAGE}:latest-${ARMV6_TAG}' + + sh 'docker manifest push --purge jc21/${IMAGE}:latest || :' + sh 'docker manifest create jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' + + sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} --arch ${AMD64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARM64_TAG} --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + sh 'docker manifest push --purge jc21/${IMAGE}:latest' + } + } + } + // ======================== + // major + // ======================== + stage('Manifest: major') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG}' + sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG}' + sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + //sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG}' + + sh 'docker manifest push --purge jc21/${IMAGE}:${MAJOR_VERSION} || :' + sh 'docker manifest create jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + + sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} --arch ${AMD64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + } + } + } + // ======================== + // version + // ======================== + stage('Manifest: version') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG}' + sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG}' + sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + //sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG}' + + sh 'docker manifest push --purge jc21/${IMAGE}:${TAG_VERSION} || :' + sh 'docker manifest create jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + + sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} --arch ${AMD64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + } + } + } + // ======================== + // version + // ======================== + stage('Manifest: develop') { + when { + branch 'develop' + } + steps { + ansiColor('xterm') { + sh 'docker pull jc21/${IMAGE}:develop-${AMD64_TAG}' + //sh 'docker pull jc21/${IMAGE}:develop-${ARM64_TAG}' + //sh 'docker pull jc21/${IMAGE}:develop-${ARMV7_TAG}' + //sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG}' + + sh 'docker manifest push --purge jc21/${IMAGE}:develop || :' + sh 'docker manifest create jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' + + sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG} --arch ${AMD64_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARM64_TAG} --arch ${ARM64_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + } + } + } + // ======================== + // master cleanup + // ======================== + parallel { + // ======================== + // amd64 + // ======================== + stage('Latest cleanup') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + } + } + } + stage('Develop cleanup') { + when { + branch 'develop' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' + } + } + } + stage('PR cleanup') { + when { + changeRequest() + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' + } + } } } } @@ -234,4 +379,3 @@ def getPackageVersion() { ver = sh(script: 'docker run --rm -v $(pwd):/data ${DOCKER_CI_TOOLS} bash -c "cat /data/package.json|jq -r \'.version\'"', returnStdout: true) return ver.trim() } - From 1db2a29d4994c6defa0191056086abfc097ea370 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 7 Mar 2019 09:45:01 +1000 Subject: [PATCH 14/22] CI Changes, docker image tag changes and manifests --- Jenkinsfile | 59 ++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 14047cfc..857b5b0d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -323,41 +323,40 @@ pipeline { } } // ======================== - // master cleanup + // cleanup // ======================== - parallel { - // ======================== - // amd64 - // ======================== - stage('Latest cleanup') { - when { - branch 'master' - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + stage { + parallel { + stage('Latest cleanup') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + } } } - } - stage('Develop cleanup') { - when { - branch 'develop' - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' + stage('Develop cleanup') { + when { + branch 'develop' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' + } } } - } - stage('PR cleanup') { - when { - changeRequest() - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' + stage('PR cleanup') { + when { + changeRequest() + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' + } } } } From 1b0563a4a68936a3b35596b2df2a36f8ed971a51 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 7 Mar 2019 09:45:01 +1000 Subject: [PATCH 15/22] CI Changes, docker image tag changes and manifests --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 857b5b0d..c2d9f623 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -325,7 +325,7 @@ pipeline { // ======================== // cleanup // ======================== - stage { + stage('Cleanup') { parallel { stage('Latest cleanup') { when { From 0ac349ba67d32db109fc8eb1a8f120365449f5ee Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 7 Mar 2019 09:45:01 +1000 Subject: [PATCH 16/22] CI Changes, docker image tag changes and manifests --- Jenkinsfile | 58 +++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c2d9f623..5b934e88 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -325,39 +325,35 @@ pipeline { // ======================== // cleanup // ======================== - stage('Cleanup') { - parallel { - stage('Latest cleanup') { - when { - branch 'master' - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' - } - } + stage('Latest cleanup') { + when { + branch 'master' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' } - stage('Develop cleanup') { - when { - branch 'develop' - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' - } - } + } + } + stage('Develop cleanup') { + when { + branch 'develop' + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' } - stage('PR cleanup') { - when { - changeRequest() - } - steps { - ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' - } - } + } + } + stage('PR cleanup') { + when { + changeRequest() + } + steps { + ansiColor('xterm') { + sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' } } } From 631d9ae4eb3dc0b1554d4b1f54d75411dcbc62e6 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 7 Mar 2019 09:45:01 +1000 Subject: [PATCH 17/22] CI Changes, docker image tag changes and manifests --- Jenkinsfile | 47 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 5b934e88..e8dbbcb3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -228,12 +228,15 @@ pipeline { // ======================== // latest manifest // ======================== - stage('Manifest: latest') { + stage('Latest Manifest') { when { branch 'master' } steps { ansiColor('xterm') { + // ======================= + // latest + // ======================= sh 'docker pull jc21/${IMAGE}:latest-${AMD64_TAG}' sh 'docker pull jc21/${IMAGE}:latest-${ARM64_TAG}' sh 'docker pull jc21/${IMAGE}:latest-${ARMV7_TAG}' @@ -247,18 +250,10 @@ pipeline { sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' //sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' sh 'docker manifest push --purge jc21/${IMAGE}:latest' - } - } - } - // ======================== - // major - // ======================== - stage('Manifest: major') { - when { - branch 'master' - } - steps { - ansiColor('xterm') { + + // ======================= + // major version + // ======================= sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG}' sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG}' sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' @@ -271,18 +266,10 @@ pipeline { sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} --arch ${ARM64_TAG}' sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' //sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' - } - } - } - // ======================== - // version - // ======================== - stage('Manifest: version') { - when { - branch 'master' - } - steps { - ansiColor('xterm') { + + // ======================= + // version + // ======================= sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG}' sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG}' sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' @@ -299,9 +286,9 @@ pipeline { } } // ======================== - // version + // develop // ======================== - stage('Manifest: develop') { + stage('Develop Manifest') { when { branch 'develop' } @@ -325,7 +312,7 @@ pipeline { // ======================== // cleanup // ======================== - stage('Latest cleanup') { + stage('Latest Cleanup') { when { branch 'master' } @@ -337,7 +324,7 @@ pipeline { } } } - stage('Develop cleanup') { + stage('Develop Cleanup') { when { branch 'develop' } @@ -347,7 +334,7 @@ pipeline { } } } - stage('PR cleanup') { + stage('PR Cleanup') { when { changeRequest() } From d79fcbf4476fb48d430ad95e10002b51717be752 Mon Sep 17 00:00:00 2001 From: kolbii <47610371+kolbii@users.noreply.github.com> Date: Mon, 11 Mar 2019 04:52:09 +0100 Subject: [PATCH 18/22] This commit resolves #98 so custom location can forward to custom path. (#99) Awesome work! --- src/backend/internal/nginx.js | 11 ++++++++++- src/backend/schema/endpoints/proxy-hosts.json | 3 +++ src/backend/templates/_location.conf | 2 +- src/frontend/js/app/nginx/proxy/location-item.ejs | 1 + src/frontend/js/i18n/messages.json | 3 ++- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/backend/internal/nginx.js b/src/backend/internal/nginx.js index 89c43a54..faaf77fb 100644 --- a/src/backend/internal/nginx.js +++ b/src/backend/internal/nginx.js @@ -151,7 +151,16 @@ const internalNginx = { const locationRendering = async () => { for (let i = 0; i < host.locations.length; i++) { - renderedLocations += await renderer.parseAndRender(template, host.locations[i]); + let locationCopy = Object.assign({}, host.locations[i]); + + if (locationCopy.forward_host.indexOf('/') > -1) { + const splitted = locationCopy.forward_host.split('/'); + + locationCopy.forward_host = splitted.shift(); + locationCopy.forward_path = `/${splitted.join('/')}`; + } + + renderedLocations += await renderer.parseAndRender(template, locationCopy); } } diff --git a/src/backend/schema/endpoints/proxy-hosts.json b/src/backend/schema/endpoints/proxy-hosts.json index cd98355f..af87c467 100644 --- a/src/backend/schema/endpoints/proxy-hosts.json +++ b/src/backend/schema/endpoints/proxy-hosts.json @@ -99,6 +99,9 @@ "forward_port": { "$ref": "#/definitions/forward_port" }, + "forward_path": { + "type": "string" + }, "advanced_config": { "type": "string" } diff --git a/src/backend/templates/_location.conf b/src/backend/templates/_location.conf index 4a1ca91b..0b8894d1 100644 --- a/src/backend/templates/_location.conf +++ b/src/backend/templates/_location.conf @@ -3,7 +3,7 @@ proxy_set_header X-Forwarded-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; - proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}; + proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }}; {{ advanced_config }} } diff --git a/src/frontend/js/app/nginx/proxy/location-item.ejs b/src/frontend/js/app/nginx/proxy/location-item.ejs index 66e97c4c..d6f362a0 100644 --- a/src/frontend/js/app/nginx/proxy/location-item.ejs +++ b/src/frontend/js/app/nginx/proxy/location-item.ejs @@ -39,6 +39,7 @@
+ <%- i18n('proxy-hosts', 'cutom-forward-host-help') %>
diff --git a/src/frontend/js/i18n/messages.json b/src/frontend/js/i18n/messages.json index c2da571e..a51f27c6 100644 --- a/src/frontend/js/i18n/messages.json +++ b/src/frontend/js/i18n/messages.json @@ -114,7 +114,8 @@ "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": "Websockets Support", - "ignore-invalid-upstream-ssl": "Ignore Invalid SSL" + "ignore-invalid-upstream-ssl": "Ignore Invalid SSL", + "cutom-forward-host-help": "Use 1.1.1.1/path for sub-folder forwarding" }, "redirection-hosts": { "title": "Redirection Hosts", From dce6423c85923f4af52ab0a605c7e16a0fdacd60 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 15 Mar 2019 07:49:08 +1000 Subject: [PATCH 19/22] Fixes #103 - Allow for longer domain names --- rootfs/etc/nginx/nginx.conf | 39 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/rootfs/etc/nginx/nginx.conf b/rootfs/etc/nginx/nginx.conf index 7d068736..19332564 100644 --- a/rootfs/etc/nginx/nginx.conf +++ b/rootfs/etc/nginx/nginx.conf @@ -19,25 +19,26 @@ events { } http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - sendfile on; - server_tokens off; - tcp_nopush on; - tcp_nodelay on; - client_body_temp_path /tmp/nginx/body 1 2; - keepalive_timeout 65; - ssl_prefer_server_ciphers on; - gzip on; - proxy_ignore_client_abort off; - client_max_body_size 2000m; - proxy_http_version 1.1; - proxy_set_header X-Forwarded-Scheme $scheme; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Accept-Encoding ""; - proxy_cache off; - proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m; - proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m; + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile on; + server_tokens off; + tcp_nopush on; + tcp_nodelay on; + client_body_temp_path /tmp/nginx/body 1 2; + keepalive_timeout 65; + ssl_prefer_server_ciphers on; + gzip on; + proxy_ignore_client_abort off; + client_max_body_size 2000m; + server_names_hash_bucket_size 64; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-Scheme $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Accept-Encoding ""; + proxy_cache off; + proxy_cache_path /var/lib/nginx/cache/public levels=1:2 keys_zone=public-cache:30m max_size=192m; + proxy_cache_path /var/lib/nginx/cache/private levels=1:2 keys_zone=private-cache:5m max_size=1024m; # MISS # BYPASS From 27a06850ff442d5c4d260617d54dd88fc755f6eb Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 15 Mar 2019 07:49:08 +1000 Subject: [PATCH 20/22] CI Docker manifest improvements --- Jenkinsfile | 55 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e8dbbcb3..167897ec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,8 +6,8 @@ pipeline { agent any environment { IMAGE = "nginx-proxy-manager" - BASE_IMAGE = "jc21/nginx-proxy-manager-base" - TEMP_IMAGE = "nginx-proxy-manager-build_${BUILD_NUMBER}" + BASE_IMAGE = "jc21/${IMAGE}-base" + TEMP_IMAGE = "${IMAGE}-build_${BUILD_NUMBER}" TAG_VERSION = getPackageVersion() MAJOR_VERSION = "2" BRANCH_LOWER = "${BRANCH_NAME.toLowerCase()}" @@ -15,7 +15,7 @@ pipeline { AMD64_TAG = "amd64" ARMV6_TAG = "armv6l" ARMV7_TAG = "armv7l" - ARM64_TAG = "aarch64" + ARM64_TAG = "arm64" } stages { stage('Build PR') { @@ -117,11 +117,11 @@ pipeline { } } // ======================== - // aarch64 + // arm64 // ======================== - stage('aarch64') { + stage('arm64') { agent { - label 'aarch64' + label 'arm64' } steps { ansiColor('xterm') { @@ -147,9 +147,6 @@ pipeline { } sh 'docker rmi ${TEMP_IMAGE}-${ARM64_TAG}' - - // Hack to clean up ec2 instance for next build - sh 'sudo chown -R ec2-user:ec2-user * || echo "Skipping ec2 ownership"' } } } @@ -242,13 +239,13 @@ pipeline { sh 'docker pull jc21/${IMAGE}:latest-${ARMV7_TAG}' //sh 'docker pull jc21/${IMAGE}:latest-${ARMV6_TAG}' - sh 'docker manifest push --purge jc21/${IMAGE}:latest || :' + sh 'docker manifest push --purge jc21/${IMAGE}:latest || echo ""' sh 'docker manifest create jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} --arch ${AMD64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARM64_TAG} --arch ${ARM64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARM64_TAG} --os linux --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV7_TAG} --os linux --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${ARMV6_TAG} --os linux --arch arm --variant ${ARMV6_TAG}' sh 'docker manifest push --purge jc21/${IMAGE}:latest' // ======================= @@ -259,13 +256,13 @@ pipeline { sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' //sh 'docker pull jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG}' - sh 'docker manifest push --purge jc21/${IMAGE}:${MAJOR_VERSION} || :' + sh 'docker manifest push --purge jc21/${IMAGE}:${MAJOR_VERSION} || echo ""' sh 'docker manifest create jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} --arch ${AMD64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} --arch ${ARM64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} --os linux --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG} --os linux --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:${MAJOR_VERSION} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV6_TAG} --os linux --arch arm --variant ${ARMV6_TAG}' // ======================= // version @@ -275,13 +272,13 @@ pipeline { sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' //sh 'docker pull jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG}' - sh 'docker manifest push --purge jc21/${IMAGE}:${TAG_VERSION} || :' + sh 'docker manifest push --purge jc21/${IMAGE}:${TAG_VERSION} || echo ""' sh 'docker manifest create jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} --arch ${AMD64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} --arch ${ARM64_TAG}' - sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} --os linux --arch ${ARM64_TAG}' + sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG} --os linux --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:${TAG_VERSION} jc21/${IMAGE}:${TAG_VERSION}-${ARMV6_TAG} --os linux --arch arm --variant ${ARMV6_TAG}' } } } @@ -303,9 +300,9 @@ pipeline { sh 'docker manifest create jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG} --arch ${AMD64_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARM64_TAG} --arch ${ARM64_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV7_TAG} --arch arm --variant ${ARMV7_TAG}' - //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV6_TAG} --arch arm --variant ${ARMV6_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARM64_TAG} --os linux --arch ${ARM64_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV7_TAG} --os linux --arch arm --variant ${ARMV7_TAG}' + //sh 'docker manifest annotate jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${ARMV6_TAG} --os linux --arch arm --variant ${ARMV6_TAG}' } } } @@ -318,9 +315,9 @@ pipeline { } steps { ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG}' - sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG}' + sh 'docker rmi jc21/${IMAGE}:latest jc21/${IMAGE}:latest-${AMD64_TAG} jc21/${IMAGE}:latest-${ARM64_TAG} jc21/${IMAGE}:latest-${ARMV7_TAG} || echo ""' + sh 'docker rmi jc21/${IMAGE}:${MAJOR_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${MAJOR_VERSION}-${ARMV7_TAG} || echo ""' + sh 'docker rmi jc21/${IMAGE}:${TAG_VERSION}-${AMD64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARM64_TAG} jc21/${IMAGE}:${TAG_VERSION}-${ARMV7_TAG} || echo ""' } } } @@ -330,7 +327,7 @@ pipeline { } steps { ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG}' + sh 'docker rmi jc21/${IMAGE}:develop jc21/${IMAGE}:develop-${AMD64_TAG} || echo ""' } } } @@ -340,7 +337,7 @@ pipeline { } steps { ansiColor('xterm') { - sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG}' + sh 'docker rmi jc21/${IMAGE}:github-${BRANCH_LOWER}-${AMD64_TAG} || echo ""' } } } From 6d8f5aa3a77e475e90a4e8a8a4b150d5139f5842 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Fri, 15 Mar 2019 07:49:08 +1000 Subject: [PATCH 21/22] Version bump --- README.md | 2 +- doc/DOCKERHUB.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b769cbcd..18324d8b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.11-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.12-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) diff --git a/doc/DOCKERHUB.md b/doc/DOCKERHUB.md index d07e7b06..5f0cde15 100644 --- a/doc/DOCKERHUB.md +++ b/doc/DOCKERHUB.md @@ -2,7 +2,7 @@ # Nginx Proxy Manager -![Version](https://img.shields.io/badge/version-2.0.11-green.svg?style=for-the-badge) +![Version](https://img.shields.io/badge/version-2.0.12-green.svg?style=for-the-badge) ![Stars](https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge) ![Pulls](https://img.shields.io/docker/pulls/jc21/nginx-proxy-manager.svg?style=for-the-badge) diff --git a/package.json b/package.json index 0107fb3c..3ca74ef9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nginx-proxy-manager", - "version": "2.0.11", + "version": "2.0.12", "description": "A beautiful interface for creating Nginx endpoints", "main": "src/backend/index.js", "devDependencies": { From 3095cff7d99e99e42183cc3f65d1f2938fbf08f5 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Tue, 19 Mar 2019 07:01:12 +1000 Subject: [PATCH 22/22] Forgot to change dockerfiles to match CI names --- Dockerfile.armv6 => Dockerfile.armv6l | 0 Dockerfile.armhf => Dockerfile.armv7l | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename Dockerfile.armv6 => Dockerfile.armv6l (100%) rename Dockerfile.armhf => Dockerfile.armv7l (100%) diff --git a/Dockerfile.armv6 b/Dockerfile.armv6l similarity index 100% rename from Dockerfile.armv6 rename to Dockerfile.armv6l diff --git a/Dockerfile.armhf b/Dockerfile.armv7l similarity index 100% rename from Dockerfile.armhf rename to Dockerfile.armv7l