diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 486f2b4d..b35bd581 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -16,7 +16,7 @@ const internalAuditLog = require('./audit-log'); const internalNginx = require('./nginx'); const certbotCommand = 'certbot'; -const certbotArgs = ['--logs-dir', '/tmp/certbot-log', '--work-dir', '/tmp/certbot-work', '--config-dir', '/data/tls/certbot', '--config', '/etc/certbot.ini', '--agree-tos', '--non-interactive', '--no-eff-email', '--register-unsafely-without-email', ...(process.env.ACME_MUST_STAPLE === 'false' ? [] : ['--must-staple']), ...(process.env.ACME_SERVER_TLS_VERIFY === 'false' ? ['--no-verify-ssl'] : [])]; +const certbotArgs = ['--logs-dir', '/tmp/certbot-log', '--work-dir', '/tmp/certbot-work', '--config-dir', '/data/tls/certbot', '--config', '/etc/certbot.ini', '--agree-tos', '--non-interactive', '--no-eff-email', '--register-unsafely-without-email', ...(process.env.ACME_SERVER_TLS_VERIFY === 'false' ? ['--no-verify-ssl'] : [])]; function omissions() { return ['is_deleted', 'owner.is_deleted']; @@ -42,7 +42,7 @@ const internalCertificate = { logger.info('Renewing TLS certs close to expiry...'); return utils - .execFile(certbotCommand, [...certbotArgs, 'renew', '--quiet', '--no-random-sleep-on-renew']) + .execFile(certbotCommand, [...certbotArgs, 'renew', '--server', process.env.ACME_SERVER, '--quiet', '--no-random-sleep-on-renew']) .then((result) => { if (result) { logger.info('Renew Result: ' + result); @@ -761,7 +761,7 @@ const internalCertificate = { requestCertbot: (certificate) => { logger.info('Requesting Certbot certificates for Cert #' + certificate.id + ': ' + certificate.domain_names.join(', ')); - return utils.execFile(certbotCommand, [...certbotArgs, 'certonly', '--cert-name', `npm-${certificate.id}`, '--domains', `${certificate.domain_names.join(',')}`, '--server', `${process.env.ACME_SERVER}`, '--authenticator', 'webroot', '--webroot-path', '/tmp/acme-challenge']).then((result) => { + return utils.execFile(certbotCommand, [...certbotArgs, 'certonly', '--cert-name', `npm-${certificate.id}`, '--domains', certificate.domain_names.join(','), '--server', process.env.ACME_SERVER, '--authenticator', 'webroot', '--webroot-path', '/tmp/acme-challenge']).then((result) => { logger.success(result); return result; }); @@ -787,7 +787,7 @@ const internalCertificate = { fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, { mode: 0o600 }); try { - const result = await utils.execFile(certbotCommand, [...certbotArgs, 'certonly', '--cert-name', `npm-${certificate.id}`, '--domains', `${certificate.domain_names.join(',')}`, '--server', `${process.env.ACME_SERVER}`, '--authenticator', dnsPlugin.full_plugin_name, `--${dnsPlugin.full_plugin_name}-credentials`, credentialsLocation]); + const result = await utils.execFile(certbotCommand, [...certbotArgs, 'certonly', '--cert-name', `npm-${certificate.id}`, '--domains', certificate.domain_names.join(','), '--server', process.env.ACME_SERVER}, '--authenticator', dnsPlugin.full_plugin_name, `--${dnsPlugin.full_plugin_name}-credentials`, credentialsLocation, ...(certificate.meta.propagation_seconds !== undefined ? [`--${dnsPlugin.full_plugin_name}-propagation-seconds`] : []), ...(certificate.meta.propagation_seconds !== undefined ? [certificate.meta.propagation_seconds] : [])]); logger.info(result); return result; } catch (err) { @@ -850,7 +850,7 @@ const internalCertificate = { const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); logger.info(revokeResult); - const renewResult = await utils.execFile(certbotCommand, [...certbotArgs, 'renew', '--force-renewal', '--cert-name', `npm-${certificate.id}`, '--no-random-sleep-on-renew']); + const renewResult = await utils.execFile(certbotCommand, [...certbotArgs, 'renew', '--server', process.env.ACME_SERVER, '--force-renewal', '--cert-name', `npm-${certificate.id}`, '--no-random-sleep-on-renew']); logger.info(renewResult); return renewResult; @@ -872,7 +872,7 @@ const internalCertificate = { const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); logger.info(revokeResult); - const renewResult = await utils.execFile(certbotCommand, [...certbotArgs, 'renew', '--force-renewal', '--cert-name', `npm-${certificate.id}`, '--no-random-sleep-on-renew']); + const renewResult = await utils.execFile(certbotCommand, [...certbotArgs, 'renew', '--server', process.env.ACME_SERVER, '--force-renewal', '--cert-name', `npm-${certificate.id}`, '--no-random-sleep-on-renew']); logger.info(renewResult); return renewResult; @@ -982,18 +982,18 @@ const internalCertificate = { } else if (result.error) { logger.info(`HTTP challenge test failed for domain ${domain} because error was returned: ${result.error.msg}`); return `other:${result.error.msg}`; - } else if (`${result.responsecode}` === '200' && result.htmlresponse === 'Success') { + } else if (result.responsecode === '200' && result.htmlresponse === 'Success') { // Server exists and has responded with the correct data return 'ok'; - } else if (`${result.responsecode}` === '200') { + } else if (result.responsecode === '200') { // Server exists but has responded with wrong data logger.info(`HTTP challenge test failed for domain ${domain} because of invalid returned data:`, result.htmlresponse); return 'wrong-data'; - } else if (`${result.responsecode}` === '404') { + } else if (result.responsecode === '404') { // Server exists but responded with a 404 logger.info(`HTTP challenge test failed for domain ${domain} because code 404 was returned`); return '404'; - } else if (`${result.responsecode}` === '0' || (typeof result.reason === 'string' && result.reason.toLowerCase() === 'host unavailable')) { + } else if (result.responsecode === '0' || (typeof result.reason === 'string' && result.reason.toLowerCase() === 'host unavailable')) { // Server does not exist at domain logger.info(`HTTP challenge test failed for domain ${domain} the host was not found`); return 'no-host'; diff --git a/backend/templates/dead_host.conf b/backend/templates/dead_host.conf index f7e593c6..7c109915 100644 --- a/backend/templates/dead_host.conf +++ b/backend/templates/dead_host.conf @@ -15,8 +15,9 @@ include conf.d/include/always.conf; {%- if use_default_location %} location / { include conf.d/include/always.conf; - root /html/dead; - try_files $uri /index.html; + root /html/404deadpage; + error_page 404 /404deadpage.html; + return 404; } {%- endif %} diff --git a/backend/templates/default.conf b/backend/templates/default.conf index 365eb156..69c706e7 100644 --- a/backend/templates/default.conf +++ b/backend/templates/default.conf @@ -26,8 +26,9 @@ server { {%- if value == "404" %} location / { include conf.d/include/always.conf; - root /html/dead; - try_files $uri /index.html; + root /html/404deadpage; + error_page 404 /404deadpage.html; + return 404; } {%- endif %} diff --git a/compose.yaml b/compose.yaml index 749a7544..408bfd95 100644 --- a/compose.yaml +++ b/compose.yaml @@ -11,10 +11,10 @@ services: environment: - "TZ=your-timezone" # set timezone, required, set it to one of the values from the "TZ identifier" https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List - "ACME_EMAIL=your-email" # email address which should be used for acme, currently optional, may be required in the future, so I recommend you to enter your email here -# - "ACME_SERVER=https://acme.zerossl.com/v2/DV90" # acme server to use for NEW certificates, default is (currently, may change later) set to: https://acme-v02.api.letsencrypt.org/directory (letsencrypt) +# - "ACME_SERVER=https://dv.acme-v02.api.pki.goog/directory" # acme server to used when requesting/renewing certs using certbot, default is (currently, may change later) set to: https://acme-v02.api.letsencrypt.org/directory (letsencrypt) # - "ACME_EAB_KID=123456789abcdef" # Key Identifier for External Account Binding for the acme server # - "ACME_EAB_HMAC_KEY=123456789abcdef" # HMAC key for External Account Binding for the acme server -# - "ACME_MUST_STAPLE=false" # enables must-staple, default true, please only disable it if you get this error MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING in Firefox, see https://github.com/ZoeyVid/NPMplus/discussions/1249, after changing this option you need to recreate (not renew) your certs +# - "ACME_MUST_STAPLE=false" # enables must-staple, default true (will change soon, see https://github.com/ZoeyVid/NPMplus/discussions/1285), I recommend you to enable this if your CA supports it # - "ACME_SERVER_TLS_VERIFY=false" # enables checking if ACME_SERVER has a valid TLS cert, default true # - "PUID=1000" # set group id, default 0 (root) # - "PGID=1000" # set user id, default 0 (root), requires PUID diff --git a/frontend/js/app/nginx/certificates/form.ejs b/frontend/js/app/nginx/certificates/form.ejs index 0068a69f..8b020a9a 100644 --- a/frontend/js/app/nginx/certificates/form.ejs +++ b/frontend/js/app/nginx/certificates/form.ejs @@ -105,7 +105,6 @@ - diff --git a/frontend/js/app/nginx/dead/form.ejs b/frontend/js/app/nginx/dead/form.ejs index 78ce9294..84d54fb5 100644 --- a/frontend/js/app/nginx/dead/form.ejs +++ b/frontend/js/app/nginx/dead/form.ejs @@ -144,7 +144,6 @@ - diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index e0f104d1..7a730ba3 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -212,7 +212,6 @@ - diff --git a/frontend/js/app/nginx/redirection/form.ejs b/frontend/js/app/nginx/redirection/form.ejs index 2a3727c8..69ea417e 100644 --- a/frontend/js/app/nginx/redirection/form.ejs +++ b/frontend/js/app/nginx/redirection/form.ejs @@ -193,7 +193,6 @@ - diff --git a/frontend/js/i18n/de-lang.json b/frontend/js/i18n/de-lang.json index 59b12d84..39bfb983 100644 --- a/frontend/js/i18n/de-lang.json +++ b/frontend/js/i18n/de-lang.json @@ -52,7 +52,7 @@ "certificate": "Zertifikat", "created": "Erstellt {name}", "date": "Date", - "dead-host": "404 Host", + "dead-host": "Dead Host", "deleted": "Gelöscht {name}", "disabled": "Deaktiviert {name}", "empty": "Es gibt keine Protokolle.", @@ -100,15 +100,15 @@ "title": "Hallo {name}" }, "dead-hosts": { - "add": "404 Host hinzufügen", - "delete": "404 Host löschen", - "delete-confirm": "Sind Sie sicher, dass Sie diesen 404-Host löschen wollen?", - "empty": "Es gibt keine 404 Hosts", - "form-title": "{id, select, undefined{Neuer} other{Bearbeitung}} 404 Host", - "help-content": "Ein 404-Host ist einfach eine Host-Einrichtung, die eine 404-Seite anzeigt.\nDies kann nützlich sein, wenn Ihre Domain in Suchmaschinen gelistet ist und Sie eine schönere Fehlerseite bereitstellen wollen oder um den Suchindexierern mitzuteilen, dass die Domain-Seiten nicht mehr existieren.\nEin weiterer Vorteil dieses Hosts besteht darin, dass man die Logs der Zugriffe auf ihn verfolgen und die Verweiser einsehen kann.", - "help-title": "Was ist ein 404-Host?", + "add": "Dead Host hinzufügen", + "delete": "Dead Host löschen", + "delete-confirm": "Sind Sie sicher, dass Sie diesen Dead-Host löschen wollen?", + "empty": "Es gibt keine Dead Hosts", + "form-title": "{id, select, undefined{Neuer} other{Bearbeitung}} Dead Host", + "help-content": "Ein Dead-Host ist einfach eine Host-Einrichtung, die eine 404-Seite anzeigt.\nDies kann nützlich sein, wenn Ihre Domain in Suchmaschinen gelistet ist und Sie eine schönere Fehlerseite bereitstellen wollen oder um den Suchindexierern mitzuteilen, dass die Domain-Seiten nicht mehr existieren.\nEin weiterer Vorteil dieses Hosts besteht darin, dass man die Logs der Zugriffe auf ihn verfolgen und die Verweiser einsehen kann.", + "help-title": "Was ist ein Dead-Host?", "search": "Suche Host..", - "title": "404 Hosts" + "title": "Dead Hosts" }, "footer": { "copy-npm": " - © 2024 jc21.com NPM", @@ -177,7 +177,7 @@ }, "settings": { "default-site": "Standard-Seite", - "default-site-404": "404 Seite", + "default-site-404": "Dead Seite", "default-site-444": "Verbindung abbrechen - erlaubt nur certbot dns-challenge", "default-site-congratulations": "Glückwunsch-Seite", "default-site-description": "Was angezeigt werden soll, wenn Nginx einen unbekannten Host antrifft", @@ -256,7 +256,7 @@ "no-wildcard-without-dns": "Zertifikat kann nicht für Wildcard-Domains angefordert werden, wenn keine DNS-Challenge verwendet wird", "none": "Nur HTTP", "other": "Individuell", - "passphrase-protection-support-info": "Schlüsseldateien, die mit einer Passphrase geschützt sind, werden nicht unterstützt.", + "passphrase-protection-support-info": "Schlüsseldateien, die mit einer Passphrase geschützt sind, werden nicht unterstützt. OCSP Stapling wird bei Custom Zertifikaten nicht untersützt.", "processing-info": "Verarbeitung... Dies kann ein paar Minuten dauern.", "propagation-seconds": "Ausbreitung in Sekunden", "propagation-seconds-info": "Leer lassen, um den Standardwert des Plugins zu verwenden. Anzahl der Sekunden, die auf die DNS-Verbreitung gewartet werden soll.", diff --git a/frontend/js/i18n/en-lang.json b/frontend/js/i18n/en-lang.json index f3067010..09e41ce3 100644 --- a/frontend/js/i18n/en-lang.json +++ b/frontend/js/i18n/en-lang.json @@ -52,7 +52,7 @@ "certificate": "Certificate", "created": "Created {name}", "date": "Date", - "dead-host": "404 Host", + "dead-host": "Dead Host", "deleted": "Deleted {name}", "disabled": "Disabled {name}", "empty": "There are no logs.", @@ -100,15 +100,15 @@ "title": "Hi {name}" }, "dead-hosts": { - "add": "Add 404 Host", - "delete": "Delete 404 Host", - "delete-confirm": "Are you sure you want to delete this 404 Host?", - "empty": "There are no 404 Hosts", - "form-title": "{id, select, undefined{New} other{Edit}} 404 Host", - "help-content": "A 404 Host is simply a host setup that shows a 404 page.\nThis can be useful when your domain is listed in search engines and you want to provide a nicer error page or specifically to tell the search indexers that the domain pages no longer exist.\nAnother benefit of having this host is to track the logs for hits to it and view the referrers.", - "help-title": "What is a 404 Host?", + "add": "Add Dead Host", + "delete": "Delete Dead Host", + "delete-confirm": "Are you sure you want to delete this Dead Host?", + "empty": "There are no Dead Hosts", + "form-title": "{id, select, undefined{New} other{Edit}} Dead Host", + "help-content": "A Dead Host is simply a host setup that shows a 404 page.\nThis can be useful when your domain is listed in search engines and you want to provide a nicer error page or specifically to tell the search indexers that the domain pages no longer exist.\nAnother benefit of having this host is to track the logs for hits to it and view the referrers.", + "help-title": "What is a Dead Host?", "search": "Search Host…", - "title": "404 Hosts" + "title": "Dead Hosts" }, "footer": { "copy-npm": " - © 2024 jc21.com NPM", @@ -256,7 +256,7 @@ "no-wildcard-without-dns": "Cannot request Certificate for wildcard domains when not using DNS challenge", "none": "HTTP only", "other": "Custom", - "passphrase-protection-support-info": "Key files protected with a passphrase are not supported.", + "passphrase-protection-support-info": "Key files protected with a passphrase are not supported. OCSP Stapling is not supported on custom certificates.", "processing-info": "Processing... This might take a few minutes.", "propagation-seconds": "Propagation Seconds", "propagation-seconds-info": "Leave empty to use the plugins default value. Number of seconds to wait for DNS propagation.", diff --git a/rootfs/etc/certbot.ini b/rootfs/etc/certbot.ini index ab7d9d46..e773e096 100644 --- a/rootfs/etc/certbot.ini +++ b/rootfs/etc/certbot.ini @@ -3,3 +3,5 @@ key-type = ecdsa no-reuse-key = true rsa-key-size = 4096 elliptic-curve = secp384r1 + +must-staple = true diff --git a/rootfs/html/404deadpage/404deadpage.html b/rootfs/html/404deadpage/404deadpage.html new file mode 100644 index 00000000..2ca07316 --- /dev/null +++ b/rootfs/html/404deadpage/404deadpage.html @@ -0,0 +1,90 @@ + + +
+Powered by NPMplus
+ + diff --git a/rootfs/html/dead/index.html b/rootfs/html/dead/index.html index ec17f904..2ca07316 100644 --- a/rootfs/html/dead/index.html +++ b/rootfs/html/dead/index.html @@ -7,7 +7,7 @@ - + diff --git a/rootfs/usr/local/bin/start.sh b/rootfs/usr/local/bin/start.sh index cd9cd5e8..1668fe8c 100755 --- a/rootfs/usr/local/bin/start.sh +++ b/rootfs/usr/local/bin/start.sh @@ -355,6 +355,13 @@ fi +if [ "$ACME_MUST_STAPLE" = "true" ]; then + sed -i "s|must-staple = .*|must-staple = true|g" /etc/certbot.ini +else + sed -i "s|must-staple = .*|must-staple = false|g" /etc/certbot.ini +fi + + if [ "$PHP82" = "true" ]; then apk add --no-cache php82-fpm