diff --git a/.version b/.version
index b7b616779..2e12e4762 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-2.9.13
+2.9.14
diff --git a/Jenkinsfile b/Jenkinsfile
index a0f21e109..860c88d0e 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -62,6 +62,7 @@ pipeline {
stage('Backend') {
steps {
echo 'Checking Syntax ...'
+ sh 'docker pull node:latest'
// See: https://github.com/yarnpkg/yarn/issues/3254
sh '''docker run --rm \\
-v "$(pwd)/backend:/app" \\
diff --git a/README.md b/README.md
index 7d03016a4..64c7c7ab6 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-
+
@@ -110,9 +110,9 @@ Special thanks to the following contributors:
diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js
index 55f55d080..351b9b3de 100644
--- a/backend/internal/certificate.js
+++ b/backend/internal/certificate.js
@@ -171,6 +171,7 @@ const internalCertificate = {
// 3. Generate the LE config
return internalNginx.generateLetsEncryptRequestConfig(certificate)
.then(internalNginx.reload)
+ .then(async() => await new Promise((r) => setTimeout(r, 5000)))
.then(() => {
// 4. Request cert
return internalCertificate.requestLetsEncryptSsl(certificate);
@@ -870,8 +871,10 @@ const internalCertificate = {
logger.info(`Requesting Let'sEncrypt certificates via ${dns_plugin.display_name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
const credentialsLocation = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
- const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
- const prepareCmd = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies;
+ // Escape single quotes and backslashes
+ const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
+ const credentialsCmd = 'mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\'';
+ const prepareCmd = 'pip install ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies;
// Whether the plugin has a ---credentials argument
const hasConfigArg = certificate.meta.dns_provider !== 'route53';
diff --git a/backend/internal/ip_ranges.js b/backend/internal/ip_ranges.js
index edf5c3a01..40e63ea40 100644
--- a/backend/internal/ip_ranges.js
+++ b/backend/internal/ip_ranges.js
@@ -9,6 +9,9 @@ const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
+const regIpV4 = /^(\d+\.?){4}\/\d+/;
+const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
+
const internalIpRanges = {
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
@@ -74,14 +77,14 @@ const internalIpRanges = {
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
})
.then((cloudfare_data) => {
- let items = cloudfare_data.split('\n');
+ let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
ip_ranges = [... ip_ranges, ... items];
})
.then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
})
.then((cloudfare_data) => {
- let items = cloudfare_data.split('\n');
+ let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
ip_ranges = [... ip_ranges, ... items];
})
.then(() => {
diff --git a/backend/setup.js b/backend/setup.js
index 41436c8f4..47fd1e7b0 100644
--- a/backend/setup.js
+++ b/backend/setup.js
@@ -181,7 +181,9 @@ const setupCertbotPlugins = () => {
// Make sure credentials file exists
const credentials_loc = '/etc/letsencrypt/credentials/credentials-' + certificate.id;
- const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + certificate.meta.dns_provider_credentials.replace('\'', '\\\'') + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
+ // Escape single quotes and backslashes
+ const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
+ const credentials_cmd = '[ -f \'' + credentials_loc + '\' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentials_loc + '\' && chmod 600 \'' + credentials_loc + '\'; }';
promises.push(utils.exec(credentials_cmd));
}
});
diff --git a/backend/templates/default.conf b/backend/templates/default.conf
index 5196f2854..ec68530ca 100644
--- a/backend/templates/default.conf
+++ b/backend/templates/default.conf
@@ -7,9 +7,9 @@
server {
listen 80 default;
{% if ipv6 -%}
- listen [::]:80;
+ listen [::]:80 default;
{% else -%}
- #listen [::]:80;
+ #listen [::]:80 default;
{% endif %}
server_name default-host.localhost;
access_log /data/logs/default-host_access.log combined;
diff --git a/docker/rootfs/etc/nginx/conf.d/default.conf b/docker/rootfs/etc/nginx/conf.d/default.conf
index 81d6ae488..37d316db5 100644
--- a/docker/rootfs/etc/nginx/conf.d/default.conf
+++ b/docker/rootfs/etc/nginx/conf.d/default.conf
@@ -30,7 +30,7 @@ server {
set $port "443";
server_name localhost;
- access_log /data/logs/fallback-access.log standard;
+ access_log /data/logs/fallback_access.log standard;
error_log /dev/null crit;
ssl_certificate /data/nginx/dummycert.pem;
ssl_certificate_key /data/nginx/dummykey.pem;
diff --git a/docker/rootfs/etc/nginx/conf.d/include/proxy.conf b/docker/rootfs/etc/nginx/conf.d/include/proxy.conf
index fcaaf0038..e2cb451ef 100644
--- a/docker/rootfs/etc/nginx/conf.d/include/proxy.conf
+++ b/docker/rootfs/etc/nginx/conf.d/include/proxy.conf
@@ -2,6 +2,8 @@ add_header X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
+proxy_set_header X-Forwarded-Host $host;
+proxy_set_header X-Forwarded-Port $port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass $forward_scheme://$server:$port$request_uri;
diff --git a/docker/rootfs/etc/services.d/nginx/run b/docker/rootfs/etc/services.d/nginx/run
index fe6ea44b3..508b7d733 100755
--- a/docker/rootfs/etc/services.d/nginx/run
+++ b/docker/rootfs/etc/services.d/nginx/run
@@ -24,7 +24,7 @@ chown root /tmp/nginx
# Dynamically generate resolvers file, if resolver is IPv6, enclose in `[]`
# thanks @tfmm
-echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" {print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
+echo resolver "$(awk 'BEGIN{ORS=" "} $1=="nameserver" { sub(/%.*$/,"",$2); print ($2 ~ ":")? "["$2"]": $2}' /etc/resolv.conf);" > /etc/nginx/conf.d/include/resolvers.conf
# Generate dummy self-signed certificate.
if [ ! -f /data/nginx/dummycert.pem ] || [ ! -f /data/nginx/dummykey.pem ]
diff --git a/docs/faq/README.md b/docs/faq/README.md
index 1703e7055..cf739ead1 100644
--- a/docs/faq/README.md
+++ b/docs/faq/README.md
@@ -21,3 +21,6 @@ Your best bet is to ask the [Reddit community for support](https://www.reddit.co
Gitter is best left for anyone contributing to the project to ask for help about internals, code reviews etc.
+## When adding username and password access control to a proxy host, I can no longer login into the app.
+
+Having an Access Control List (ACL) with username and password requires the browser to always send this username and password in the `Authorization` header on each request. If your proxied app also requires authentication (like Nginx Proxy Manager itself), most likely the app will also use the `Authorization` header to transmit this information, as this is the standardized header meant for this kind of information. However having multiples of the same headers is not allowed in the [internet standard](https://www.rfc-editor.org/rfc/rfc7230#section-3.2.2) and almost all apps do not support multiple values in the `Authorization` header. Hence one of the two logins will be broken. This can only be fixed by either removing one of the logins or by changing the app to use other non-standard headers for authorization.
\ No newline at end of file
diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js
index 56b31cf2a..a56c3f8e0 100644
--- a/frontend/js/app/nginx/certificates/form.js
+++ b/frontend/js/app/nginx/certificates/form.js
@@ -278,9 +278,11 @@ module.exports = Mn.View.extend({
this.ui.credentials_file_content.hide();
this.ui.loader_content.hide();
this.ui.le_error_info.hide();
- const domainNames = this.ui.domain_names[0].value.split(',');
- if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) {
- this.ui.test_domains_button.prop('disabled', true);
+ if (this.ui.domain_names[0]) {
+ const domainNames = this.ui.domain_names[0].value.split(',');
+ if (!domainNames || domainNames.length === 0 || (domainNames.length === 1 && domainNames[0] === "")) {
+ this.ui.test_domains_button.prop('disabled', true);
+ }
}
},
diff --git a/global/certbot-dns-plugins.js b/global/certbot-dns-plugins.js
index 398291352..7f7d8c327 100644
--- a/global/certbot-dns-plugins.js
+++ b/global/certbot-dns-plugins.js
@@ -67,11 +67,11 @@ dns_azure_zone2 = example.org:/subscriptions/99800903-fb14-4992-9aff-12eaf274462
},
//####################################################//
cloudflare: {
- display_name: 'Cloudflare',
- package_name: 'certbot-dns-cloudflare',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: 'cloudflare',
- credentials: `# Cloudflare API token
+ display_name: 'Cloudflare',
+ package_name: 'certbot-dns-cloudflare',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: 'cloudflare',
+ credentials: `# Cloudflare API token
dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`,
full_plugin_name: 'dns-cloudflare',
},
@@ -93,11 +93,11 @@ dns_cloudflare_api_token = 0123456789abcdef0123456789abcdef01234567`,
},
//####################################################//
cloudxns: {
- display_name: 'CloudXNS',
- package_name: 'certbot-dns-cloudxns',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef
+ display_name: 'CloudXNS',
+ package_name: 'certbot-dns-cloudxns',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `dns_cloudxns_api_key = 1234567890abcdef1234567890abcdef
dns_cloudxns_secret_key = 1122334455667788`,
full_plugin_name: 'dns-cloudxns',
},
@@ -143,12 +143,12 @@ dns_desec_endpoint = https://desec.io/api/v1/`,
},
//####################################################//
digitalocean: {
- display_name: 'DigitalOcean',
- package_name: 'certbot-dns-digitalocean',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: 'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff',
- full_plugin_name: 'dns-digitalocean',
+ display_name: 'DigitalOcean',
+ package_name: 'certbot-dns-digitalocean',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: 'dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff',
+ full_plugin_name: 'dns-digitalocean',
},
//####################################################//
directadmin: {
@@ -163,20 +163,20 @@ directadmin_password = aSuperStrongPassword`,
},
//####################################################//
dnsimple: {
- display_name: 'DNSimple',
- package_name: 'certbot-dns-dnsimple',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: 'dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw',
- full_plugin_name: 'dns-dnsimple',
+ display_name: 'DNSimple',
+ package_name: 'certbot-dns-dnsimple',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: 'dns_dnsimple_token = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw',
+ full_plugin_name: 'dns-dnsimple',
},
//####################################################//
dnsmadeeasy: {
- display_name: 'DNS Made Easy',
- package_name: 'certbot-dns-dnsmadeeasy',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a
+ display_name: 'DNS Made Easy',
+ package_name: 'certbot-dns-dnsmadeeasy',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `dns_dnsmadeeasy_api_key = 1c1a3c91-4770-4ce7-96f4-54c0eb0e457a
dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`,
full_plugin_name: 'dns-dnsmadeeasy',
},
@@ -186,8 +186,8 @@ dns_dnsmadeeasy_secret_key = c9b5625f-9834-4ff8-baba-4ed5f32cae55`,
package_name: 'certbot-dns-dnspod',
version_requirement: '~=0.1.0',
dependencies: '',
- credentials: `dns_dnspod_email = "DNSPOD-API-REQUIRES-A-VALID-EMAIL"
-dns_dnspod_api_token = "DNSPOD-API-TOKEN"`,
+ credentials: `dns_dnspod_email = "email@example.com"
+dns_dnspod_api_token = "id,key"`,
full_plugin_name: 'dns-dnspod',
},
//####################################################//
@@ -235,11 +235,11 @@ dns_godaddy_key = abcdef0123456789abcdef01234567abcdef0123`,
},
//####################################################//
google: {
- display_name: 'Google',
- package_name: 'certbot-dns-google',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `{
+ display_name: 'Google',
+ package_name: 'certbot-dns-google',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `{
"type": "service_account",
...
}`,
@@ -319,11 +319,11 @@ dns_joker_domain = `,
},
//####################################################//
linode: {
- display_name: 'Linode',
- package_name: 'certbot-dns-linode',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64
+ display_name: 'Linode',
+ package_name: 'certbot-dns-linode',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `dns_linode_key = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ64
dns_linode_version = [|3|4]`,
full_plugin_name: 'dns-linode',
},
@@ -339,11 +339,11 @@ dns_loopia_password = abcdef0123456789abcdef01234567abcdef0123`,
},
//####################################################//
luadns: {
- display_name: 'LuaDNS',
- package_name: 'certbot-dns-luadns',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `dns_luadns_email = user@example.com
+ display_name: 'LuaDNS',
+ package_name: 'certbot-dns-luadns',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `dns_luadns_email = user@example.com
dns_luadns_token = 0123456789abcdef0123456789abcdef`,
full_plugin_name: 'dns-luadns',
},
@@ -369,12 +369,12 @@ dns_netcup_api_password = abcdef0123456789abcdef01234567abcdef0123`,
},
//####################################################//
nsone: {
- display_name: 'NS1',
- package_name: 'certbot-dns-nsone',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: 'dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw',
- full_plugin_name: 'dns-nsone',
+ display_name: 'NS1',
+ package_name: 'certbot-dns-nsone',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: 'dns_nsone_api_key = MDAwMDAwMDAwMDAwMDAw',
+ full_plugin_name: 'dns-nsone',
},
//####################################################//
oci: {
@@ -392,11 +392,11 @@ key_file = ~/.oci/oci_api_key.pem`,
},
//####################################################//
ovh: {
- display_name: 'OVH',
- package_name: 'certbot-dns-ovh',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `dns_ovh_endpoint = ovh-eu
+ display_name: 'OVH',
+ package_name: 'certbot-dns-ovh',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `dns_ovh_endpoint = ovh-eu
dns_ovh_application_key = MDAwMDAwMDAwMDAw
dns_ovh_application_secret = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
dns_ovh_consumer_key = MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw`,
@@ -434,11 +434,11 @@ certbot_regru:dns_password=password`,
},
//####################################################//
rfc2136: {
- display_name: 'RFC 2136',
- package_name: 'certbot-dns-rfc2136',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `# Target DNS server
+ display_name: 'RFC 2136',
+ package_name: 'certbot-dns-rfc2136',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `# Target DNS server
dns_rfc2136_server = 192.0.2.1
# Target DNS port
dns_rfc2136_port = 53
@@ -452,11 +452,11 @@ dns_rfc2136_algorithm = HMAC-SHA512`,
},
//####################################################//
route53: {
- display_name: 'Route 53 (Amazon)',
- package_name: 'certbot-dns-route53',
- // version_requirement: '', // Official plugin, no version requirement
- dependencies: '',
- credentials: `[default]
+ display_name: 'Route 53 (Amazon)',
+ package_name: 'certbot-dns-route53',
+ version_requirement: '==$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')', // official plugin, use certbot version
+ dependencies: '',
+ credentials: `[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY`,
full_plugin_name: 'dns-route53',
@@ -472,6 +472,16 @@ dns_transip_key_file = /etc/letsencrypt/transip-rsa.key`,
full_plugin_name: 'dns-transip',
},
//####################################################//
+ tencentcloud: {
+ display_name: 'Tencent Cloud',
+ package_name: 'certbot-dns-tencentcloud',
+ version_requirement: '~=2.0.0',
+ dependencies: '',
+ credentials: `dns_tencentcloud_secret_id = TENCENT_CLOUD_SECRET_ID
+dns_tencentcloud_secret_key = TENCENT_CLOUD_SECRET_KEY`,
+ full_plugin_name: 'dns-tencentcloud',
+ },
+ //####################################################//
vultr: {
display_name: 'Vultr',
package_name: 'certbot-dns-vultr',