mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-07-03 08:36:50 +00:00
Compare commits
66 Commits
v2.12.0
...
c6d884dab6
Author | SHA1 | Date | |
---|---|---|---|
c6d884dab6 | |||
5dc78df0bb | |||
04636b71a9 | |||
1353937c36 | |||
f68c1b7c29 | |||
32e0784865 | |||
f386f6b640 | |||
5ba7363c9e | |||
2e45444328 | |||
eb5c51a657 | |||
cb795565ea | |||
04b3608b4e | |||
111fc287eb | |||
95a94a4f8c | |||
5e7b69c396 | |||
2723de24fd | |||
891877afb6 | |||
8e9e033a72 | |||
e6ec74c2f7 | |||
b3de76c945 | |||
fcf4117f8e | |||
d26e8c1d0c | |||
19ed4c1212 | |||
03018d252b | |||
8351dd41f6 | |||
97212f2686 | |||
fe068a8b51 | |||
61e2bde98f | |||
81c9038929 | |||
4ea50ca40c | |||
53ed12bcf2 | |||
cb3e4ed59c | |||
b20dc5eade | |||
586afc0c91 | |||
93ea17a9bb | |||
2075f98cad | |||
07a4e5791f | |||
640a1eeb68 | |||
20646e7bb5 | |||
87998a03ce | |||
a0b26b9e98 | |||
d6791f4e38 | |||
62c94f3099 | |||
25a26d6175 | |||
17246e418f | |||
f7d3ca0b07 | |||
a55de386e7 | |||
e9d4f5b827 | |||
1c1cee3836 | |||
eaf6335694 | |||
ffe05ebd41 | |||
2e9a4f1aed | |||
d17c85e4c8 | |||
dad8d0ca00 | |||
d7e0558a35 | |||
ee41bb5562 | |||
0cf6b9caa4 | |||
68a9baf206 | |||
d92421d098 | |||
96c58b203e | |||
d499e2bfef | |||
2f9e062718 | |||
edbed1af90 | |||
8497022e41 | |||
fa2c814fcb | |||
d96a3987c0 |
10
Jenkinsfile
vendored
10
Jenkinsfile
vendored
@ -43,7 +43,7 @@ pipeline {
|
||||
steps {
|
||||
script {
|
||||
// Defaults to the Branch name, which is applies to all branches AND pr's
|
||||
buildxPushTags = "-t docker.io/jc21/${IMAGE}:github-${BRANCH_LOWER}"
|
||||
buildxPushTags = "-t docker.io/nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,13 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
npmGithubPrComment("Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as `jc21/${IMAGE}:github-${BRANCH_LOWER}`\n\n**Note:** ensure you backup your NPM instance before testing this PR image! Especially if this PR contains database changes.", true)
|
||||
npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on
|
||||
[DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev)
|
||||
as `nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}`
|
||||
|
||||
**Note:** ensure you backup your NPM instance before testing this image! Especially if there are database changes
|
||||
**Note:** this is a different docker image namespace than the official image
|
||||
""", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="https://nginxproxymanager.com/github.png">
|
||||
<br><br>
|
||||
<img src="https://img.shields.io/badge/version-2.12.0-green.svg?style=for-the-badge">
|
||||
<img src="https://img.shields.io/badge/version-2.12.1-green.svg?style=for-the-badge">
|
||||
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
||||
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
||||
</a>
|
||||
|
@ -570,6 +570,7 @@ const internalCertificate = {
|
||||
return internalCertificate.create(access, {
|
||||
provider: 'letsencrypt',
|
||||
domain_names: data.domain_names,
|
||||
ssl_key_type: data.ssl_key_type,
|
||||
meta: data.meta
|
||||
});
|
||||
},
|
||||
@ -832,6 +833,7 @@ const internalCertificate = {
|
||||
|
||||
const cmd = `${certbotCommand} certonly ` +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name "npm-${certificate.id}" ` +
|
||||
@ -873,6 +875,7 @@ const internalCertificate = {
|
||||
|
||||
let mainCmd = certbotCommand + ' certonly ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
@ -969,6 +972,7 @@ const internalCertificate = {
|
||||
|
||||
const cmd = certbotCommand + ' renew --force-renewal ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
@ -1002,6 +1006,7 @@ const internalCertificate = {
|
||||
|
||||
let mainCmd = certbotCommand + ' renew --force-renewal ' +
|
||||
`--config "${letsencryptConfig}" ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-name 'npm-${certificate.id}' ` +
|
||||
@ -1032,9 +1037,10 @@ const internalCertificate = {
|
||||
*/
|
||||
revokeLetsEncryptSsl: (certificate, throw_errors) => {
|
||||
logger.info('Revoking Let\'sEncrypt certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', '));
|
||||
|
||||
|
||||
const mainCmd = certbotCommand + ' revoke ' +
|
||||
`--config '${letsencryptConfig}' ` +
|
||||
`--key-type '${certificate.ssl_key_type}' ` +
|
||||
'--work-dir "/tmp/letsencrypt-lib" ' +
|
||||
'--logs-dir "/tmp/letsencrypt-log" ' +
|
||||
`--cert-path '/etc/letsencrypt/live/npm-${certificate.id}/fullchain.pem' ` +
|
||||
|
@ -228,8 +228,32 @@ const internalHost = {
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal use only, checks to see if the there is another default server record
|
||||
*
|
||||
* @param {String} hostname
|
||||
* @param {String} [ignore_type] 'proxy', 'redirection', 'dead'
|
||||
* @param {Integer} [ignore_id] Must be supplied if type was also supplied
|
||||
* @returns {Promise}
|
||||
*/
|
||||
checkDefaultServerNotExist: function (hostname) {
|
||||
let promises = proxyHostModel
|
||||
.query()
|
||||
.where('default_server', true)
|
||||
.andWhere('domain_names', 'not like', '%' + hostname + '%');
|
||||
|
||||
|
||||
return Promise.resolve(promises)
|
||||
.then((promises_results) => {
|
||||
if (promises_results.length > 0){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = internalHost;
|
||||
|
@ -181,9 +181,11 @@ const internalNginx = {
|
||||
* @param {Object} host
|
||||
* @returns {Promise}
|
||||
*/
|
||||
generateConfig: (host_type, host) => {
|
||||
generateConfig: (host_type, host_row) => {
|
||||
// Prevent modifying the original object:
|
||||
let host = JSON.parse(JSON.stringify(host_row));
|
||||
const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
|
||||
|
||||
|
||||
if (config.debug()) {
|
||||
logger.info('Generating ' + nice_host_type + ' Config:', JSON.stringify(host, null, 2));
|
||||
}
|
||||
|
@ -43,6 +43,22 @@ const internalProxyHost = {
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
// Get a list of the domain names and check each of them against default records
|
||||
if (data.default_server){
|
||||
if (data.domain_names.length > 1) {
|
||||
throw new error.ValidationError('Default server cant be set for multiple domain!');
|
||||
}
|
||||
|
||||
return internalHost
|
||||
.checkDefaultServerNotExist(data.domain_names[0])
|
||||
.then((result) => {
|
||||
if (!result){
|
||||
throw new error.ValidationError('One default server already exists');
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// At this point the domains should have been checked
|
||||
data.owner_user_id = access.token.getUserId(1);
|
||||
@ -140,6 +156,22 @@ const internalProxyHost = {
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
// Get a list of the domain names and check each of them against default records
|
||||
if (data.default_server){
|
||||
if (data.domain_names.length > 1) {
|
||||
throw new error.ValidationError('Default server cant be set for multiple domain!');
|
||||
}
|
||||
|
||||
return internalHost
|
||||
.checkDefaultServerNotExist(data.domain_names[0])
|
||||
.then((result) => {
|
||||
if (!result){
|
||||
throw new error.ValidationError('One default server already exists');
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
return internalProxyHost.get(access, {id: data.id});
|
||||
})
|
||||
@ -152,6 +184,7 @@ const internalProxyHost = {
|
||||
if (create_certificate) {
|
||||
return internalCertificate.createQuickCertificate(access, {
|
||||
domain_names: data.domain_names || row.domain_names,
|
||||
ssl_key_type: data.ssl_key_type || row.ssl_key_type,
|
||||
meta: _.assign({}, row.meta, data.meta)
|
||||
})
|
||||
.then((cert) => {
|
||||
|
@ -5,6 +5,8 @@ const authModel = require('../models/auth');
|
||||
const helpers = require('../lib/helpers');
|
||||
const TokenModel = require('../models/token');
|
||||
|
||||
const ERROR_MESSAGE_INVALID_AUTH = 'Invalid email or password';
|
||||
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
@ -69,15 +71,15 @@ module.exports = {
|
||||
};
|
||||
});
|
||||
} else {
|
||||
throw new error.AuthError('Invalid password');
|
||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new error.AuthError('No password auth for user');
|
||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new error.AuthError('No relevant user found');
|
||||
throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
39
backend/migrations/20241209062244_ssl_key_type.js
Normal file
39
backend/migrations/20241209062244_ssl_key_type.js
Normal file
@ -0,0 +1,39 @@
|
||||
const migrate_name = 'identifier_for_migrate';
|
||||
const logger = require('../logger').migrate;
|
||||
|
||||
/**
|
||||
* Migrate
|
||||
*
|
||||
* @see http://knexjs.org/#Schema
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
|
||||
logger.info(`[${migrate_name}] Migrating Up...`);
|
||||
|
||||
return knex.schema.alterTable('proxy_host', (table) => {
|
||||
table.enum('ssl_key_type', ['ecdsa', 'rsa']).defaultTo('ecdsa').notNullable();
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' added to table 'proxy_host'`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Undo Migrate
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Down...`);
|
||||
|
||||
return knex.schema.alterTable('proxy_host', (table) => {
|
||||
table.dropColumn('ssl_key_type');
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' removed from table 'proxy_host'`);
|
||||
});
|
||||
};
|
39
backend/migrations/20241211081223_ssl_key_type_in_proxy.js
Normal file
39
backend/migrations/20241211081223_ssl_key_type_in_proxy.js
Normal file
@ -0,0 +1,39 @@
|
||||
const migrate_name = 'identifier_for_migrate';
|
||||
const logger = require('../logger').migrate;
|
||||
|
||||
/**
|
||||
* Migrate
|
||||
*
|
||||
* @see http://knexjs.org/#Schema
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
|
||||
logger.info(`[${migrate_name}] Migrating Up...`);
|
||||
|
||||
return knex.schema.alterTable('certificate', (table) => {
|
||||
table.enum('ssl_key_type', ['ecdsa', 'rsa']).defaultTo('ecdsa').notNullable();
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' added to table 'proxy_host'`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Undo Migrate
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Down...`);
|
||||
|
||||
return knex.schema.alterTable('certificate', (table) => {
|
||||
table.dropColumn('ssl_key_type');
|
||||
}).then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'ssl_key_type' removed from table 'proxy_host'`);
|
||||
});
|
||||
};
|
40
backend/migrations/20241221201400_default_server.js
Normal file
40
backend/migrations/20241221201400_default_server.js
Normal file
@ -0,0 +1,40 @@
|
||||
const migrate_name = 'identifier_for_migrate';
|
||||
const logger = require('../logger').migrate;
|
||||
|
||||
/**
|
||||
* Migrate Up
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Up...`);
|
||||
|
||||
// Add default_server column to proxy_host table
|
||||
return knex.schema.table('proxy_host', (table) => {
|
||||
table.boolean('default_server').notNullable().defaultTo(false);
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'default_server' added to 'proxy_host' table`);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Migrate Down
|
||||
*
|
||||
* @param {Object} knex
|
||||
* @param {Promise} Promise
|
||||
* @returns {Promise}
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
logger.info(`[${migrate_name}] Migrating Down...`);
|
||||
|
||||
// Remove default_server column from proxy_host table
|
||||
return knex.schema.table('proxy_host', (table) => {
|
||||
table.dropColumn('default_server');
|
||||
})
|
||||
.then(() => {
|
||||
logger.info(`[${migrate_name}] Column 'default_server' removed from 'proxy_host' table`);
|
||||
});
|
||||
};
|
@ -21,6 +21,7 @@ const boolFields = [
|
||||
'enabled',
|
||||
'hsts_enabled',
|
||||
'hsts_subdomains',
|
||||
'default_server',
|
||||
];
|
||||
|
||||
class ProxyHost extends Model {
|
||||
|
@ -41,6 +41,15 @@
|
||||
"owner": {
|
||||
"$ref": "./user-object.json"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"type": "string",
|
||||
"enum": ["ecdsa", "rsa"],
|
||||
"description": "Type of SSL key (either ecdsa or rsa)"
|
||||
},
|
||||
"default_server": {
|
||||
"type": "boolean",
|
||||
"description": "Defines if the server is the default for unmatched requests"
|
||||
},
|
||||
"meta": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
@ -23,9 +23,9 @@
|
||||
"locations",
|
||||
"hsts_enabled",
|
||||
"hsts_subdomains",
|
||||
"certificate",
|
||||
"use_default_location",
|
||||
"ipv6"
|
||||
"ssl_key_type",
|
||||
"default_server",
|
||||
"certificate"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@ -152,11 +152,14 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"use_default_location": {
|
||||
"type": "boolean"
|
||||
"ssl_key_type": {
|
||||
"type": "string",
|
||||
"enum": ["ecdsa", "rsa"],
|
||||
"description": "Type of SSL key (either ecdsa or rsa)"
|
||||
},
|
||||
"ipv6": {
|
||||
"type": "boolean"
|
||||
"default_server": {
|
||||
"type": "boolean",
|
||||
"description": "Defines if the server is the default for unmatched requests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
},
|
||||
"forward_scheme": {
|
||||
"type": "string",
|
||||
"enum": ["http", "https"]
|
||||
"enum": ["auto", "http", "https"]
|
||||
},
|
||||
"forward_domain_name": {
|
||||
"description": "Domain Name",
|
||||
|
@ -25,7 +25,7 @@
|
||||
"value": {
|
||||
"description": "Value in almost any form",
|
||||
"example": "congratulations",
|
||||
"oneOf": [
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
@ -46,7 +46,10 @@
|
||||
},
|
||||
"meta": {
|
||||
"description": "Extra metadata",
|
||||
"example": {},
|
||||
"example": {
|
||||
"redirect": "http://example.com",
|
||||
"html": "<h1>404</h1>"
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,9 @@
|
||||
"incoming_port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
"maximum": 65535,
|
||||
"if": {"properties": {"tcp_forwarding": {"const": true}}},
|
||||
"then": {"not": {"oneOf": [{"const": 80}, {"const": 443}]}}
|
||||
},
|
||||
"forwarding_host": {
|
||||
"anyOf": [
|
||||
|
@ -49,8 +49,7 @@
|
||||
"minLength": 1
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +94,7 @@
|
||||
"avatar": "",
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"certificate": null,
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
"certificate": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -79,9 +79,7 @@
|
||||
"nickname": "Admin",
|
||||
"avatar": "",
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -79,6 +79,12 @@
|
||||
},
|
||||
"locations": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/locations"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/ssl_key_type"
|
||||
},
|
||||
"default_server": {
|
||||
"$ref": "../../../../components/proxy-host-object.json#/properties/default_server"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,9 +135,7 @@
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"certificate": null,
|
||||
"access_list": null,
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
"access_list": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -67,6 +67,12 @@
|
||||
},
|
||||
"locations": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/locations"
|
||||
},
|
||||
"ssl_key_type": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/ssl_key_type"
|
||||
},
|
||||
"default_server": {
|
||||
"$ref": "../../../components/proxy-host-object.json#/properties/default_server"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,9 +120,7 @@
|
||||
"avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"access_list": null,
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
"access_list": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -114,9 +114,7 @@
|
||||
"avatar": "",
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"certificate": null,
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
"certificate": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -99,9 +99,7 @@
|
||||
"nickname": "Admin",
|
||||
"avatar": "",
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -129,9 +129,7 @@
|
||||
"roles": ["admin"]
|
||||
},
|
||||
"certificate": null,
|
||||
"access_list": null,
|
||||
"use_default_location": true,
|
||||
"ipv6": true
|
||||
"access_list": null
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -13,7 +13,8 @@
|
||||
"name": "settingID",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
"minLength": 1,
|
||||
"enum": ["default-site"]
|
||||
},
|
||||
"required": true,
|
||||
"description": "Setting ID",
|
||||
@ -31,10 +32,21 @@
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"value": {
|
||||
"$ref": "../../../components/setting-object.json#/properties/value"
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"enum": ["congratulations", "404", "444", "redirect", "html"]
|
||||
},
|
||||
"meta": {
|
||||
"$ref": "../../../components/setting-object.json#/properties/meta"
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"redirect": {
|
||||
"type": "string"
|
||||
},
|
||||
"html": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
auth_basic "Authorization required";
|
||||
auth_basic_user_file /data/access/{{ access_list_id }};
|
||||
|
||||
{% if access_list.pass_auth == 0 %}
|
||||
{% if access_list.pass_auth == 0 or access_list.pass_auth == true %}
|
||||
proxy_set_header Authorization "";
|
||||
{% endif %}
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
deny all;
|
||||
|
||||
# Access checks must...
|
||||
{% if access_list.satisfy_any == 1 %}
|
||||
{% if access_list.satisfy_any == 1 or access_list.satisfy_any == true %}
|
||||
satisfy any;
|
||||
{% else %}
|
||||
satisfy all;
|
||||
|
@ -1,15 +1,20 @@
|
||||
listen 80;
|
||||
listen 80{% if default_server == true %} default_server{% endif %};
|
||||
{% if ipv6 -%}
|
||||
listen [::]:80;
|
||||
listen [::]:80{% if default_server == true %} default_server{% endif %};
|
||||
{% else -%}
|
||||
#listen [::]:80;
|
||||
{% endif %}
|
||||
{% if certificate -%}
|
||||
listen 443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||
listen 443 ssl{% if default_server == true %} default_server{% endif %};
|
||||
{% if ipv6 -%}
|
||||
listen [::]:443 ssl{% if http2_support == 1 or http2_support == true %} http2{% endif %};
|
||||
listen [::]:443 ssl{% if default_server == true %} default_server{% endif %};
|
||||
{% else -%}
|
||||
#listen [::]:443;
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
server_name {{ domain_names | join: " " }};
|
||||
{% if http2_support == 1 or http2_support == true %}
|
||||
http2 on;
|
||||
{% else -%}
|
||||
http2 off;
|
||||
{% endif %}
|
@ -7,11 +7,7 @@
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
set $proxy_forward_scheme {{ forward_scheme }};
|
||||
set $proxy_server "{{ forward_host }}";
|
||||
set $proxy_port {{ forward_port }};
|
||||
|
||||
proxy_pass $proxy_forward_scheme://$proxy_server:$proxy_port{{ forward_path }};
|
||||
proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
|
||||
|
||||
{% include "_access.conf" %}
|
||||
{% include "_assets.conf" %}
|
||||
|
@ -830,9 +830,9 @@ crc32-stream@^4.0.2:
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
|
@ -53,9 +53,11 @@ COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager
|
||||
# Remove frontend service not required for prod, dev nginx config as well
|
||||
RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
|
||||
&& chmod 644 /etc/logrotate.d/nginx-proxy-manager
|
||||
COPY docker/start-container /usr/local/bin/start-container
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
VOLUME [ "/data" ]
|
||||
ENTRYPOINT [ "/init" ]
|
||||
ENTRYPOINT [ "start-container" ]
|
||||
|
||||
LABEL org.label-schema.schema-version="1.0" \
|
||||
org.label-schema.license="MIT" \
|
||||
|
@ -35,5 +35,8 @@ RUN rm -f /etc/nginx/conf.d/production.conf \
|
||||
COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
|
||||
COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
|
||||
|
||||
COPY start-container /usr/local/bin/start-container
|
||||
RUN chmod +x /usr/local/bin/start-container
|
||||
|
||||
EXPOSE 80 81 443
|
||||
ENTRYPOINT [ "/init" ]
|
||||
ENTRYPOINT [ "start-container" ]
|
||||
|
@ -1,7 +1,5 @@
|
||||
text = True
|
||||
non-interactive = True
|
||||
webroot-path = /data/letsencrypt-acme-challenge
|
||||
key-type = ecdsa
|
||||
elliptic-curve = secp384r1
|
||||
preferred-chain = ISRG Root X1
|
||||
server =
|
||||
|
@ -1,6 +1,4 @@
|
||||
text = True
|
||||
non-interactive = True
|
||||
webroot-path = /data/letsencrypt-acme-challenge
|
||||
key-type = ecdsa
|
||||
elliptic-curve = secp384r1
|
||||
preferred-chain = ISRG Root X1
|
||||
|
@ -1,4 +1,4 @@
|
||||
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
||||
location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|woff2|eot|ttf|svg|ico|css\.map|js\.map)$ {
|
||||
if_modified_since off;
|
||||
|
||||
# use the public cache
|
||||
|
@ -3,5 +3,7 @@ ssl_session_cache shared:SSL:50m;
|
||||
|
||||
# intermediate configuration. tweak to your needs.
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_ciphers "ALL:RC4-SHA:AES128-SHA:AES256-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:AES128-GCM-SHA256:RSA-AES256-CBC-SHA:RC4-MD5:DES-CBC3-SHA:AES256-SHA:RC4-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_ecdh_curve X25519:prime256v1:secp384r1;
|
||||
ssl_dhparam /etc/ssl/certs/dhparam.pem;
|
13
docker/start-container
Normal file
13
docker/start-container
Normal file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
FILE="/etc/ssl/certs/dhparam.pem"
|
||||
|
||||
if [ ! -f "$FILE" ]; then
|
||||
echo "the $FILE does not exist, creating..."
|
||||
openssl dhparam -out "$FILE" 2048
|
||||
else
|
||||
echo "the $FILE already exists, skipping..."
|
||||
fi
|
||||
|
||||
echo "run default script"
|
||||
exec /init
|
@ -50,7 +50,6 @@ networks:
|
||||
Let's look at a Portainer example:
|
||||
|
||||
```yml
|
||||
version: '3.8'
|
||||
services:
|
||||
|
||||
portainer:
|
||||
@ -92,8 +91,6 @@ This image supports the use of Docker secrets to import from files and keep sens
|
||||
You can set any environment variable from a file by appending `__FILE` (double-underscore FILE) to the environmental variable name.
|
||||
|
||||
```yml
|
||||
version: '3.8'
|
||||
|
||||
secrets:
|
||||
# Secrets are single-line text files where the sole content is the secret
|
||||
# Paths in this example assume that secrets are kept in local folder called ".secrets"
|
||||
|
@ -9,7 +9,6 @@ outline: deep
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yml
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: 'jc21/nginx-proxy-manager:latest'
|
||||
@ -55,7 +54,6 @@ are going to use.
|
||||
Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container:
|
||||
|
||||
```yml
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: 'jc21/nginx-proxy-manager:latest'
|
||||
@ -137,5 +135,13 @@ Email: admin@example.com
|
||||
Password: changeme
|
||||
```
|
||||
|
||||
Immediately after logging in with this default user you will be asked to modify your details and change your password.
|
||||
Immediately after logging in with this default user you will be asked to modify your details and change your password. You can change defaults with:
|
||||
|
||||
|
||||
```
|
||||
environment:
|
||||
INITIAL_ADMIN_EMAIL: my@example.com
|
||||
INITIAL_ADMIN_PASSWORD: mypassword1
|
||||
```
|
||||
|
||||
|
||||
|
@ -50,8 +50,7 @@ module.exports = Mn.View.extend({
|
||||
onRender: function () {
|
||||
let view = this;
|
||||
|
||||
if (typeof view.stats.hosts === 'undefined') {
|
||||
Api.Reports.getHostStats()
|
||||
Api.Reports.getHostStats()
|
||||
.then(response => {
|
||||
if (!view.isDestroyed()) {
|
||||
view.stats.hosts = response;
|
||||
@ -61,7 +60,6 @@ module.exports = Mn.View.extend({
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -72,7 +72,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="allow_websocket_upgrade" value="1"<%- allow_websocket_upgrade ? ' checked' : '' %>>
|
||||
@ -81,6 +81,15 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="default_server" value="1"<%- default_server ? ' checked' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description"><%- i18n('proxy-hosts', 'default-server') %></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
@ -105,6 +114,15 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label"><%- i18n('all-hosts', 'ssl-key-type') %></label>
|
||||
<select name="ssl_key_type" class="form-control custom-select">
|
||||
<option value="ecdsa" data-data="{"id":"ecdsa"}" <%- ssl_key_type == 'ecdsa' ? 'selected' : '' %>>ECDSA</option>
|
||||
<option value="rsa" data-data="{"id":"rsa"}" <%- ssl_key_type == 'rsa' ? 'selected' : '' %>>RSA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
|
@ -167,6 +167,7 @@ module.exports = Mn.View.extend({
|
||||
data.hsts_enabled = !!data.hsts_enabled;
|
||||
data.hsts_subdomains = !!data.hsts_subdomains;
|
||||
data.ssl_forced = !!data.ssl_forced;
|
||||
data.default_server = !!data.default_server;
|
||||
|
||||
if (typeof data.meta === 'undefined') data.meta = {};
|
||||
data.meta.letsencrypt_agree = data.meta.letsencrypt_agree == 1;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<td class="text-center">
|
||||
<div class="avatar d-block" style="background-image: url(<%- owner.avatar || '/images/default-avatar.jpg' %>)" title="Owned by <%- owner.name %>">
|
||||
<span class="avatar-status <%- owner.is_disabled ? 'bg-red' : 'bg-green' %>"></span>
|
||||
<div class="avatar d-block" style="background-image: url(<%- (owner && owner.avatar) || '/images/default-avatar.jpg' %>)" title="Owned by <%- (owner && owner.name) || 'a deleted user' %>">
|
||||
<span class="avatar-status <%- owner && !owner.is_disabled ? 'bg-green' : 'bg-red' %>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><%- i18n('users', 'form-title', {id: id}) %></h5>
|
||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<form>
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><%- i18n('users', 'form-title', {id: id}) %></h5>
|
||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
@ -49,10 +49,10 @@
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
|
||||
<button type="button" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal"><%- i18n('str', 'cancel') %></button>
|
||||
<button type="submit" class="btn btn-teal save"><%- i18n('str', 'save') %></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@ module.exports = Mn.View.extend({
|
||||
|
||||
events: {
|
||||
|
||||
'click @ui.save': function (e) {
|
||||
'submit @ui.form': function (e) {
|
||||
e.preventDefault();
|
||||
this.ui.error.hide();
|
||||
let view = this;
|
||||
|
@ -77,6 +77,7 @@
|
||||
"block-exploits": "Block Common Exploits",
|
||||
"caching-enabled": "Cache Assets",
|
||||
"ssl-certificate": "SSL Certificate",
|
||||
"ssl-key-type": "SSL Key Type",
|
||||
"none": "None",
|
||||
"new-cert": "Request a new SSL Certificate",
|
||||
"with-le": "with Let's Encrypt",
|
||||
@ -131,6 +132,7 @@
|
||||
"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",
|
||||
"default-server": "Default Server",
|
||||
"ignore-invalid-upstream-ssl": "Ignore Invalid SSL",
|
||||
"custom-forward-host-help": "Add a path for sub-folder forwarding.\nExample: 203.0.113.25/path/",
|
||||
"search": "Search Host…"
|
||||
|
@ -10,6 +10,8 @@ const model = Backbone.Model.extend({
|
||||
modified_on: null,
|
||||
domain_names: [],
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
http2_support: false,
|
||||
hsts_enabled: false,
|
||||
|
@ -14,6 +14,8 @@ const model = Backbone.Model.extend({
|
||||
forward_port: null,
|
||||
access_list_id: 0,
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
|
@ -14,6 +14,8 @@ const model = Backbone.Model.extend({
|
||||
forward_domain_name: '',
|
||||
preserve_path: true,
|
||||
certificate_id: 0,
|
||||
ssl_key_type: 'ecdsa',
|
||||
default_server: false,
|
||||
ssl_forced: false,
|
||||
hsts_enabled: false,
|
||||
hsts_subdomains: false,
|
||||
|
@ -2648,9 +2648,9 @@ electron-to-chromium@^1.3.47:
|
||||
integrity sha512-67V62Z4CFOiAtox+o+tosGfVk0QX4DJgH609tjT8QymbJZVAI/jWnAthnr8c5hnRNziIRwkc9EMQYejiVz3/9Q==
|
||||
|
||||
elliptic@^6.5.3, elliptic@^6.5.4:
|
||||
version "6.5.7"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
|
||||
integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
|
||||
version "6.6.0"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
|
||||
integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
|
||||
dependencies:
|
||||
bn.js "^4.11.9"
|
||||
brorand "^1.1.0"
|
||||
|
@ -7,7 +7,7 @@
|
||||
"credentials": "dns_acmedns_api_url = http://acmedns-server/\ndns_acmedns_registration_file = /data/acme-registration.json",
|
||||
"full_plugin_name": "dns-acmedns"
|
||||
},
|
||||
"active24":{
|
||||
"active24":{
|
||||
"name": "Active24",
|
||||
"package_name": "certbot-dns-active24",
|
||||
"version": "~=1.5.1",
|
||||
@ -303,6 +303,14 @@
|
||||
"credentials": "dns_joker_username = <Dynamic DNS Authentication Username>\ndns_joker_password = <Dynamic DNS Authentication Password>\ndns_joker_domain = <Dynamic DNS Domain>",
|
||||
"full_plugin_name": "dns-joker"
|
||||
},
|
||||
"leaseweb": {
|
||||
"name": "LeaseWeb",
|
||||
"package_name": "certbot-dns-leaseweb",
|
||||
"version": "~=1.0.1",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_leaseweb_api_token = 01234556789",
|
||||
"full_plugin_name": "dns-leaseweb"
|
||||
},
|
||||
"linode": {
|
||||
"name": "Linode",
|
||||
"package_name": "certbot-dns-linode",
|
||||
@ -424,13 +432,13 @@
|
||||
"full_plugin_name": "dns-rfc2136"
|
||||
},
|
||||
"rockenstein": {
|
||||
"name": "rockenstein AG",
|
||||
"package_name": "certbot-dns-rockenstein",
|
||||
"version": "~=1.0.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_rockenstein_token=<token>",
|
||||
"full_plugin_name": "dns-rockenstein"
|
||||
},
|
||||
"name": "rockenstein AG",
|
||||
"package_name": "certbot-dns-rockenstein",
|
||||
"version": "~=1.0.0",
|
||||
"dependencies": "",
|
||||
"credentials": "dns_rockenstein_token=<token>",
|
||||
"full_plugin_name": "dns-rockenstein"
|
||||
},
|
||||
"route53": {
|
||||
"name": "Route 53 (Amazon)",
|
||||
"package_name": "certbot-dns-route53",
|
||||
|
@ -9,7 +9,7 @@ describe('Full Certificate Provisions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.only('Should be able to create new http certificate', function() {
|
||||
it('Should be able to create new http certificate', function() {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/nginx/certificates',
|
||||
@ -35,7 +35,7 @@ describe('Full Certificate Provisions', () => {
|
||||
it('Should be able to create new DNS certificate with Powerdns', function() {
|
||||
cy.task('backendApiPost', {
|
||||
token: token,
|
||||
path: '/api/certificates',
|
||||
path: '/api/nginx/certificates',
|
||||
data: {
|
||||
domain_names: [
|
||||
'website2.example.com'
|
||||
@ -45,7 +45,8 @@ describe('Full Certificate Provisions', () => {
|
||||
dns_challenge: true,
|
||||
dns_provider: 'powerdns',
|
||||
dns_provider_credentials: 'dns_powerdns_api_url = http://ns1.pdns:8081\r\ndns_powerdns_api_key = npm',
|
||||
letsencrypt_agree: true
|
||||
letsencrypt_agree: true,
|
||||
propagation_seconds: 5,
|
||||
},
|
||||
provider: 'letsencrypt'
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Hosts endpoints', () => {
|
||||
describe('Proxy Hosts endpoints', () => {
|
||||
let token;
|
||||
|
||||
before(() => {
|
124
test/cypress/e2e/api/Settings.cy.js
Normal file
124
test/cypress/e2e/api/Settings.cy.js
Normal file
@ -0,0 +1,124 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
describe('Settings endpoints', () => {
|
||||
let token;
|
||||
|
||||
before(() => {
|
||||
cy.getToken().then((tok) => {
|
||||
token = tok;
|
||||
});
|
||||
});
|
||||
|
||||
it('Get all settings', function() {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/settings',
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('get', 200, '/settings', data);
|
||||
expect(data.length).to.be.greaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('Get default-site setting', function() {
|
||||
cy.task('backendApiGet', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('get', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site congratulations', function() {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
data: {
|
||||
value: 'congratulations',
|
||||
},
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
expect(data).to.have.property('value');
|
||||
expect(data.value).to.be.equal('congratulations');
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site 404', function() {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
data: {
|
||||
value: '404',
|
||||
},
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
expect(data).to.have.property('value');
|
||||
expect(data.value).to.be.equal('404');
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site 444', function() {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
data: {
|
||||
value: '444',
|
||||
},
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
expect(data).to.have.property('value');
|
||||
expect(data.value).to.be.equal('444');
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site redirect', function() {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
data: {
|
||||
value: 'redirect',
|
||||
meta: {
|
||||
redirect: 'https://www.google.com',
|
||||
},
|
||||
},
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
expect(data).to.have.property('value');
|
||||
expect(data.value).to.be.equal('redirect');
|
||||
expect(data).to.have.property('meta');
|
||||
expect(data.meta).to.have.property('redirect');
|
||||
expect(data.meta.redirect).to.be.equal('https://www.google.com');
|
||||
});
|
||||
});
|
||||
|
||||
it('Default Site html', function() {
|
||||
cy.task('backendApiPut', {
|
||||
token: token,
|
||||
path: '/api/settings/default-site',
|
||||
data: {
|
||||
value: 'html',
|
||||
meta: {
|
||||
html: '<p>hello world</p>'
|
||||
},
|
||||
},
|
||||
}).then((data) => {
|
||||
cy.validateSwaggerSchema('put', 200, '/settings/{settingID}', data);
|
||||
expect(data).to.have.property('id');
|
||||
expect(data.id).to.be.equal('default-site');
|
||||
expect(data).to.have.property('value');
|
||||
expect(data.value).to.be.equal('html');
|
||||
expect(data).to.have.property('meta');
|
||||
expect(data.meta).to.have.property('html');
|
||||
expect(data.meta.html).to.be.equal('<p>hello world</p>');
|
||||
});
|
||||
});
|
||||
});
|
@ -7,7 +7,7 @@ const BackendApi = function(config, token) {
|
||||
|
||||
this.axios = axios.create({
|
||||
baseURL: config.baseUrl,
|
||||
timeout: 60000,
|
||||
timeout: 90000,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -132,9 +132,9 @@
|
||||
integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
|
||||
|
||||
"@eslint/plugin-kit@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d"
|
||||
integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz#812980a6a41ecf3a8341719f92a6d1e784a2e0e8"
|
||||
integrity sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==
|
||||
dependencies:
|
||||
levn "^0.4.1"
|
||||
|
||||
@ -628,9 +628,9 @@ core-util-is@1.0.2:
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
|
Reference in New Issue
Block a user