diff --git a/Dockerfile b/Dockerfile index 655068cd3..82decaf65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -72,14 +72,14 @@ RUN apk upgrade --no-cache -a && \ sed -i "s|APPSEC_PROCESS_TIMEOUT=.*|APPSEC_PROCESS_TIMEOUT=10000|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf -FROM zoeyvid/nginx-quic:368-python +FROM zoeyvid/nginx-quic:371-python SHELL ["/bin/ash", "-eo", "pipefail", "-c"] -ARG CRS_VER=v4.9.0 +ARG CRS_VER=v4.10.0 COPY rootfs / COPY --from=strip-backend /app /app RUN apk upgrade --no-cache -a && \ - apk add --no-cache ca-certificates tzdata tini curl \ + apk add --no-cache ca-certificates tzdata tini curl util-linux-misc \ nodejs \ bash nano \ logrotate goaccess fcgi \ @@ -113,20 +113,20 @@ COPY --from=crowdsec /src/crowdsec-nginx-bouncer/lua-mod/templa COPY --from=crowdsec /src/crowdsec-nginx-bouncer/lua-mod/lib/crowdsec.lua /usr/local/nginx/lib/lua/crowdsec.lua COPY --from=crowdsec /src/crowdsec-nginx-bouncer/lua-mod/lib/plugins /usr/local/nginx/lib/lua/plugins COPY --from=frontend /app/dist /html/frontend -COPY --from=zoeyvid/certbot-docker:69 /usr/local /usr/local LABEL com.centurylinklabs.watchtower.monitor-only="true" -ENV NODE_ENV=production \ - NODE_CONFIG_DIR=/data/etc/npm \ - DB_SQLITE_FILE=/data/etc/npm/database.sqlite -ENV ACME_SERVER="https://acme-v02.api.letsencrypt.org/directory" \ - ACME_MUST_STAPLE=true \ +ENV NODE_ENV=production \ + TV=3 \ + ACME_SERVER="https://acme-v02.api.letsencrypt.org/directory" \ + ACME_MUST_STAPLE=false \ + ACME_OCSP_STAPLING=true \ + ACME_KEY_TYPE=ecdsa \ ACME_SERVER_TLS_VERIFY=true \ PUID=0 \ PGID=0 \ - NIBEP=48693 \ - GOAIWSP=48683 \ + NIBEP=48683 \ + GOAIWSP=48693 \ NPM_PORT=81 \ GOA_PORT=91 \ IPV4_BINDING=0.0.0.0 \ @@ -136,16 +136,19 @@ ENV ACME_SERVER="https://acme-v02.api.letsencrypt.org/directory" \ NPM_IPV6_BINDING=[::] \ GOA_IPV6_BINDING=[::] \ DISABLE_IPV6=false \ - NPM_DISABLE_IPV6=false \ - GOA_DISABLE_IPV6=false \ NPM_LISTEN_LOCALHOST=false \ GOA_LISTEN_LOCALHOST=false \ DEFAULT_CERT_ID=0 \ + HTTP_PORT=80 \ + HTTPS_PORT=443 \ DISABLE_HTTP=false \ DISABLE_H3_QUIC=false \ + NGINX_QUIC_BPF=false \ NGINX_ACCESS_LOG=false \ NGINX_LOG_NOT_FOUND=false \ NGINX_404_REDIRECT=false \ + NGINX_HSTS_SUBDMAINS=true \ + X_FRAME_OPTIONS=deny \ NGINX_DISABLE_PROXY_BUFFERING=false \ DISABLE_NGINX_BEAUTIFIER=false \ CLEAN=true \ @@ -158,7 +161,8 @@ ENV ACME_SERVER="https://acme-v02.api.letsencrypt.org/directory" \ GOA=false \ GOACLA="--agent-list --real-os --double-decode --anonymize-ip --anonymize-level=1 --keep-last=30 --with-output-resolver --no-query-string" \ PHP82=false \ - PHP83=false + PHP83=false \ + PHP84=false WORKDIR /app ENTRYPOINT ["tini", "--", "entrypoint.sh"] diff --git a/README.md b/README.md index 0d8b02b23..eac5db5ec 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,14 @@ # NPMplus -This project comes as a pre-built docker image that enables you to easily forward to your websites +This is an improved fork of the nginx-proxy-manager and comes as a pre-built docker image that enables you to easily forward to your websites running at home or otherwise, including free TLS, without having to know too much about Nginx or Certbot. - [Quick Setup](#quick-setup) -**Note: NO armv7, route53 and aws cloudfront ip ranges support.**
-**Note: Other Databases like MariaDB may work, but are unsupported.**
-**Note: watchtower does NOT update NPMplus, you need to do it yourself (it will only pull the image, but not update the container itself).**
-**Note: access.log/stream.log, logrotate and goaccess are NOT enabled by default bceuase of GDPR, you can enable them in the compose.yaml.**
- -**Note: add `net.ipv4.ip_unprivileged_port_start=0` at the end of `/etc/sysctl.conf` to support PUID/PGID in network mode host.**
-**Note: Don't forget to open Port 80 (tcp) and 443 (tcp AND udp, http3/quic needs udp) in your firewall (because of network mode host, you also need to open this ports in ufw, if you use ufw).**
-**Note: If you don't use network mode host, which I don't recommend, don't forget to also expose port 443/udp (http3/quic needs udp) and to enable IPv6 in Docker see step 1 and 2 [here](https://github.com/nextcloud/all-in-one/blob/main/docker-ipv6-support.md).**
-**MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING: please see/read/use the ACME_MUST_STAPLE env option of the compose.yaml**
- +**Note: no armv7, route53 and aws cloudfront ip ranges support.**
+**Note: other Databases like MariaDB/MySQL or PostgreSQL may work, but are unsupported and have no advantage over SQLite.**
+**Note: watchtower does not update NPMplus, you need to do it yourself (it will only pull the image, but will not redeploy the container itself).**
+**Note: remember to add your domain to the hsts preload list if you use security headers: https://hstspreload.org**
## Project Goal I created this project to fill a personal need to provide users with an easy way to accomplish reverse @@ -22,7 +16,7 @@ proxying hosts with TLS termination and it had to be so easy that a monkey could While there might be advanced options they are optional and the project should be as simple as possible so that the barrier for entry here is low. -## Features +## Upstream Features - Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io) - Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx @@ -37,17 +31,18 @@ so that the barrier for entry here is low. - Supports HTTP/3 (QUIC) protocol. - Supports CrowdSec IPS. Please see [here](https://github.com/ZoeyVid/NPMplus#crowdsec) to enable it. - goaccess included, see compose.yaml to enable, runs by default on https://:91 (nginx config from [here](https://github.com/xavier-hernandez/goaccess-for-nginxproxymanager/blob/main/resources/nginx/nginx.conf)) -- Supports ModSecurity, with coreruleset as an option. You can configure ModSecurity/coreruleset by editing the files in the `/opt/npm/etc/modsecurity` folder (no support from me, you need to write the rules yourself - for CRS I can try to help you). +- Supports ModSecurity, with coreruleset as an option. You can configure ModSecurity/coreruleset by editing the files in the `/opt/npm/etc/modsecurity` folder (no support from me, you need to write the rules yourself - for CoreRuleSet I can try to help you). + - By default NPMplus UI does not work when you proxy NPMplus through NPMplus and you have CoreRuleSet enabled, see below - ModSecurity by default blocks uploads of big files, you need to edit its config to fix this, but it can use a lot of resources to scan big files by ModSecurity - - ModSecurity overblocking (403 Error) with CRS? Please see [here](https://coreruleset.org/docs/concepts/false_positives_tuning) and edit the `/opt/npm/etc/modsecurity/crs-setup.conf` file. - - Try to whitelist the Content-Type you are sending (for example, `application/activity+json` for Mastodon and `application/dns-message` for DoH). - - Try to whitelist the HTTP request method you are using (for example, `PUT` is blocked by default, which also affects NPM). - - CRS plugins are supported, you can find a guide in this readme + - ModSecurity overblocking (403 Error) when using CoreRuleSet? Please see [here](https://coreruleset.org/docs/concepts/false_positives_tuning) and edit the `/opt/npm/etc/modsecurity/crs-setup.conf` file. + - Try to whitelist the Content-Type you are sending (for example, `application/activity+json` for Mastodon and `application/dns-message` for DoH). + - Try to whitelist the HTTP request method you are using (for example, `PUT` is blocked by default, which also blocks NPMplus UI). + - CoreRuleSet plugins are supported, you can find a guide in this readme - Darkmode button in the footer for comfortable viewing (CSS done by [@theraw](https://github.com/theraw)) - Fixes proxy to https origin when the origin only accepts TLSv1.3 - Only enables TLSv1.2 and TLSv1.3 protocols, also ML-KEM support - Faster creation of TLS certificates is achieved by eliminating unnecessary nginx reloads and configuration creations. -- Uses OCSP Stapling for enhanced security (manual certs not supported) +- Supports OCSP Stapling/Must-Staple for enhanced security (manual certs not supported, see compose.yaml for details) - Resolved dnspod plugin issue - To migrate manually, delete all dnspod certs and recreate them OR change the credentials file as per the template given [here](https://github.com/ZoeyVid/NPMplus/blob/develop/global/certbot-dns-plugins.js) - Smaller docker image with alpine-based distribution @@ -60,7 +55,7 @@ so that the barrier for entry here is low. - access.log is disabled by default, unified and moved to `/opt/npm/nginx/access.log` - Error Log written to console - `Server` response header hidden -- PHP 8.2/8.3 optional, with option to add extensions; available packages can added using envs in the compose file +- PHP optional, with option to add extensions; available packages can added using envs in the compose file, recommended to be used together with PUID/PGID - Allows different acme servers using env - Supports up to 99 domains per cert - Brotli compression can be enabled @@ -69,27 +64,27 @@ so that the barrier for entry here is low. - Automatic database vacuum (only sqlite) - Automatic cleaning of old invalid certbot certs (set CLEAN to true) - Password reset (only sqlite) using `docker exec -it npmplus password-reset.js USER_EMAIL PASSWORD` -- Supports TLS for MariaDB/MySQL; set `DB_MYSQL_TLS` env to true. Self-signed certificates can be uploaded to `/opt/npm/etc/npm/ca.crt` and `DB_MYSQL_CA` set to `/data/etc/npm/ca.crt` (not tested, unsupported) - multi lang support, if you want to add an language, see this commit as an example: https://github.com/ZoeyVid/NPMplus/commit/a026b42329f66b89fe1fbe5e6034df5d3fc2e11f (implementation based on [@lateautumn233](https://github.com/lateautumn233) fork) - See the compose file for all available options - many env options optimized for network_mode host (ports/ip bindings) -- allow port range in streams +- allow port range in streams and $server_port as a valid input +- improved regex checks for inputs +- dns secrets are not mounted anymore, since they are saved in the db and rewritten on every container start, so they don't need to be mounted - fixed smaller issues/bugs - other small changes/improvements ## migration - **NOTE: migrating back to the original is not possible**, so make first a **backup** before migration, so you can use the backup to switch back -- please delete all dnspod certs and recreate them after migration OR you manually change the credentialsfile (see [here](https://github.com/ZoeyVid/npmplus/blob/develop/global/certbot-dns-plugins.json) for the template) -- stop nginx-proxy-manager download the latest compose.yaml, adjust your paths (of /etc/letsencrypt and /data) to the ones you used with nginx-proxy-manager and adjust the env of the compose file how you like it and then deploy it -- you can now remove the /etc/letsencrypt mount, since it was moved to /data while migration and redeploy the compose file -- since this fork uses `network_mode: host` by default (and all guides are written for this mode), please don't forget to open port 80/tcp, 443/tcp and 443/udp (and maybe 81/tcp) in your firewall -- since many buttons changed, please edit every host you have and click save. (Please also resave it, if all buttons/values are fine, to update the host config to fully fit the NPMplus template) +- please delete all certs using dnspod as dns provider and recreate them after migration, since the certbot plugin used was replaced +- stop nginx-proxy-manager download the latest compose.yaml, adjust your paths (of /etc/letsencrypt and /data) to the ones you used with nginx-proxy-manager and adjust the envs of the compose file how you like it and then deploy it +- you can now remove the /etc/letsencrypt mount, since it was moved to /data while migration, and redeploy the compose file +- since many buttons changed, please check if they are still correct for every host you have. - maybe setup crowdsec (see below) - please report all (migration) issues you may have # Quick Setup -1. Install Docker and Docker Compose (or portainer) -- [Docker Install documentation](https://docs.docker.com/engine) +1. Install Docker and Docker Compose (podman or docker rootless may also work) +- [Docker Install documentation](https://docs.docker.com/engine/install) - [Docker Compose Install documentation](https://docs.docker.com/compose/install/linux) 2. Download this [compose.yaml](https://raw.githubusercontent.com/ZoeyVid/NPMplus/refs/heads/develop/compose.yaml) (or use its content as a portainer stack) 3. adjust TZ and ACME_EMAIL to your values and maybe adjust other env options to your needs. @@ -170,8 +165,8 @@ location / { ``` b) Custom Nginx Configuration (advanced tab), which looks the following for file server and **php**: - Note: the slash at the end of the file path is important -- Note: first enable `PHP82` and/or `PHP83` inside your compose file -- Note: you can replace `fastcgi_pass php82;` with `fastcgi_pass php83;` +- Note: first enable `PHP82`, `PHP83` and/or `PHP84` inside your compose file +- Note: you can replace `fastcgi_pass php82;` with `fastcgi_pass php83;`/`fastcgi_pass php84;` - Note: to add more php extension using envs you can set in the compose file ``` location / { @@ -191,11 +186,11 @@ location / { ### prerun scripts (EXPERT option) - if you don't know what this is, ignore it run order: entrypoint.sh (prerun scripts) => start.sh => launch.sh
-if you need to run scripts before NPMplus launches put them under: `/opt/npm/etc/prerun/*.sh` (please add `#!/bin/sh` / `#!/bin/bash` to the top of the script)
+if you need to run scripts before NPMplus launches put them under: `/opt/npm/etc/prerun/*.sh` (please add `#!/usr/bin/env sh` / `#!/usr/bin/env bash` to the top of the script)
you need to create this folder yourself - **NOTE:** I won't help you creating those patches/scripts if you need them you also need to know how to create them ## Contributing -All are welcome to create pull requests for this project. +All are welcome to create pull requests for this project, but this does not mean it will be merged. # Please report Bugs first to this fork before reporting them to the upstream Repository ## Getting Help diff --git a/backend/index.js b/backend/index.js index 475c1ee51..992e2481e 100755 --- a/backend/index.js +++ b/backend/index.js @@ -21,8 +21,8 @@ async function appStart() { internalCertificate.initTimer(); internalIpRanges.initTimer(); - const server = app.listen(48693, '127.0.0.1', () => { - logger.info('Backend PID ' + process.pid + ' listening on port 48693 ...'); + const server = app.listen(Number(process.env.NIBEP), '127.0.0.1', () => { + logger.info('Backend PID ' + process.pid + ' listening on port ' + process.env.NIBEP); process.on('SIGTERM', () => { logger.info('PID ' + process.pid + ' received SIGTERM'); diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index f5687281e..07870df27 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -783,7 +783,6 @@ const internalCertificate = { logger.info(`Requesting Certbot certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); const credentialsLocation = '/data/tls/certbot/credentials/credentials-' + certificate.id; - fs.mkdirSync('/data/tls/certbot/credentials', { recursive: true }); fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, { mode: 0o600 }); try { @@ -832,6 +831,9 @@ const internalCertificate = { }) .then(() => { return updated_certificate; + }) + .then(() => { + internalNginx.reload(); }); }); } else { @@ -847,8 +849,12 @@ const internalCertificate = { renewCertbot: async (certificate) => { logger.info(`Renewing Certbot certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); - const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); - logger.info(revokeResult); + try { + const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); + logger.info(revokeResult); + } catch { + // do nothing + } 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); @@ -869,8 +875,12 @@ const internalCertificate = { logger.info(`Renewing Certbot certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`); - const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); - logger.info(revokeResult); + try { + const revokeResult = await utils.execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']); + logger.info(revokeResult); + } catch { + // do nothing + } 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); @@ -889,16 +899,6 @@ const internalCertificate = { return utils .execFile(certbotCommand, [...certbotArgs, 'revoke', '--cert-name', `npm-${certificate.id}`, '--no-delete-after-revoke']) .then(async (result) => { - fs.rm('/data/tls/certbot/credentials/credentials-' + certificate.id, { force: true }, (err) => { - if (err) { - logger.error('Error deleting credentials:', err.message); - if (throw_errors) { - throw err; - } - } else { - logger.info('Credentials file deleted successfully'); - } - }); logger.info(result); return result; }) diff --git a/backend/internal/ip_ranges.js b/backend/internal/ip_ranges.js index d21beb40f..d6a1dfa01 100644 --- a/backend/internal/ip_ranges.js +++ b/backend/internal/ip_ranges.js @@ -104,7 +104,7 @@ const internalIpRanges = { let template = null; const filename = '/tmp/ip_ranges.conf'; try { - template = fs.readFileSync(__dirname + '/../templates/ip_ranges.conf', { encoding: 'utf8' }); + template = fs.readFileSync('/app/templates/ip_ranges.conf', { encoding: 'utf8' }); } catch (err) { reject(new error.ConfigurationError(err.message)); return; diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 81661a414..51fd6a37f 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -7,7 +7,6 @@ const error = require('../lib/error'); const internalNginx = { /** * This will: - * - test the nginx config first to make sure it's OK * - create / recreate the config for the host * - test again * - IF OK: update the meta with online status @@ -23,15 +22,7 @@ const internalNginx = { let combined_meta = {}; return internalNginx - .test() - .then(() => { - // Nginx is OK - // We're deleting this config regardless. - return internalNginx.deleteConfig(host_type, host); - }) - .then(() => { - return internalNginx.generateConfig(host_type, host); - }) + .generateConfig(host_type, host) .then(() => { // Test nginx again and update meta with result return internalNginx @@ -79,14 +70,7 @@ const internalNginx = { * @returns {Promise} */ test: () => { - return utils - .execFile('certbot-ocsp-fetcher.sh', ['-c', '/data/tls/certbot', '-o', '/data/tls/certbot/live', '--no-reload-webserver', '--quiet']) - .then(() => { - return utils.execFile('nginx', ['-tq']); - }) - .catch(() => { - return utils.execFile('nginx', ['-tq']); - }); + return utils.execFile('nginx', ['-tq']); }, /** @@ -94,7 +78,17 @@ const internalNginx = { */ reload: () => { - return internalNginx.test().then(() => { + if (process.env.ACME_OCSP_STAPLING === 'true') { + return utils.execFile('certbot-ocsp-fetcher.sh', ['-c', '/data/tls/certbot', '-o', '/data/tls/certbot/live', '--no-reload-webserver', '--quiet']).finally(() => { + if (fs.existsSync('/usr/local/nginx/logs/nginx.pid') && fs.readFileSync('/usr/local/nginx/logs/nginx.pid', 'utf8').trim().length > 0) { + logger.info('Reloading Nginx'); + return utils.execFile('nginx', ['-s', 'reload']); + } else { + logger.info('Starting Nginx'); + utils.execfg('nginx', ['-e', 'stderr']); + } + }); + } else { if (fs.existsSync('/usr/local/nginx/logs/nginx.pid') && fs.readFileSync('/usr/local/nginx/logs/nginx.pid', 'utf8').trim().length > 0) { logger.info('Reloading Nginx'); return utils.execFile('nginx', ['-s', 'reload']); @@ -102,7 +96,7 @@ const internalNginx = { logger.info('Starting Nginx'); utils.execfg('nginx', ['-e', 'stderr']); } - }); + } }, /** @@ -112,7 +106,7 @@ const internalNginx = { */ getConfigName: (host_type, host_id) => { if (host_type === 'default') { - return '/data/nginx/default.conf'; + return '/usr/local/nginx/conf/conf.d/default.conf'; } return '/data/nginx/' + internalNginx.getFileFriendlyHostType(host_type) + '/' + host_id + '.conf'; }, @@ -127,7 +121,7 @@ const internalNginx = { let template; try { - template = fs.readFileSync(__dirname + '/../templates/_location.conf', { encoding: 'utf8' }); + template = fs.readFileSync('/app/templates/_location.conf', { encoding: 'utf8' }); } catch (err) { reject(new error.ConfigurationError(err.message)); return; @@ -146,6 +140,7 @@ const internalNginx = { locationCopy.forward_host = split.shift(); locationCopy.forward_path = `/${split.join('/')}`; } + locationCopy.env = process.env; renderedLocations += await renderEngine.parseAndRender(template, locationCopy); } @@ -172,7 +167,7 @@ const internalNginx = { const filename = internalNginx.getConfigName(nice_host_type, host.id); try { - template = fs.readFileSync(__dirname + '/../templates/' + nice_host_type + '.conf', { encoding: 'utf8' }); + template = fs.readFileSync('/app/templates/' + nice_host_type + '.conf', { encoding: 'utf8' }); } catch (err) { reject(new error.ConfigurationError(err.message)); return; @@ -206,6 +201,8 @@ const internalNginx = { locationsPromise = Promise.resolve(); } + host.env = process.env; + locationsPromise.then(() => { renderEngine .parseAndRender(template, host) @@ -219,6 +216,11 @@ const internalNginx = { }) .catch((err) => { reject(new error.ConfigurationError(err.message)); + }) + .then(() => { + if (process.env.DISABLE_NGINX_BEAUTIFIER === 'false') { + utils.execFile('nginxbeautifier', ['-s', '4', filename]); + } }); }); }); diff --git a/backend/lib/config.js b/backend/lib/config.js index 1836d6f70..ad1d35b34 100644 --- a/backend/lib/config.js +++ b/backend/lib/config.js @@ -49,15 +49,14 @@ const configure = () => { return; } - const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/etc/npm/database.sqlite'; - logger.info(`Using Sqlite: ${envSqliteFile}`); + logger.info('Using Sqlite: /data/etc/npm/database.sqlite'); instance = { database: { engine: 'knex-native', knex: { client: 'better-sqlite3', connection: { - filename: envSqliteFile, + filename: '/data/etc/npm/database.sqlite', }, useNullAsDefault: true, }, diff --git a/backend/lib/utils.js b/backend/lib/utils.js index 082f03264..cdbb73024 100644 --- a/backend/lib/utils.js +++ b/backend/lib/utils.js @@ -1,4 +1,6 @@ const _ = require('lodash'); +const fs = require('fs'); +const crypto = require('crypto'); const spawn = require('child_process').spawn; const execFile = require('child_process').execFile; const { Liquid } = require('liquidjs'); @@ -6,6 +8,21 @@ const logger = require('../logger').global; const error = require('./error'); module.exports = { + writeHash: function () { + const envVars = fs.readdirSync('/app/templates').flatMap((file) => { + const content = fs.readFileSync('/app/templates/' + file, 'utf8'); + const matches = content.match(/env\.[A-Z0-9_]+/g) || []; + return matches.map((match) => match.replace('env.', '')); + }); + const uniqueEnvVars = + [...new Set(envVars)] + .sort() + .map((varName) => process.env[varName]) + .join('') + process.env.TV; + const hash = crypto.createHash('sha512').update(uniqueEnvVars).digest('hex'); + fs.writeFileSync('/data/etc/npm/env.sha512sum', hash); + }, + /** * @param {String} cmd * @param {Array} args @@ -34,6 +51,7 @@ module.exports = { */ execfg: function (cmd, args) { return new Promise((resolve, reject) => { + logger.debug('CMD: ' + cmd + ' ' + (args ? args.join(' ') : '')); const childProcess = spawn(cmd, args, { shell: true, detached: true, @@ -94,7 +112,7 @@ module.exports = { */ getRenderEngine: function () { const renderEngine = new Liquid({ - root: __dirname + '/../templates/', + root: '/app/templates/', }); /** diff --git a/backend/migrations/20241230192345_change_forwarding_port_to_string.js b/backend/migrations/20241230192345_change_forwarding_port_to_string.js new file mode 100644 index 000000000..0af46df6f --- /dev/null +++ b/backend/migrations/20241230192345_change_forwarding_port_to_string.js @@ -0,0 +1,42 @@ +const migrate_name = 'change_forwarding_port_to_string'; +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 + .alterTable('stream', (table) => { + table.string('forwarding_port', 12).notNull().alter(); + }) + .then(function () { + logger.info('[' + migrate_name + '] stream Table altered'); + }); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex /*, Promise */) { + logger.info('[' + migrate_name + '] Migrating Down...'); + + return knex.schema + .alterTable('stream', (table) => { + table.integer('forwarding_port').notNull().unsigned().alter(); + }) + .then(function () { + logger.info('[' + migrate_name + '] stream Table altered'); + }); +}; diff --git a/backend/package.json b/backend/package.json index 65e106f0e..974c87425 100644 --- a/backend/package.json +++ b/backend/package.json @@ -10,7 +10,7 @@ "archiver": "7.0.1", "batchflow": "0.4.0", "bcrypt": "5.1.1", - "better-sqlite3": "11.7.0", + "better-sqlite3": "11.7.2", "body-parser": "2.0.2", "compression": "1.7.5", "express": "4.21.2", @@ -18,10 +18,10 @@ "gravatar": "1.8.2", "jsonwebtoken": "9.0.2", "knex": "3.1.0", - "liquidjs": "10.19.0", + "liquidjs": "10.20.1", "lodash": "4.17.21", "moment": "2.30.1", - "mysql2": "3.11.5", + "mysql2": "3.12.0", "node-rsa": "1.1.1", "objection": "3.1.5", "path": "0.12.7", @@ -35,7 +35,7 @@ "eslint": "9.17.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.2.1", - "globals": "15.13.0", + "globals": "15.14.0", "prettier": "3.4.2" }, "scripts": { diff --git a/backend/routes/main.js b/backend/routes/main.js index 4b44f4ef6..5eabc3f5a 100644 --- a/backend/routes/main.js +++ b/backend/routes/main.js @@ -1,5 +1,4 @@ const express = require('express'); -const pjson = require('../package.json'); const error = require('../lib/error'); let router = express.Router({ @@ -13,15 +12,8 @@ let router = express.Router({ * GET /api */ router.get('/', (req, res /*, next*/) => { - let version = pjson.version.split('-').shift().split('.'); - res.status(200).send({ status: 'OK', - version: { - major: parseInt(version.shift(), 10), - minor: parseInt(version.shift(), 10), - revision: parseInt(version.shift(), 10), - }, }); }); diff --git a/backend/schema/common.json b/backend/schema/common.json index c3e6316b5..5d99506b3 100644 --- a/backend/schema/common.json +++ b/backend/schema/common.json @@ -76,7 +76,7 @@ "uniqueItems": true, "items": { "type": "string", - "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$" + "pattern": "^(([^.]+\\.)+[^.]+)|(\\[[0-9a-f:]+\\])$" } }, "enabled": { diff --git a/backend/schema/components/certificate-object.json b/backend/schema/components/certificate-object.json index bbe575ed0..65204e035 100644 --- a/backend/schema/components/certificate-object.json +++ b/backend/schema/components/certificate-object.json @@ -30,7 +30,7 @@ "uniqueItems": true, "items": { "type": "string", - "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$" + "pattern": "^(([^.]+\\.)+[^.]+)|(\\[[0-9a-f:]+\\])$" } }, "expires_on": { diff --git a/backend/schema/components/health-object.json b/backend/schema/components/health-object.json index 8d223417b..a2798edba 100644 --- a/backend/schema/components/health-object.json +++ b/backend/schema/components/health-object.json @@ -2,37 +2,12 @@ "type": "object", "description": "Health object", "additionalProperties": false, - "required": ["status", "version"], + "required": ["status"], "properties": { "status": { "type": "string", "description": "Healthy", "example": "OK" - }, - "version": { - "type": "object", - "description": "The version object", - "example": { - "major": 2, - "minor": 0, - "revision": 0 - }, - "additionalProperties": false, - "required": ["major", "minor", "revision"], - "properties": { - "major": { - "type": "integer", - "minimum": 0 - }, - "minor": { - "type": "integer", - "minimum": 0 - }, - "revision": { - "type": "integer", - "minimum": 0 - } - } } } } diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json index 5098802b1..ea33b880a 100644 --- a/backend/schema/components/proxy-host-object.json +++ b/backend/schema/components/proxy-host-object.json @@ -44,8 +44,7 @@ }, "forward_host": { "type": "string", - "minLength": 1, - "maxLength": 255 + "pattern": "^(([^.]+\\.)+[^.]+)|(\\[[0-9a-f:]+\\])$" }, "forward_port": { "type": "integer", @@ -101,6 +100,7 @@ }, "path": { "type": "string", + "pattern": "^/.+$", "minLength": 1 }, "forward_scheme": { @@ -113,7 +113,8 @@ "$ref": "#/properties/forward_port" }, "forward_path": { - "type": "string" + "type": "string", + "pattern": "^($|/.+$)" }, "advanced_config": { "type": "string" diff --git a/backend/schema/components/redirection-host-object.json b/backend/schema/components/redirection-host-object.json index 108872845..8b6a8f53d 100644 --- a/backend/schema/components/redirection-host-object.json +++ b/backend/schema/components/redirection-host-object.json @@ -34,7 +34,7 @@ "description": "Domain Name", "example": "jc21.com", "type": "string", - "pattern": "^(?:[^.*]+\\.?)+[^.]$" + "pattern": "^(([^.]+\\.)+[^.]+)|(\\[[0-9a-f:]+\\])($|/.*$)" }, "preserve_path": { "description": "Should the path be preserved", diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json index 826ef1f24..16c8ada24 100644 --- a/backend/schema/components/stream-object.json +++ b/backend/schema/components/stream-object.json @@ -18,31 +18,17 @@ }, "incoming_port": { "type": "string", - "pattern": "^(?!80$|443$)([0-9]+|[0-9]+-[0-9]+)$", + "pattern": "^([0-9]+{1,5}$|[0-9]+{1,5}-[0-9]+{1,5}$)", "maxLength": 11 }, "forwarding_host": { - "anyOf": [ - { - "description": "Domain Name", - "example": "jc21.com", - "type": "string", - "pattern": "^(?:[^.*]+\\.?)+[^.]$" - }, - { - "type": "string", - "format": "ipv4" - }, - { - "type": "string", - "format": "ipv6" - } - ] + "type": "string", + "pattern": "^(([^.]+\\.)+[^.]+)|(\\[[0-9a-f:]+\\])$" }, "forwarding_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 + "type": "string", + "pattern": "^([0-9]+{1,5}|\\$server_port)$", + "maxLength": 12 }, "tcp_forwarding": { "type": "boolean" diff --git a/backend/schema/components/user-object.json b/backend/schema/components/user-object.json index 180e8f197..d1e8b08c7 100644 --- a/backend/schema/components/user-object.json +++ b/backend/schema/components/user-object.json @@ -29,6 +29,7 @@ "type": "string", "description": "Email", "minLength": 3, + "pattern": "@", "example": "jc@jc21.com" }, "name": { diff --git a/backend/schema/definitions.json b/backend/schema/definitions.json deleted file mode 100644 index 7f5b4dd20..000000000 --- a/backend/schema/definitions.json +++ /dev/null @@ -1,240 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "definitions", - "definitions": { - "id": { - "description": "Unique identifier", - "example": 123456, - "readOnly": true, - "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 - }, - "expand": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "sort": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "required": [ - "field", - "dir" - ], - "additionalProperties": false, - "properties": { - "field": { - "type": "string" - }, - "dir": { - "type": "string", - "pattern": "^(asc|desc)$" - } - } - } - }, - "query": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "string", - "minLength": 1, - "maxLength": 255 - } - ] - }, - "criteria": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "object" - } - ] - }, - "fields": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "omit": { - "anyOf": [ - { - "type": "null" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] - }, - "created_on": { - "description": "Date and time of creation", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "modified_on": { - "description": "Date and time of last update", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "user_id": { - "description": "User ID", - "example": 1234, - "type": "integer", - "minimum": 1 - }, - "certificate_id": { - "description": "Certificate ID", - "example": 1234, - "anyOf": [ - { - "type": "integer", - "minimum": 0 - }, - { - "type": "string", - "pattern": "^new$" - } - ] - }, - "access_list_id": { - "description": "Access List ID", - "example": 1234, - "type": "integer", - "minimum": 0 - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "email": { - "description": "Email Address", - "example": "john@example.com", - "format": "email", - "type": "string", - "minLength": 6, - "maxLength": 100 - }, - "password": { - "description": "Password", - "type": "string", - "minLength": 8, - "maxLength": 255 - }, - "domain_name": { - "description": "Domain Name", - "example": "jc21.com", - "type": "string", - "pattern": "^(?:[^.*]+\\.?)+[^.]$" - }, - "domain_names": { - "description": "Domain Names separated by a comma", - "example": "*.jc21.com,blog.jc21.com", - "type": "array", - "maxItems": 99, - "uniqueItems": true, - "items": { - "type": "string", - "pattern": "^(?:\\*\\.)?(?:[^.*]+\\.?)+[^.]$" - } - }, - "http_code": { - "description": "Redirect HTTP Status Code", - "example": 302, - "type": "integer", - "minimum": 300, - "maximum": 308 - }, - "scheme": { - "description": "RFC Protocol", - "example": "HTTPS or $scheme", - "type": "string", - "minLength": 4 - }, - "enabled": { - "description": "Is Enabled", - "example": true, - "type": "boolean" - }, - "ssl_enabled": { - "description": "Is SSL Enabled", - "example": true, - "type": "boolean" - }, - "ssl_forced": { - "description": "Is SSL Forced", - "example": false, - "type": "boolean" - }, - "hsts_enabled": { - "description": "Is HSTS Enabled", - "example": false, - "type": "boolean" - }, - "hsts_subdomains": { - "description": "Is HSTS applicable to all subdomains", - "example": false, - "type": "boolean" - }, - "ssl_provider": { - "type": "string", - "pattern": "^(letsencrypt|other)$" - }, - "http2_support": { - "description": "HTTP2 Protocol Support", - "example": false, - "type": "boolean" - }, - "block_exploits": { - "description": "Should we block common exploits", - "example": true, - "type": "boolean" - }, - "caching_enabled": { - "description": "Should we cache assets", - "example": true, - "type": "boolean" - } - } -} diff --git a/backend/schema/endpoints/certificates.json b/backend/schema/endpoints/certificates.json deleted file mode 100644 index aea3e43c7..000000000 --- a/backend/schema/endpoints/certificates.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/certificates", - "title": "Certificates", - "description": "Endpoints relating to Certificates", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "provider": { - "$ref": "../definitions.json#/definitions/ssl_provider" - }, - "nice_name": { - "type": "string", - "description": "Nice Name for the custom certificate" - }, - "domain_names": { - "$ref": "../definitions.json#/definitions/domain_names" - }, - "expires_on": { - "description": "Date and time of expiration", - "format": "date-time", - "readOnly": true, - "type": "string" - }, - "meta": { - "type": "object", - "additionalProperties": false, - "properties": { - "letsencrypt_email": { - "type": "string", - "format": "email" - }, - "letsencrypt_agree": { - "type": "boolean" - }, - "dns_challenge": { - "type": "boolean" - }, - "dns_provider": { - "type": "string" - }, - "dns_provider_credentials": { - "type": "string" - }, - "propagation_seconds": { - "anyOf": [ - { - "type": "integer", - "minimum": 0 - } - ] - - } - } - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "provider": { - "$ref": "#/definitions/provider" - }, - "nice_name": { - "$ref": "#/definitions/nice_name" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "expires_on": { - "$ref": "#/definitions/expires_on" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Certificates", - "href": "/nginx/certificates", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Certificate", - "href": "/nginx/certificates", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "provider" - ], - "properties": { - "provider": { - "$ref": "#/definitions/provider" - }, - "nice_name": { - "$ref": "#/definitions/nice_name" - }, - "domain_names": { - "$ref": "#/definitions/domain_names" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Certificate", - "href": "/nginx/certificates/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Test HTTP Challenge", - "description": "Tests whether the HTTP challenge should work", - "href": "/nginx/certificates/{definitions.identity.example}/test-http", - "access": "private", - "method": "GET", - "rel": "info", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - } - } - ] -} diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json deleted file mode 100644 index cc4dd6f58..000000000 --- a/backend/schema/endpoints/streams.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/streams", - "title": "Streams", - "description": "Endpoints relating to Streams", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "incoming_port": { - "type": "string", - "pattern": "^([0-9]+|[0-9]+-[0-9]+)$", - "maxLength": 11 - }, - "forwarding_host": { - "anyOf": [ - { - "$ref": "../definitions.json#/definitions/domain_name" - }, - { - "type": "string", - "format": "ipv4" - }, - { - "type": "string", - "format": "ipv6" - } - ] - }, - "forwarding_port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "tcp_forwarding": { - "type": "boolean" - }, - "udp_forwarding": { - "type": "boolean" - }, - "enabled": { - "$ref": "../definitions.json#/definitions/enabled" - }, - "meta": { - "type": "object" - } - }, - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "enabled": { - "$ref": "#/definitions/enabled" - }, - "meta": { - "$ref": "#/definitions/meta" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Streams", - "href": "/nginx/streams", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new Stream", - "href": "/nginx/streams", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "incoming_port", - "forwarding_host", - "forwarding_port" - ], - "properties": { - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "incoming_port": { - "$ref": "#/definitions/incoming_port" - }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" - }, - "forwarding_port": { - "$ref": "#/definitions/forwarding_port" - }, - "tcp_forwarding": { - "$ref": "#/definitions/tcp_forwarding" - }, - "udp_forwarding": { - "$ref": "#/definitions/udp_forwarding" - }, - "meta": { - "$ref": "#/definitions/meta" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Enable", - "description": "Enables a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}/enable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Disable", - "description": "Disables a existing Stream", - "href": "/nginx/streams/{definitions.identity.example}/disable", - "access": "private", - "method": "POST", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - } - ] -} diff --git a/backend/schema/endpoints/users.json b/backend/schema/endpoints/users.json deleted file mode 100644 index 5adff9025..000000000 --- a/backend/schema/endpoints/users.json +++ /dev/null @@ -1,287 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "endpoints/users", - "title": "Users", - "description": "Endpoints relating to Users", - "stability": "stable", - "type": "object", - "definitions": { - "id": { - "$ref": "../definitions.json#/definitions/id" - }, - "created_on": { - "$ref": "../definitions.json#/definitions/created_on" - }, - "modified_on": { - "$ref": "../definitions.json#/definitions/modified_on" - }, - "name": { - "description": "Name", - "example": "Jamie Curnow", - "type": "string", - "minLength": 2, - "maxLength": 100 - }, - "nickname": { - "description": "Nickname", - "example": "Jamie", - "type": "string", - "minLength": 2, - "maxLength": 50 - }, - "email": { - "$ref": "../definitions.json#/definitions/email" - }, - "avatar": { - "description": "Avatar", - "example": "http://somewhere.jpg", - "type": "string", - "minLength": 2, - "maxLength": 150, - "readOnly": true - }, - "roles": { - "description": "Roles", - "example": [ - "admin" - ], - "type": "array" - }, - "is_disabled": { - "description": "Is Disabled", - "example": false, - "type": "boolean" - } - }, - "links": [ - { - "title": "List", - "description": "Returns a list of Users", - "href": "/users", - "access": "private", - "method": "GET", - "rel": "self", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "array", - "items": { - "$ref": "#/properties" - } - } - }, - { - "title": "Create", - "description": "Creates a new User", - "href": "/users", - "access": "private", - "method": "POST", - "rel": "create", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "required": [ - "name", - "nickname", - "email" - ], - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - }, - "auth": { - "type": "object", - "description": "Auth Credentials", - "example": { - "type": "password", - "secret": "bigredhorsebanana" - } - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Update", - "description": "Updates a existing User", - "href": "/users/{definitions.identity.example}", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "properties": { - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - } - } - }, - "targetSchema": { - "properties": { - "$ref": "#/properties" - } - } - }, - { - "title": "Delete", - "description": "Deletes a existing User", - "href": "/users/{definitions.identity.example}", - "access": "private", - "method": "DELETE", - "rel": "delete", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Set Password", - "description": "Sets a password for an existing User", - "href": "/users/{definitions.identity.example}/auth", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "required": [ - "type", - "secret" - ], - "properties": { - "type": { - "type": "string", - "pattern": "^password$" - }, - "current": { - "type": "string", - "minLength": 1, - "maxLength": 99 - }, - "secret": { - "type": "string", - "minLength": 8, - "maxLength": 99 - } - } - }, - "targetSchema": { - "type": "boolean" - } - }, - { - "title": "Set Permissions", - "description": "Sets Permissions for a User", - "href": "/users/{definitions.identity.example}/permissions", - "access": "private", - "method": "PUT", - "rel": "update", - "http_header": { - "$ref": "../examples.json#/definitions/auth_header" - }, - "schema": { - "type": "object", - "properties": { - "visibility": { - "type": "string", - "pattern": "^(all|user)$" - }, - "access_lists": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "dead_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "proxy_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "redirection_hosts": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "streams": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - }, - "certificates": { - "type": "string", - "pattern": "^(hidden|view|manage)$" - } - } - }, - "targetSchema": { - "type": "boolean" - } - } - ], - "properties": { - "id": { - "$ref": "#/definitions/id" - }, - "created_on": { - "$ref": "#/definitions/created_on" - }, - "modified_on": { - "$ref": "#/definitions/modified_on" - }, - "name": { - "$ref": "#/definitions/name" - }, - "nickname": { - "$ref": "#/definitions/nickname" - }, - "email": { - "$ref": "#/definitions/email" - }, - "avatar": { - "$ref": "#/definitions/avatar" - }, - "roles": { - "$ref": "#/definitions/roles" - }, - "is_disabled": { - "$ref": "#/definitions/is_disabled" - } - } -} diff --git a/backend/schema/index.json b/backend/schema/index.json deleted file mode 100644 index 28bea1b28..000000000 --- a/backend/schema/index.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "root", - "title": "NPMplus REST API", - "description": "This is the NPMplus REST API", - "version": "2.0.0", - "links": [ - { - "href": "http://npm.example.com/api", - "rel": "self" - } - ], - "properties": { - "tokens": { - "$ref": "endpoints/tokens.json" - }, - "users": { - "$ref": "endpoints/users.json" - }, - "proxy-hosts": { - "$ref": "endpoints/proxy-hosts.json" - }, - "redirection-hosts": { - "$ref": "endpoints/redirection-hosts.json" - }, - "dead-hosts": { - "$ref": "endpoints/dead-hosts.json" - }, - "streams": { - "$ref": "endpoints/streams.json" - }, - "certificates": { - "$ref": "endpoints/certificates.json" - }, - "access-lists": { - "$ref": "endpoints/access-lists.json" - }, - "settings": { - "$ref": "endpoints/settings.json" - } - } -} diff --git a/backend/setup.js b/backend/setup.js index fbf7acc80..8070203a5 100644 --- a/backend/setup.js +++ b/backend/setup.js @@ -7,6 +7,13 @@ const authModel = require('./models/auth'); const settingModel = require('./models/setting'); const certbot = require('./lib/certbot'); +const proxyModel = require('./models/proxy_host'); +const redirectModel = require('./models/redirection_host'); +const deadModel = require('./models/dead_host'); +const streamModel = require('./models/stream'); +const internalNginx = require('./internal/nginx'); +const utils = require('./lib/utils'); + /** * Creates a default admin users if one doesn't already exist in the database * @@ -73,6 +80,7 @@ const setupDefaultUser = () => { * @returns {Promise} */ const setupDefaultSettings = () => { + let defaultp = process.env.INITIAL_DEFAULT_PAGE || 'congratulations'; return settingModel .query() .select(settingModel.raw('COUNT(`id`) as `count`')) @@ -86,7 +94,7 @@ const setupDefaultSettings = () => { id: 'default-site', name: 'Default Site', description: 'What to show when Nginx is hit with an unknown Host', - value: 'congratulations', + value: defaultp, meta: {}, }) .then(() => { @@ -116,10 +124,7 @@ const setupCertbotPlugins = () => { if (plugins.indexOf(certificate.meta.dns_provider) === -1) { plugins.push(certificate.meta.dns_provider); } - - const credentialsLocation = '/data/tls/certbot/credentials/credentials-' + certificate.id; - fs.mkdirSync('/data/tls/certbot/credentials', { recursive: true }); - fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, { mode: 0o600 }); + fs.writeFileSync('/tmp/certbot-credentials/credentials-' + certificate.id, certificate.meta.dns_provider_credentials, { mode: 0o600 }); } }); @@ -134,6 +139,84 @@ const setupCertbotPlugins = () => { }); }; +/** + * regenerate all hosts if needed + * + * @returns {Promise} + */ +const regenerateAllHosts = () => { + settingModel + .query() + .where('id', 'default-site') + .first() + .then((row) => { + internalNginx.generateConfig('default', row); + }) + .then(() => { + if (process.env.REGENERATE_ALL === 'true') { + const promises = []; + + promises.push( + proxyModel + .query() + .where('is_deleted', 0) + .andWhere('enabled', 1) + .withGraphFetched('[access_list.[clients, items], certificate]') + .then((rows) => { + if (rows && rows.length) { + internalNginx.bulkGenerateConfigs('proxy_host', rows); + } + }), + ); + + promises.push( + redirectModel + .query() + .where('is_deleted', 0) + .andWhere('enabled', 1) + .withGraphFetched('[certificate]') + .then((rows) => { + if (rows && rows.length) { + internalNginx.bulkGenerateConfigs('redirection_host', rows); + } + }), + ); + + promises.push( + deadModel + .query() + .where('is_deleted', 0) + .andWhere('enabled', 1) + .withGraphFetched('[certificate]') + .then((rows) => { + if (rows && rows.length) { + internalNginx.bulkGenerateConfigs('dead_host', rows); + } + }), + ); + + promises.push( + streamModel + .query() + .where('is_deleted', 0) + .andWhere('enabled', 1) + .then((rows) => { + if (rows && rows.length) { + internalNginx.bulkGenerateConfigs('stream', rows); + } + }), + ); + + // Execute all promises and then write the hash + return Promise.all(promises).then(() => { + utils.writeHash(); + }); + } + }); + + return Promise.resolve(); // Return resolved promise if REGENERATE_ALL is not true +}; + module.exports = function () { - return setupDefaultUser().then(setupDefaultSettings).then(setupCertbotPlugins); + return setupDefaultUser().then(setupDefaultSettings).then(setupCertbotPlugins).then(regenerateAllHosts); }; diff --git a/backend/templates/_access.conf b/backend/templates/_access.conf index 6b9082b65..58bbb9ae8 100644 --- a/backend/templates/_access.conf +++ b/backend/templates/_access.conf @@ -1,24 +1,24 @@ -{%- if access_list_id > 0 %} - {%- if access_list.items.length > 0 %} +{% if access_list_id > 0 %} + {% if access_list.items.length > 0 %} # Authorization auth_basic "Authorization required"; auth_basic_user_file /data/etc/access/{{ access_list_id }}; - {%- unless access_list.pass_auth %} + {% unless access_list.pass_auth %} proxy_set_header Authorization ""; - {%- endunless %} - {%- endif %} + {% endunless %} + {% endif %} # Access Rules: {{ access_list.clients | size }} total - {%- for client in access_list.clients %} + {% for client in access_list.clients %} {{client | nginxAccessRule}} - {%- endfor %} + {% endfor %} deny all; # Access checks must... - {%- if access_list.satisfy_any %} + {% if access_list.satisfy_any %} satisfy any; - {%- else %} + {% else %} satisfy all; - {%- endif %} -{%- endif %} + {% endif %} +{% endif %} diff --git a/backend/templates/_brotli.conf b/backend/templates/_brotli.conf index c9e124e7e..8b5888d45 100644 --- a/backend/templates/_brotli.conf +++ b/backend/templates/_brotli.conf @@ -1,4 +1,4 @@ -{%- if http2_support %} +{% if http2_support %} # Enable Brotli include conf.d/include/brotli.conf; -{%- endif %} +{% endif %} diff --git a/backend/templates/_certificates.conf b/backend/templates/_certificates.conf index dee4f9a2a..9ab7408f1 100644 --- a/backend/templates/_certificates.conf +++ b/backend/templates/_certificates.conf @@ -1,14 +1,18 @@ -{%- if certificate and certificate_id > 0 %} -{%- if certificate.provider == "letsencrypt" %} +{% if certificate and certificate_id > 0 %} +{% if certificate.provider == "letsencrypt" %} # Certbot TLS include conf.d/include/tls-ciphers.conf; ssl_certificate /data/tls/certbot/live/npm-{{ certificate_id }}/fullchain.pem; ssl_certificate_key /data/tls/certbot/live/npm-{{ certificate_id }}/privkey.pem; + {% if env.ACME_OCSP_STAPLING == "true" %} + ssl_stapling on; + ssl_stapling_verify on; ssl_stapling_file /data/tls/certbot/live/npm-{{ certificate_id }}.der; -{%- else %} + {% endif %} +{% else %} # Custom TLS include conf.d/include/tls-ciphers-no-stapling.conf; ssl_certificate /data/tls/custom/npm-{{ certificate_id }}/fullchain.pem; ssl_certificate_key /data/tls/custom/npm-{{ certificate_id }}/privkey.pem; -{%- endif %} -{%- endif %} +{% endif %} +{% endif %} diff --git a/backend/templates/_forced_tls.conf b/backend/templates/_forced_tls.conf index cfd7bb5c9..55a7b3b04 100644 --- a/backend/templates/_forced_tls.conf +++ b/backend/templates/_forced_tls.conf @@ -1,6 +1,6 @@ -{%- if certificate and certificate_id > 0 %} -{%- if ssl_forced %} +{% if certificate and certificate_id > 0 %} +{% if ssl_forced %} # Force TLS include conf.d/include/force-tls.conf; -{%- endif %} -{%- endif %} +{% endif %} +{% endif %} diff --git a/backend/templates/_hsts.conf b/backend/templates/_hsts.conf index 8ecd16a6b..8d9d35511 100644 --- a/backend/templates/_hsts.conf +++ b/backend/templates/_hsts.conf @@ -1,17 +1,7 @@ -{%- if certificate and certificate_id > 0 %} -{%- if ssl_forced %} -{%- if hsts_enabled %} - more_clear_headers "Expect-CT"; +{% if certificate and certificate_id > 0 %} +{% if ssl_forced %} +{% if hsts_enabled %} include conf.d/include/hsts.conf; -{%- endif %} -{%- endif %} -{%- endif %} - -{%- unless certificate and certificate_id > 0 %} -{%- unless ssl_forced %} -{%- unless hsts_enabled %} - more_clear_headers "Expect-CT"; - more_clear_headers "Strict-Transport-Security"; -{%- endunless %} -{%- endunless %} -{%- endunless %} +{% endif %} +{% endif %} +{% endif %} diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 0f4923510..a7bf8e4ad 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,21 +1,24 @@ - +{% if env.DISABLE_HTTP == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTP_PORT }}; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTP_PORT }};{% endif %} +{% else %} listen unix:/run/nginx-{{ id }}.sock; +{% endif %} - listen 80; - listen [::]:80; - -{%- if certificate and certificate_id > 0 %} - listen 443 ssl; - listen [::]:443 ssl; +{% if certificate and certificate_id > 0 %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} ssl; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} ssl;{% endif %} - listen 443 quic; - listen [::]:443 quic; +{% if env.DISABLE_H3_QUIC == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} quic; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} quic;{% endif %} -{%- if hsts_subdomains %} - more_set_headers 'Alt-Svc: h3=":443"; ma=86400'; -{%- else %} +{% if hsts_subdomains %} + more_set_headers 'Alt-Svc: h3=":{{ env.HTTPS_PORT }}"; ma=86400'; +{% else %} more_clear_headers "Alt-Svc"; http3 off; -{%- endif %} -{%- endif %} +{% endif %} +{% endif %} +{% endif %} server_name {{ domain_names | join: " " }}; diff --git a/backend/templates/_location.conf b/backend/templates/_location.conf index 4311dc835..95ca77bbe 100644 --- a/backend/templates/_location.conf +++ b/backend/templates/_location.conf @@ -3,12 +3,12 @@ location {{ path }} { set $forward_path "{{ forward_path }}"; - {%- if allow_websocket_upgrade %} + {% if allow_websocket_upgrade %} proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; - {%- endif %} + {% endif %} - include conf.d/include/proxy-location.conf; + include conf.d/include/proxy.conf; proxy_set_header X-Forwarded-Host $host{{ path }}; if ($forward_path = "") { rewrite ^{{ path }}(/.*)$ $1 break; diff --git a/backend/templates/dead_host.conf b/backend/templates/dead_host.conf index 9380f7031..e8709c6bb 100644 --- a/backend/templates/dead_host.conf +++ b/backend/templates/dead_host.conf @@ -1,28 +1,27 @@ -{%- include "_header_comment.conf" %} +{% include "_header_comment.conf" %} -{%- if enabled %} +{% if enabled %} server { -{%- include "_listen.conf" %} -{%- include "_certificates.conf" %} -{%- include "_hsts.conf" %} -{%- include "_forced_tls.conf" %} -{%- include "_brotli.conf" %} +{% include "_listen.conf" %} +{% include "_certificates.conf" %} +{% include "_hsts.conf" %} +{% include "_forced_tls.conf" %} +{% include "_brotli.conf" %} include conf.d/include/always.conf; {{ advanced_config }} -{%- if use_default_location %} +{% if use_default_location %} location / { include conf.d/include/always.conf; root /html/404deadpage; error_page 404 /404deadpage.html; try_files $uri =404; } -{%- endif %} +{% endif %} # Custom - include /data/nginx_custom/server_dead.conf; - + include /data/custom_nginx/server_dead.conf; } -{%- endif %} +{% endif %} diff --git a/backend/templates/default.conf b/backend/templates/default.conf index b7d69f8ff..01e3015d1 100644 --- a/backend/templates/default.conf +++ b/backend/templates/default.conf @@ -2,60 +2,101 @@ # Default Site # ------------------------------------------------------------ server { - listen 80 default_server; - listen [::]:80 default_server; +{% if env.DISABLE_HTTP == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTP_PORT }}; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTP_PORT }};{% endif %} +{% endif %} - listen 443 ssl default_server; - listen [::]:443 ssl default_server; + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} ssl; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} ssl;{% endif %} - listen 443 quic reuseport default_server; - listen [::]:443 quic reuseport default_server; - more_set_headers 'Alt-Svc: h3=":443"; ma=86400'; - - server_name _; +{% if env.DISABLE_H3_QUIC == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} quic reuseport; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} quic reuseport;{% endif %} + more_set_headers 'Alt-Svc: h3=":{{ env.HTTPS_PORT }}"; ma=86400'; +{% else %} + more_clear_headers "Alt-Svc"; + http3 off; +{% endif %} + server_name ""; + include conf.d/include/always.conf; include conf.d/include/brotli.conf; include conf.d/include/force-tls.conf; include conf.d/include/tls-ciphers.conf; + + ssl_certificate ; + ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; + #ssl_stapling_file ; + + return 444; +} + +server { +{% if env.DISABLE_HTTP == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTP_PORT }} default_server; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTP_PORT }} default_server;{% endif %} +{% endif %} + + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} ssl default_server; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} ssl default_server;{% endif %} + +{% if env.DISABLE_H3_QUIC == "false" %} + listen {{ env.IPV4_BINDING }}:{{ env.HTTPS_PORT }} quic default_server; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ env.HTTPS_PORT }} quic default_server;{% endif %} + more_set_headers 'Alt-Svc: h3=":{{ env.HTTPS_PORT }}"; ma=86400'; +{% else %} + more_clear_headers "Alt-Svc"; + http3 off; +{% endif %} + + server_name _; include conf.d/include/always.conf; + include conf.d/include/brotli.conf; + include conf.d/include/force-tls.conf; + include conf.d/include/tls-ciphers.conf; ssl_certificate ; ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; #ssl_stapling_file ; -{%- if value == "404" %} +{% if value == "404" %} location / { include conf.d/include/always.conf; root /html/404deadpage; error_page 404 /404deadpage.html; try_files $uri =404; } -{%- endif %} +{% endif %} -{%- if value == "444" %} +{% if value == "444" %} return 444; -{%- endif %} +{% endif %} -{%- if value == "redirect" %} +{% if value == "redirect" %} location / { include conf.d/include/always.conf; return 307 {{ meta.redirect }}; } -{%- endif %} +{% endif %} -{%- if value == "congratulations" %} +{% if value == "congratulations" %} location / { include conf.d/include/always.conf; root /html/default; try_files $uri /index.html; } -{%- endif %} +{% endif %} -{%- if value == "html" %} +{% if value == "html" %} location / { include conf.d/include/always.conf; root /data/etc/html; try_files $uri /index.html; } -{%- endif %} +{% endif %} } diff --git a/backend/templates/ip_ranges.conf b/backend/templates/ip_ranges.conf index a1fb5abf7..ee7db9359 100644 --- a/backend/templates/ip_ranges.conf +++ b/backend/templates/ip_ranges.conf @@ -1,6 +1,6 @@ -{%- for range in ip_ranges %} +{% for range in ip_ranges %} set_real_ip_from {{ range }}; -{%- endfor %} +{% endfor %} map $http_cf_connecting_ip $real_ip { "" $http_x_real_ip; diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf index b2bb752d0..f89b301d5 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -1,55 +1,56 @@ -{%- include "_header_comment.conf" %} +{% include "_header_comment.conf" %} -{%- if enabled %} +{% if enabled %} server { set $forward_scheme {{ forward_scheme }}; set $server "{{ forward_host }}"; set $port {{ forward_port }}; -{%- include "_listen.conf" %} -{%- include "_certificates.conf" %} -{%- include "_hsts.conf" %} -{%- include "_forced_tls.conf" %} -{%- include "_brotli.conf" %} -{%- include "_access.conf" %} +{% include "_listen.conf" %} +{% include "_certificates.conf" %} +{% include "_hsts.conf" %} +{% include "_forced_tls.conf" %} +{% include "_brotli.conf" %} +{% include "_access.conf" %} - {%- if block_exploits %} + {% if block_exploits %} modsecurity on; - {%- if caching_enabled %} + {% if caching_enabled %} modsecurity_rules_file /usr/local/nginx/conf/conf.d/include/modsecurity-crs.conf; - {%- else %} + {% else %} modsecurity_rules_file /usr/local/nginx/conf/conf.d/include/modsecurity.conf; - {%- endif %} - {%- endif %} + {% endif %} + {% endif %} include conf.d/include/always.conf; - {%- if access_list_id > 0 %} - {%- if access_list.items.length > 0 %} + {% if access_list_id > 0 %} + {% if access_list.items.length > 0 %} {{ access_list.passauth }} - {%- endif %} - {%- endif %} + {% endif %} + {% endif %} {{ advanced_config }} # custom locations {{ locations }} -{%- if use_default_location %} +{% if use_default_location %} location / { include conf.d/include/always.conf; - {%- if allow_websocket_upgrade %} + {% if allow_websocket_upgrade %} proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; - {%- endif %} + {% endif %} # Proxy! include conf.d/include/proxy.conf; + proxy_pass $forward_scheme://$server:$port$request_uri; } -{%- endif %} +{% endif %} # Custom - include /data/nginx_custom/server_proxy.conf; + include /data/custom_nginx/server_proxy.conf; } -{%- endif %} +{% endif %} diff --git a/backend/templates/redirection_host.conf b/backend/templates/redirection_host.conf index 913dfae1d..8d0359acd 100644 --- a/backend/templates/redirection_host.conf +++ b/backend/templates/redirection_host.conf @@ -1,29 +1,29 @@ -{%- include "_header_comment.conf" %} +{% include "_header_comment.conf" %} -{%- if enabled %} +{% if enabled %} server { -{%- include "_listen.conf" %} -{%- include "_certificates.conf" %} -{%- include "_hsts.conf" %} -{%- include "_forced_tls.conf" %} -{%- include "_brotli.conf" %} +{% include "_listen.conf" %} +{% include "_certificates.conf" %} +{% include "_hsts.conf" %} +{% include "_forced_tls.conf" %} +{% include "_brotli.conf" %} include conf.d/include/always.conf; {{ advanced_config }} -{%- if use_default_location %} +{% if use_default_location %} location / { include conf.d/include/always.conf; - {%- if preserve_path %} + {% if preserve_path %} return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }}$request_uri; - {%- else %} + {% else %} return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }}; - {%- endif %} + {% endif %} } -{%- endif %} +{% endif %} # Custom - include /data/nginx_custom/server_redirect.conf; + include /data/custom_nginx/server_redirect.conf; } -{%- endif %} +{% endif %} diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 1d534694b..32f7cbccf 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -2,31 +2,31 @@ # {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }} # ------------------------------------------------------------ -{%- if enabled %} +{% if enabled %} -{%- if tcp_forwarding %} +{% if tcp_forwarding %} server { - listen {{ incoming_port }}; - listen [::]:{{ incoming_port }}; + listen {{ env.IPV4_BINDING }}:{{ incoming_port }}; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ incoming_port }};{% endif %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; # Custom - include /data/nginx_custom/server_stream.conf; - include /data/nginx_custom/server_stream_tcp.conf; + include /data/custom_nginx/server_stream.conf; + include /data/custom_nginx/server_stream_tcp.conf; } -{%- endif %} +{% endif %} -{%- if udp_forwarding %} +{% if udp_forwarding %} server { - listen {{ incoming_port }} udp; - listen [::]:{{ incoming_port }} udp; + listen {{ env.IPV4_BINDING }}:{{ incoming_port }} udp; + {% if env.DISABLE_IPV6 == "false" %}listen {{ env.IPV6_BINDING }}:{{ incoming_port }} udp;{% endif %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; # Custom - include /data/nginx_custom/server_stream.conf; - include /data/nginx_custom/server_stream_udp.conf; + include /data/custom_nginx/server_stream.conf; + include /data/custom_nginx/server_stream_udp.conf; } -{%- endif %} +{% endif %} -{%- endif %} +{% endif %} diff --git a/compose.yaml b/compose.yaml index 408bfd959..7a7ce7fab 100644 --- a/compose.yaml +++ b/compose.yaml @@ -4,22 +4,25 @@ services: image: zoeyvid/npmplus restart: always network_mode: host +# privileged: true # required if you set NGINX_QUIC_BPF to true volumes: - "/opt/npm:/data" # - "/var/www:/var/www" # optional, if you want to use it as webserver for html/php # - "/opt/npm-letsencrypt:/etc/letsencrypt" # Only needed for first time migration from original nginx-proxy-manager to this fork 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://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 (will change soon, see https://github.com/ZoeyVid/NPMplus/discussions/1285), I recommend you to enable this if your CA supports it + - "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, optional for letsencrypt, but required for zerossl and google public ca +# - "ACME_SERVER=https://dv.acme-v02.api.pki.goog/directory (google public ca) / https://acme.zerossl.com/v2/DV90 (zerossl)" # acme server used when requesting/renewing certs using certbot, default is set to: https://acme-v02.api.letsencrypt.org/directory (letsencrypt) +# - "ACME_EAB_KID=123456789abcdef" # Key Identifier for External Account Binding for the acme server, not supported by letsencrypt, optional for zerossl (Login on theier site => Developer), but required for google public ca: https://cloud.google.com/certificate-manager/docs/public-ca-tutorial?hl=de#request-key-hmac +# - "ACME_EAB_HMAC_KEY=123456789abcdef" # HMAC key for External Account Binding for the acme server, not supported by letsencrypt, optional for zerossl (Login on theier site => Developer), but required for google public ca: https://cloud.google.com/certificate-manager/docs/public-ca-tutorial?hl=de#request-key-hmac +# - "ACME_MUST_STAPLE=true" # enables must-staple, default false, I recommend you to enable this if your CA supports it, supported by zerossl, google public ca ignores this, unsupported by letsencrypt (will fail) +# not released # - "ACME_OCSP_STAPLING=false" # enables ocsp stapling, default true, I recommend you to enable this if your CA supports it, supported by zerossl and google public ca, unsupported by letsencrypt certs created after May 7, 2025 (will create warning in your log, default value will change then) +# not released # - "ACME_KEY_TYPE=rsa" # which key type to use ecdsa or rsa, default and recommended: ecdsa # - "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 -# - "NIBEP=48694" # internal port of the NPMplus API, always bound to 127.0.0.1, default 48693, you need to change it, if you want to run multiple npm instances in network mode host -# - "GOAIWSP=48684" # internal port of goaccess, always bound to 127.0.0.1, default 48683, you need to change it, if you want to run multiple npm with goaccess instances in network mode host +# - "NIBEP=48684" # internal port of the NPMplus API, always bound to 127.0.0.1, default 48683, you need to change it, if you want to run multiple npm instances in network mode host +# - "GOAIWSP=48694" # internal port of goaccess, always bound to 127.0.0.1, default 48693, you need to change it, if you want to run multiple npm with goaccess instances in network mode host # - "NPM_PORT=82" # Port the NPM UI should be bound to, default 81, you need to change it, if you want to run multiple npm instances in network mode host # - "GOA_PORT=92" # Port the goaccess should be bound to, default 91, you need to change it, if you want to run multiple npm with goaccess instances in network mode host # - "IPV4_BINDING=127.0.0.1" # IPv4 address to bind, defaults to all @@ -28,16 +31,19 @@ services: # - "IPV6_BINDING=[::1]" # IPv6 address to bind, defaults to all # - "NPM_IPV6_BINDING=[::1]" # IPv6 address to bind for the NPM UI, defaults to all # - "GOA_IPV6_BINDING=[::1]" # IPv6 address to bind for goaccess, defaults to all -# - "DISABLE_IPV6=true" # disable IPv6 and IPv6 resolver of nginx, overrides with IPV6_BINDING, default false -# - "NPM_DISABLE_IPV6=true" # disable IPv6 for the NPM UI, overrides NPM_IPV6_BINDING, default false -# - "GOA_DISABLE_IPV6=true" # disable IPv6 for goaccess, overrides GOA_IPV6_BINDING, default false +# - "DISABLE_IPV6=true" # fully disables listing on IPv6 and the IPv6 resolver of nginx, overrides IPV6_BINDING/NPM_IPV6_BINDING/GOA_IPV6_BINDING, default false # - "NPM_LISTEN_LOCALHOST=true" # Binds the NPM UI only to localhost, overrides NPM_IPV4_BINDING/NPM_IPV6_BINDING, default false # - "GOA_LISTEN_LOCALHOST=true" # Binds goaccess only to localhost, overrides NPM_IPV4_BINDING/NPM_IPV6_BINDING, default false # - "DEFAULT_CERT_ID=1" # ID of cert, which should be used instead of dummycerts, default 0/unset/dummycerts +# not released # - "HTTP_PORT=8080" # tcp port to use for http traffic, changing this may breaks certbot http challenge, default 80 +# not released # - "HTTPS_PORT=8443" # udp and tcp port to use for https traffic, this also needs to be changed if you don't use network_mode host to keep http3/quic working, changing this may breaks certbot http challenge, default 443 # - "DISABLE_HTTP=true" # disables nginx to listen on port 80, default false -# - "DISABLE_H3_QUIC=true" # disables nginx to listen on port 443 udp for default and your hosts, this will disable HTTP/3 and QUIC, default false +# - "DISABLE_H3_QUIC=true" # disables nginx to listen on port 443 udp for default and your hosts, this will fully disable HTTP/3 and QUIC, even if you enable it inside the UI, not recommended, default false +# not released # - "NGINX_QUIC_BPF=true" # enables nginxs quic_bpf (https://nginx.org/en/docs/http/ngx_http_v3_module.html#quic_bpf), you also need to to give the NPMplus container privileged permissions to use this, default false # - "NGINX_LOG_NOT_FOUND=true" # Allow logging of 404 errors, default false # - "NGINX_404_REDIRECT=true" # Redirect to / instead of showing a 404 error page, default false +# not released # - "NGINX_HSTS_SUBDMAINS=false" # when enabling security headers, also enable hsts for subdomains, default true +# not released # - "X_FRAME_OPTIONS=sameorigin" # value to use for the X-Frame-Options header when enabling security headers, valid is deny, sameorigin and none (means unset), default deny, since this applies to all hosts I recommend you to instead keep the default and only change it for hosts which need it using the advanced config and more_set_headers # - "NGINX_DISABLE_PROXY_BUFFERING=true" # Disables the proxy_buffering/proxy_request_buffering options of nginx, default false, may not work if you use crowdsec/appsec # - "DISABLE_NGINX_BEAUTIFIER=true" # disables nginxbeautifier, useful when it fails parsing non-standard configs, default false # - "CLEAN=false" # Clean folders, default true @@ -50,12 +56,15 @@ services: # - "GOA=true" # Enables goaccess, requires LOGROTATE, default false --- if you download the GeoLite2-Country.mmdb, GeoLite2-City.mmdb AND GeoLite2-ASN.mmdb file from MaxMind and place them in /opt/npm/etc/goaccess/geoip it will automatically enable GeoIP in goaccess after restarting NPMplus (no need to change GOACLA below), you may also deploy the compose.geoip.yaml (please change the timezone) # - "GOACLA=--agent-list --real-os --double-decode --anonymize-ip --anonymize-level=2 --keep-last=7 --with-output-resolver --no-query-string" # Arguments that should be passed to goaccess, default: https://github.com/ZoeyVid/NPMplus/blob/develop/rootfs/usr/local/bin/launch.sh#L50 and: --agent-list --real-os --double-decode --anonymize-ip --anonymize-level=1 --keep-last=30 --with-output-resolver --no-query-string # - "PHP82=true" # Activate PHP82, default false -# - "PHP82_APKS=php82-curl php82-openssl" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.20&repo=community&arch=x86_64&name=php82-*, default none, requires PHP82 +# - "PHP82_APKS=php82-curl php82-openssl" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.21&repo=community&arch=x86_64&name=php82-*, default none, requires PHP82 # - "PHP83=true" # Activate PHP83, default false -# - "PHP83_APKS=php83-curl php83-openssl" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.20&repo=community&arch=x86_64&name=php83-*, default none, requires PHP83 -# - "PHP_APKS=php-pecl-apcu php-pecl-redis" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.20&repo=community&arch=x86_64&name=php-*, default none, requires PHP82 and/or PHP83, not recommended, please use PHP82_APKS or PHP83_APKS +# - "PHP83_APKS=php83-curl php83-openssl" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.21&repo=community&arch=x86_64&name=php83-*, default none, requires PHP83 +# not released # - "PHP84=true" # Activate PHP84, default false +# not released # - "PHP84_APKS=php84-curl php84-openssl" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.21&repo=community&arch=x86_64&name=php84-*, default none, requires PHP84 +# - "PHP_APKS=php-pecl-apcu php-pecl-redis" # Add php extensions, see available packages here: https://pkgs.alpinelinux.org/packages?branch=v3.21&repo=community&arch=x86_64&name=php-*, default none, requires PHP82, PHP83 and/or PHP84, not recommended, please use PHP82_APKS, PHP83_APKS or PHP84_APKS # - "INITIAL_ADMIN_EMAIL=initial-email" # email to use instead of admin@example.org on first start of NPMplus for the initial user -# - "INITIAL_ADMIN_PASSWORD=initial-password" # password to use instead of the one in the README.md on first start of NPMplus for the initial user +# - "INITIAL_ADMIN_PASSWORD=initial-password" # password to use instead of iArhP1j7p1P6TA92FA2FMbbUGYqwcYzxC4AVEe12Wbi94FY9gNN62aKyF1shrvG4NycjjX9KfmDQiwkLZH1ZDR9xMjiG2QmoHXi on first start of NPMplus for the initial user +# - "INITIAL_DEFAULT_PAGE=444" # default page to set on first start of NPMplus for the initial user, default congratulations, can be one of: 404, 444, redirect, congratulations or html # This can be used with DISABLE_HTTP=true, to force HTTPS redirects for every host # npmplus-caddy: diff --git a/frontend/js/app/api.js b/frontend/js/app/api.js index c9d554f10..e25f0525d 100644 --- a/frontend/js/app/api.js +++ b/frontend/js/app/api.js @@ -198,10 +198,6 @@ function DownloadFile(verb, path, filename) { } module.exports = { - status: function () { - return fetch('get', ''); - }, - Tokens: { /** diff --git a/frontend/js/app/cache.js b/frontend/js/app/cache.js index 17e60def5..0cc10a6ce 100644 --- a/frontend/js/app/cache.js +++ b/frontend/js/app/cache.js @@ -2,8 +2,7 @@ const UserModel = require('../models/user'); let cache = { User: new UserModel.Model(), - locale: navigator.languages[0].toLowerCase(), - version: null + locale: navigator.languages[0].toLowerCase() }; module.exports = cache; diff --git a/frontend/js/app/dashboard/main.js b/frontend/js/app/dashboard/main.js index 4765d061e..c2e82f855 100644 --- a/frontend/js/app/dashboard/main.js +++ b/frontend/js/app/dashboard/main.js @@ -50,7 +50,8 @@ module.exports = Mn.View.extend({ onRender: function () { let view = this; - Api.Reports.getHostStats() + if (typeof view.stats.hosts === 'undefined') { + Api.Reports.getHostStats() .then(response => { if (!view.isDestroyed()) { view.stats.hosts = response; @@ -60,6 +61,7 @@ module.exports = Mn.View.extend({ .catch(err => { console.log(err); }); + } }, /** diff --git a/frontend/js/app/main.js b/frontend/js/app/main.js index c825664b5..fcf337f84 100644 --- a/frontend/js/app/main.js +++ b/frontend/js/app/main.js @@ -31,11 +31,7 @@ const App = Mn.Application.extend({ } // Check if we are still logged in by refreshing the token - Api.status() - .then(result => { - Cache.version = [result.version.major, result.version.minor, result.version.revision].join('.'); - }) - .then(Api.Tokens.refresh) + Api.Tokens.refresh() .then(this.bootstrap) .then(() => { console.info(i18n('main', 'logged-in', Cache.User.attributes)); @@ -106,14 +102,7 @@ const App = Mn.Application.extend({ */ bootstrapTimer: function () { setTimeout(() => { - Api.status() - .then(result => { - let version = [result.version.major, result.version.minor, result.version.revision].join('.'); - if (version !== Cache.version) { - document.location.reload(); - } - }) - .then(this.bootstrap) + this.bootstrap() .then(() => { this.bootstrapTimer(); }) diff --git a/frontend/js/app/nginx/certificates/form.ejs b/frontend/js/app/nginx/certificates/form.ejs index 8b020a9a1..500540d58 100644 --- a/frontend/js/app/nginx/certificates/form.ejs +++ b/frontend/js/app/nginx/certificates/form.ejs @@ -132,7 +132,7 @@ diff --git a/frontend/js/app/nginx/certificates/form.js b/frontend/js/app/nginx/certificates/form.js index 21e98a857..0b945dca8 100644 --- a/frontend/js/app/nginx/certificates/form.js +++ b/frontend/js/app/nginx/certificates/form.js @@ -272,7 +272,7 @@ module.exports = Mn.View.extend({ text: input }; }, - createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/ + createFilter: /^([^.]+\.)+[^.]+$/ }); this.ui.dns_challenge_content.hide(); this.ui.credentials_file_content.hide(); diff --git a/frontend/js/app/nginx/dead/form.ejs b/frontend/js/app/nginx/dead/form.ejs index 84d54fb5e..cfc1c9995 100644 --- a/frontend/js/app/nginx/dead/form.ejs +++ b/frontend/js/app/nginx/dead/form.ejs @@ -180,7 +180,7 @@ diff --git a/frontend/js/app/nginx/dead/form.js b/frontend/js/app/nginx/dead/form.js index dc37b2aa9..c59feb04b 100644 --- a/frontend/js/app/nginx/dead/form.js +++ b/frontend/js/app/nginx/dead/form.js @@ -45,7 +45,6 @@ module.exports = Mn.View.extend({ this.ui.letsencrypt.hide().find('input').prop('disabled', true); } - let enabled = id === 'new' || parseInt(id, 10) > 0; let inputs = this.ui.ssl_forced.add(this.ui.hsts_subdomains); @@ -71,8 +70,6 @@ module.exports = Mn.View.extend({ if (!checked) { this.ui.hsts_enabled.prop('checked', false); } - - this.ui.hsts_enabled.trigger('change'); }, 'change @ui.dns_challenge_switch': function () { @@ -228,7 +225,7 @@ module.exports = Mn.View.extend({ text: input }; }, - createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/ + createFilter: /^(([^.]+\.)+[^.]+)|(\[[0-9a-f:]+\])$/ }); // Certificates diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 7a730ba3a..f05c34b24 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -75,7 +75,7 @@
@@ -248,7 +248,7 @@
@@ -269,7 +269,7 @@ -

<%- i18n('all-hosts', 'advanced-config-header-info') %>

+

<%- i18n('all-hosts', 'advanced-config-header-info', {url: 'https://github.com/openresty/headers-more-nginx-module?tab=readme-ov-file#more_set_headers'}) %>

diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index 708ff81b2..7ad4c99ae 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -24,6 +24,8 @@ module.exports = Mn.View.extend({ form: 'form', domain_names: 'input[name="domain_names"]', forward_host: 'input[name="forward_host"]', + block_exploits: 'input[name="block_exploits"]', + caching_enabled: 'input[name="caching_enabled"]', buttons: '.modal-footer button', cancel: 'button.cancel', save: 'button.save', @@ -51,6 +53,18 @@ module.exports = Mn.View.extend({ }, events: { + 'change @ui.block_exploits': function () { + let checked = this.ui.block_exploits.prop('checked'); + this.ui.caching_enabled + .prop('disabled', !checked) + .parents('.form-group') + .css('opacity', checked ? 1 : 0.5); + + if (!checked) { + this.ui.caching_enabled.prop('checked', false); + } + }, + 'change @ui.certificate_select': function () { let id = this.ui.certificate_select.val(); if (id === 'new') { @@ -85,8 +99,6 @@ module.exports = Mn.View.extend({ if (!checked) { this.ui.hsts_enabled.prop('checked', false); } - - this.ui.hsts_enabled.trigger('change'); }, 'change @ui.dns_challenge_switch': function () { @@ -252,8 +264,7 @@ module.exports = Mn.View.extend({ onRender: function () { let view = this; - this.ui.ssl_forced.trigger('change'); - this.ui.hsts_enabled.trigger('change'); + this.ui.block_exploits.trigger('change'); // Domain names this.ui.domain_names.selectize({ @@ -266,7 +277,7 @@ module.exports = Mn.View.extend({ text: input }; }, - createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/ + createFilter: /^(([^.]+\.)+[^.]+)|(\[[0-9a-f:]+\])$/ }); // Access Lists diff --git a/frontend/js/app/nginx/redirection/form.ejs b/frontend/js/app/nginx/redirection/form.ejs index 69ea417ed..5336b39ef 100644 --- a/frontend/js/app/nginx/redirection/form.ejs +++ b/frontend/js/app/nginx/redirection/form.ejs @@ -229,7 +229,7 @@ diff --git a/frontend/js/app/nginx/redirection/form.js b/frontend/js/app/nginx/redirection/form.js index eec7bb97c..493b4aaee 100644 --- a/frontend/js/app/nginx/redirection/form.js +++ b/frontend/js/app/nginx/redirection/form.js @@ -71,8 +71,6 @@ module.exports = Mn.View.extend({ if (!checked) { this.ui.hsts_enabled.prop('checked', false); } - - this.ui.hsts_enabled.trigger('change'); }, 'change @ui.dns_challenge_switch': function () { @@ -230,7 +228,7 @@ module.exports = Mn.View.extend({ text: input }; }, - createFilter: /^(?:\*\.)?(?:[^.*]+\.?)+[^.]$/ + createFilter: /^(([^.]+\.)+[^.]+)|(\[[0-9a-f:]+\])$/ }); // Certificates diff --git a/frontend/js/app/nginx/stream/form.ejs b/frontend/js/app/nginx/stream/form.ejs index 1267719a0..9383abdea 100644 --- a/frontend/js/app/nginx/stream/form.ejs +++ b/frontend/js/app/nginx/stream/form.ejs @@ -21,7 +21,7 @@
- +
diff --git a/frontend/js/app/ui/footer/main.js b/frontend/js/app/ui/footer/main.js index 73f515e68..610b5005d 100644 --- a/frontend/js/app/ui/footer/main.js +++ b/frontend/js/app/ui/footer/main.js @@ -4,11 +4,5 @@ const Cache = require('../../cache'); module.exports = Mn.View.extend({ className: 'container', - template: template, - - templateContext: { - getVersion: function () { - return Cache.version || '0.0.0'; - } - } + template: template }); diff --git a/frontend/js/i18n/de-lang.json b/frontend/js/i18n/de-lang.json index 39bfb983e..ddad88f73 100644 --- a/frontend/js/i18n/de-lang.json +++ b/frontend/js/i18n/de-lang.json @@ -27,7 +27,7 @@ "all-hosts": { "advanced": "Erweitert", "advanced-config": "Individuelle Nginx-Konfiguration", - "advanced-config-header-info": "Bitte beachten Sie, dass das Hinzufügen eines Pfads '/' die Proxy-Konfiguration überschreibt", + "advanced-config-header-info": "Bitte beachten Sie, dass das Hinzufügen eines Pfads '/' die Proxy-Konfiguration überschreibt. Wenn Header gesetzt werden sollen, wird empfohlen more_set_headers zu nutzen.", "advanced-config-var-headline": "Diese Proxy-Details sind als nginx-Variablen verfügbar:", "advanced-warning": "Geben Sie hier Ihre eigene Nginx-Konfiguration ein - auf eigenes Risiko!", "cert-provider": "Zertifikat-Anbieter", @@ -35,7 +35,7 @@ "domain-names": "Domain-Namen", "empty-subtitle": "{manage, select, true{Warum erstellen Sie keinen?} other{Und Sie haben nicht die Erlaubnis, einen zu erstellen.}}", "enable-brotli": "Brotli einschalten", - "enable-crs": "CoreRuleSet aktivieren (Erfordert ModSecurity)", + "enable-crs": "CoreRuleSet aktivieren", "enable-hsts": "Aktivieren Sie HSTS und Sicherheits-Header", "enable-http3": "Aktiviere HTTP/3-Quic", "enable-modsec": "ModSecurity einschalten", diff --git a/frontend/js/i18n/en-lang.json b/frontend/js/i18n/en-lang.json index 09e41ce39..734faf3ca 100644 --- a/frontend/js/i18n/en-lang.json +++ b/frontend/js/i18n/en-lang.json @@ -27,7 +27,7 @@ "all-hosts": { "advanced": "Advanced", "advanced-config": "Custom Nginx Configuration", - "advanced-config-header-info": "Please note, adding a location '/' will overwrite the proxy configuration", + "advanced-config-header-info": "Please note, adding a location '/' will overwrite the proxy configuration. If you want to set headers I recommend you to use more_set_headers", "advanced-config-var-headline": "These proxy details are available as nginx variables:", "advanced-warning": "Enter your custom Nginx configuration here at your own risk!", "cert-provider": "Certificate Provider", @@ -35,7 +35,7 @@ "domain-names": "Domain Names", "empty-subtitle": "{manage, select, true{Why don't you create one?} other{And you don't have permission to create one.}}", "enable-brotli": "Enable Brotli", - "enable-crs": "Enable CoreRuleSet (Requires ModSecurity)", + "enable-crs": "Enable CoreRuleSet", "enable-hsts": "Enable HSTS and security headers", "enable-http3": "Enable HTTP/3-Quic", "enable-modsec": "Enable ModSecurity", diff --git a/frontend/js/login/ui/login.js b/frontend/js/login/ui/login.js index 757eb4e31..b2885f269 100644 --- a/frontend/js/login/ui/login.js +++ b/frontend/js/login/ui/login.js @@ -34,9 +34,6 @@ module.exports = Mn.View.extend({ }, templateContext: { - i18n: i18n, - getVersion: function () { - return $('#login').data('version'); - } + i18n: i18n } }); diff --git a/rootfs/html/dead/index.html b/rootfs/html/dead/index.html deleted file mode 100644 index fa14d0f01..000000000 --- a/rootfs/html/dead/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - Dead Host - - - - - -
-

Dead Host

-
- - diff --git a/rootfs/usr/local/bin/aio.sh b/rootfs/usr/local/bin/aio.sh index d75870baf..30119d065 100755 --- a/rootfs/usr/local/bin/aio.sh +++ b/rootfs/usr/local/bin/aio.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh if [ "$NC_AIO" = "true" ] && [ ! -f /data/etc/aio.lock ]; then while [ "$(healthcheck.sh)" != "OK" ]; do sleep 10s; done diff --git a/rootfs/usr/local/bin/entrypoint.sh b/rootfs/usr/local/bin/entrypoint.sh index 82bf28b79..fda642fa9 100755 --- a/rootfs/usr/local/bin/entrypoint.sh +++ b/rootfs/usr/local/bin/entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh if [ -n "$(ls -A /data/etc/prerun 2> /dev/null)" ]; then for script in /data/etc/prerun/*.sh; do diff --git a/rootfs/usr/local/bin/healthcheck.sh b/rootfs/usr/local/bin/healthcheck.sh index 35f7cd89c..bae9da18d 100755 --- a/rootfs/usr/local/bin/healthcheck.sh +++ b/rootfs/usr/local/bin/healthcheck.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh export HCNPM_IP="$NPM_IPV4_BINDING" export HCGOA_IP="$GOA_IPV4_BINDING" diff --git a/rootfs/usr/local/bin/launch.sh b/rootfs/usr/local/bin/launch.sh index 5297b8c60..70a73fcd1 100755 --- a/rootfs/usr/local/bin/launch.sh +++ b/rootfs/usr/local/bin/launch.sh @@ -1,15 +1,7 @@ -#!/bin/sh +#!/usr/bin/env sh echo " ------------------------------------- - _ _ ___ __ __ _ -| \ || . \| \ \ ___ | | _ _ ___ -| || _/| || . \| || | |[_-[ -|_\_||_| |_|_|_|| _/|_| \__|/__/ - |_| -------------------------------------- -Version: $(jq -r .version /app/package.json) -Date: $(date) User: $(whoami) PUID: $PUID User ID: $(id -u) @@ -36,6 +28,13 @@ if [ "$PHP83" = "true" ]; then fi fi +if [ "$PHP84" = "true" ]; then + if ! PHP_INI_SCAN_DIR=/data/php/84/conf.d php-fpm84 -c /data/php/84 -y /data/php/84/php-fpm.conf -FORt > /dev/null 2>&1; then + PHP_INI_SCAN_DIR=/data/php/84/conf.d php-fpm84 -c /data/php/84 -y /data/php/84/php-fpm.conf -FORt + sleep inf + fi +fi + if [ "$(echo "$ACME_SERVER" | sed "s|^https\?://\([^/]\+\).*$|\1|g")" = "acme.zerossl.com" ] && [ -z "$ACME_EAB_KID" ] && [ -z "$ACME_EAB_HMAC_KEY" ]; then if [ -z "$ACME_EMAIL" ]; then @@ -68,12 +67,19 @@ if [ ! -d /data/tls/certbot/accounts/"$(echo "$ACME_SERVER" | sed "s|^https\?:// sleep inf fi fi + echo fi +if [ "$ACME_OCSP_STAPLING" = "true" ]; then + certbot-ocsp-fetcher.sh -c /data/tls/certbot -o /data/tls/certbot/live --no-reload-webserver || true + echo +fi touch /data/etc/logrotate.lock +echo "Starting services..." if [ "$PHP82" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FOR; fi & if [ "$PHP83" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/83/conf.d php-fpm83 -c /data/php/83 -y /data/php/83/php-fpm.conf -FOR; fi & +if [ "$PHP84" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/84/conf.d php-fpm84 -c /data/php/84 -y /data/php/84/php-fpm.conf -FOR; fi & if [ "$LOGROTATE" = "true" ]; then while true; do touch /data/etc/logrotate.lock; logrotate --verbose --state /data/etc/logrotate.state /etc/logrotate; rm /data/etc/logrotate.lock; sleep 25h; done; fi & # shellcheck disable=SC2086 if [ "$GOA" = "true" ]; then while true; do if [ -f /data/nginx/access.log ] && [ ! -f /data/etc/logrotate.lock ]; then goaccess --no-global-config --num-tests=0 --tz="$TZ" --date-format="%d/%b/%Y" --time-format="%H:%M:%S" --log-format='[%d:%t %^] %v %h %T "%r" %s %b %b %R %u' --no-ip-validation \ diff --git a/rootfs/usr/local/bin/start.sh b/rootfs/usr/local/bin/start.sh index 1668fe8c2..aa406c351 100755 --- a/rootfs/usr/local/bin/start.sh +++ b/rootfs/usr/local/bin/start.sh @@ -1,16 +1,29 @@ -#!/bin/sh +#!/usr/bin/env sh + +echo " +------------------------------------- + _ _ ___ __ __ _ +| \ || . \| \ \ ___ | | _ _ ___ +| || _/| || . \| || | |[_-[ +|_\_||_| |_|_|_|| _/|_| \__|/__/ + |_| +------------------------------------- +Version: $(jq -r .version /app/package.json) +Date: $(date) +------------------------------------- +" if [ "$(whoami)" != "root" ] || [ "$(id -u)" != "0" ] || [ "$(id -g)" != "0" ]; then - echo '--------------------------------------' + echo "-----------------------------------------------------------------" echo "This docker container must be run as root, do not specify a user." - echo '--------------------------------------' + echo "-----------------------------------------------------------------" sleep inf fi if [ ! -d /data ]; then - echo '--------------------------------------' - echo "/data is not mounted! Check your docker configuration." - echo '--------------------------------------' + echo "----------------------------------------------" + echo "/data is not mounted! Check your compose.yaml." + echo "----------------------------------------------" sleep inf fi @@ -18,41 +31,38 @@ fi touch /data/.env . /data/.env - -if [ -n "$NPM_CERT_ID" ]; then - echo "NPM_CERT_ID env is replaced by DEFAULT_CERT_ID, please change it to DEFAULT_CERT_ID" +if [ -s /tmp/env.sha512sum ] && [ "$(cat /tmp/env.sha512sum)" != "$(sha512sum < /data/.env)" ]; then + echo "You need to recreate the NPMplus container after changing the .env file, restarting the container after changing the .env file is not supported" sleep inf fi -if [ -n "$LE_SERVER" ]; then - echo "LE_SERVER env is replaced by ACME_SERVER, please change it to ACME_SERVER" - sleep inf -fi +sha512sum < /data/.env > /tmp/env.sha512sum -if [ -n "$DEBUG" ]; then - echo "DEBUG env is unsopported." + +#tmp +if [ -n "$NPM_DISABLE_IPV6" ]; then + echo "NPM_DISABLE_IPV6 env is not supported. DISABLE_IPV6 will also disable IPv6 for the NPMplus web UI." sleep inf fi -if [ -n "$X_FRAME_OPTIONS" ]; then - echo "X_FRAME_OPTIONS env is unsopported." +#tmp +if [ -n "$GOA_DISABLE_IPV6" ]; then + echo "GOA_DISABLE_IPV6 env is not supported. DISABLE_IPV6 will also disable IPv6 for goaccess." sleep inf fi -if [ -n "$LE_STAGING" ]; then - echo "LE_STAGING env is unsopported, please use ACME_SERVER." +if [ -n "$LE_SERVER" ]; then + echo "LE_SERVER env is replaced by ACME_SERVER, please change it to ACME_SERVER" sleep inf fi -if [ -n "$PHP81" ]; then - find /data/nginx -type f -name '*.conf' -exec sed -i "s|fastcgi_pass php81;|fastcgi_pass php82;|g" {} \; - echo "PHP81 was removed, please use PHP82 or PHP83" +if [ -n "$LE_STAGING" ]; then + echo "LE_STAGING env is not supported, please use ACME_SERVER." sleep inf fi -if [ -n "$PHP81_APKS" ]; then - find /data/nginx -type f -name '*.conf' -exec sed -i "s|fastcgi_pass php81;|fastcgi_pass php82;|g" {} \; - echo "PHP81_APKS was removed, please use PHP82_APKS or PHP83_APKS" +if [ -n "$DEBUG" ]; then + echo "DEBUG env is not supported." sleep inf fi @@ -83,6 +93,16 @@ if ! echo "$ACME_MUST_STAPLE" | grep -q "^true$\|^false$"; then sleep inf fi +if ! echo "$ACME_OCSP_STAPLING" | grep -q "^true$\|^false$"; then + echo "ACME_OCSP_STAPLING needs to be true or false." + sleep inf +fi + +if ! echo "$ACME_KEY_TYPE" | grep -q "^ecdsa$\|^rsa$"; then + echo "ACME_KEY_TYPE needs to be ecdsa or rsa." + sleep inf +fi + if ! echo "$ACME_SERVER_TLS_VERIFY" | grep -q "^true$\|^false$"; then echo "ACME_SERVER_TLS_VERIFY needs to be true or false." sleep inf @@ -90,12 +110,22 @@ fi if ! echo "$PUID" | grep -q "^[0-9]\+$"; then - echo "PUID needs to be a number." + echo "PUID needs to be a number greater or equal to 1000, or equal to 0." + sleep inf +fi + +if [ "$PUID" -lt "1000" ] && [ "$PUID" != "0" ]; then + echo "PUID needs to be a number greater or equal to 1000, or equal to 0." sleep inf fi if ! echo "$PGID" | grep -q "^[0-9]\+$"; then - echo "PGID needs to be a number." + echo "PGID needs to be a number greater or equal to 1000, or equal to 0." + sleep inf +fi + +if [ "$PGID" -lt "1000" ] && [ "$PGID" != "0" ]; then + echo "PGID needs to be a number greater or equal to 1000, or equal to 0." sleep inf fi @@ -104,6 +134,10 @@ if [ "$PGID" != "0" ] && [ "$PUID" = "0" ]; then sleep inf fi +if [ "$PGID" = "0" ] && [ "$PUID" != "0" ]; then + echo "You've set PUID but not PGID. Are you sure that this is what you wanted?" +fi + if ! echo "$NIBEP" | grep -q "^[0-9]\+$"; then echo "NIBEP needs to be a number." @@ -149,17 +183,33 @@ if [ "$GOA_LISTEN_LOCALHOST" = "true" ]; then fi -if ! echo "$IPV4_BINDING" | grep -q "^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$"; then +if ! echo "$HTTP_PORT" | grep -q "^[0-9]\+$"; then + echo "HTTP_PORT needs to be a number." + sleep inf +fi + +if ! echo "$HTTPS_PORT" | grep -q "^[0-9]\+$"; then + echo "HTTPS_PORT needs to be a number." + sleep inf +fi + +if [ "$HTTP_PORT" = "$HTTPS_PORT" ] && [ "$DISABLE_HTTP" = "false" ]; then + echo "HTTP_PORT and HTTPS_PORT need to be different." + sleep inf +fi + + +if ! echo "$IPV4_BINDING" | grep -q "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$"; then echo "IPV4_BINDING needs to be a IPv4-Address: four blocks of numbers separated by dots." sleep inf fi -if ! echo "$NPM_IPV4_BINDING" | grep -q "^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$"; then +if ! echo "$NPM_IPV4_BINDING" | grep -q "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$"; then echo "NPM_IPV4_BINDING needs to be a IPv4-Address: four blocks of numbers separated by dots." sleep inf fi -if ! echo "$GOA_IPV4_BINDING" | grep -q "^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$"; then +if ! echo "$GOA_IPV4_BINDING" | grep -q "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$"; then echo "GOA_IPV4_BINDING needs to be a IPv4-Address: four blocks of numbers separated by dots." sleep inf fi @@ -185,16 +235,6 @@ if ! echo "$DISABLE_IPV6" | grep -q "^true$\|^false$"; then sleep inf fi -if ! echo "$NPM_DISABLE_IPV6" | grep -q "^true$\|^false$"; then - echo "NPM_DISABLE_IPV6 needs to be true or false." - sleep inf -fi - -if ! echo "$GOA_DISABLE_IPV6" | grep -q "^true$\|^false$"; then - echo "GOA_DISABLE_IPV6 needs to be true or false." - sleep inf -fi - if ! echo "$DEFAULT_CERT_ID" | grep -q "^[0-9]\+$"; then echo "DEFAULT_CERT_ID needs to be a number." @@ -211,6 +251,11 @@ if ! echo "$DISABLE_H3_QUIC" | grep -q "^true$\|^false$"; then sleep inf fi +if ! echo "$NGINX_QUIC_BPF" | grep -q "^true$\|^false$"; then + echo "NGINX_QUIC_BPF needs to be true or false." + sleep inf +fi + if ! echo "$NGINX_LOG_NOT_FOUND" | grep -q "^true$\|^false$"; then echo "NGINX_LOG_NOT_FOUND needs to be true or false." sleep inf @@ -221,6 +266,16 @@ if ! echo "$NGINX_404_REDIRECT" | grep -q "^true$\|^false$"; then sleep inf fi +if ! echo "$NGINX_HSTS_SUBDMAINS" | grep -q "^true$\|^false$"; then + echo "NGINX_HSTS_SUBDMAINS needs to be true or false." + sleep inf +fi + +if ! echo "$X_FRAME_OPTIONS" | grep -q "^none$\|^sameorigin$\|^deny$"; then + echo "X_FRAME_OPTIONS needs to be none, sameorigin or deny." + sleep inf +fi + if ! echo "$NGINX_DISABLE_PROXY_BUFFERING" | grep -q "^true$\|^false$"; then echo "NGINX_DISABLE_PROXY_BUFFERING needs to be true or false." sleep inf @@ -295,8 +350,8 @@ if [ -n "$GOACLA" ] && ! echo "$GOACLA" | grep -q "^-[a-zA-Z0-9 =/_.-]\+$"; then fi -if [ -n "$PHP_APKS" ] && [ "$PHP82" = "false" ] && [ "$PHP83" = "false" ]; then - echo "PHP_APKS is set, but PHP82 and PHP83 is disabled." +if [ -n "$PHP_APKS" ] && [ "$PHP82" = "false" ] && [ "$PHP83" = "false" ] && [ "$PHP84" = "false" ]; then + echo "PHP_APKS is set, but PHP82, PHP83 and PHP84 is disabled." sleep inf fi @@ -333,102 +388,140 @@ if [ -n "$PHP83_APKS" ] && ! echo "$PHP83_APKS" | grep -q "^[a-z0-9 _-]\+$"; the fi -if [ -n "$INITIAL_ADMIN_EMAIL" ] && ! echo "$INITIAL_ADMIN_EMAIL" | grep -q "^.*@.*$"; then - echo "INITIAL_ADMIN_EMAIL needs to contains @." +if ! echo "$PHP84" | grep -q "^true$\|^false$"; then + echo "PHP84 needs to be true or false." sleep inf fi +if [ -n "$PHP84_APKS" ] && [ "$PHP84" = "false" ]; then + echo "PHP84_APKS is set, but PHP84 is disabled." + sleep inf +fi -if [ -n "$NC_AIO" ] && ! echo "$NC_AIO" | grep -q "^true$\|^false$"; then - echo "NC_AIO needs to be true or false." +if [ -n "$PHP84_APKS" ] && ! echo "$PHP84_APKS" | grep -q "^[a-z0-9 _-]\+$"; then + echo "PHP84_APKS can consist of lower letters a-z, numbers 0-9, spaces, underscores and hyphens." + sleep inf +fi + + +if [ -n "$INITIAL_ADMIN_EMAIL" ] && ! echo "$INITIAL_ADMIN_EMAIL" | grep -q "@.*\."; then + echo "INITIAL_ADMIN_EMAIL needs to contains a @ and one dot." + sleep inf +fi + +if [ -n "$INITIAL_DEFAULT_PAGE" ] && ! echo "$INITIAL_DEFAULT_PAGE" | grep -q "^\(404\|444\|redirect\|congratulations\|html\)$"; then + echo "INITIAL_DEFAULT_PAGE needs to be 404, 444, redirect, congratulations or html." sleep inf fi -if [ "$NC_AIO" = "true" ] && ([ -z "$NC_DOMAIN" ] || ! echo "$NC_DOMAIN" | grep -q "^[a-z0-9.]\+$"); then - echo "NC_DOMAIN must consist of lower letters a-z, numbers 0-9 and dots and is required in AIO mode." + +if [ -n "$NC_AIO" ] && ! echo "$NC_AIO" | grep -q "^true$\|^false$"; then + echo "NC_AIO needs to be true or false." sleep inf fi if [ "$NC_AIO" = "true" ]; then export DISABLE_HTTP="true" + if [ -z "$NC_DOMAIN" ]; then + echo "NC_DOMAIN is required in AIO mode." + sleep inf + fi fi +if [ ! -s /data/etc/npm/env.sha512sum ] || [ "$(cat /data/etc/npm/env.sha512sum)" != "$( (grep "env\.[A-Z0-9_]\+" -roh /app/templates | sed "s|env.||g" | sort | uniq | xargs printenv; echo "$TV") | tr -d "\n" | sha512sum | cut -d" " -f1)" ]; then + echo "At least one ENV changed, all hosts will be regenerated." + export REGENERATE_ALL="true" +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 + +if [ "$ACME_MUST_STAPLE" = "false" ]; then + sed -i "s|must-staple = true|must-staple = false|g" /etc/certbot.ini +fi +if [ "$ACME_KEY_TYPE" = "rsa" ]; then + sed -i "s|key-type = ecdsa|key-type = rsa|g" /etc/certbot.ini fi if [ "$PHP82" = "true" ]; then - apk add --no-cache php82-fpm - # From https://github.com/nextcloud/all-in-one/pull/1377/files if [ -n "$PHP82_APKS" ]; then for apk in $(echo "$PHP82_APKS" | tr " " "\n"); do - if ! echo "$apk" | grep -q "^php82-.*$"; then echo "$apk is a non allowed value." echo "It needs to start with \"php82-\"." echo "It is set to \"$apk\"." sleep inf fi - echo "Installing $apk via apk..." if ! apk add --no-cache "$apk" > /dev/null 2>&1; then echo "The apk \"$apk\" was not installed!" fi - done fi - mkdir -vp /data/php cp -varnT /etc/php82 /data/php/82 - sed -i "s|listen =.*|listen = /run/php82.sock|" /data/php/82/php-fpm.d/www.conf + sed -i "s|#\?listen =.*|listen = /run/php82.sock|" /data/php/82/php-fpm.d/www.conf sed -i "s|;error_log =.*|error_log = /proc/self/fd/2|g" /data/php/82/php-fpm.conf sed -i "s|include=.*|include=/data/php/82/php-fpm.d/*.conf|g" /data/php/82/php-fpm.conf - elif [ "$FULLCLEAN" = "true" ]; then rm -vrf /data/php/82 fi if [ "$PHP83" = "true" ]; then - apk add --no-cache php83-fpm - # From https://github.com/nextcloud/all-in-one/pull/1377/files if [ -n "$PHP83_APKS" ]; then for apk in $(echo "$PHP83_APKS" | tr " " "\n"); do - if ! echo "$apk" | grep -q "^php83-.*$"; then echo "$apk is a non allowed value." echo "It needs to start with \"php83-\"." echo "It is set to \"$apk\"." sleep inf fi - echo "Installing $apk via apk..." if ! apk add --no-cache "$apk" > /dev/null 2>&1; then echo "The apk \"$apk\" was not installed!" fi - done fi - mkdir -vp /data/php cp -varnT /etc/php83 /data/php/83 - sed -i "s|listen =.*|listen = /run/php83.sock|" /data/php/83/php-fpm.d/www.conf + sed -i "s|#\?listen =.*|listen = /run/php83.sock|" /data/php/83/php-fpm.d/www.conf sed -i "s|;error_log =.*|error_log = /proc/self/fd/2|g" /data/php/83/php-fpm.conf sed -i "s|include=.*|include=/data/php/83/php-fpm.d/*.conf|g" /data/php/83/php-fpm.conf - elif [ "$FULLCLEAN" = "true" ]; then rm -vrf /data/php/83 fi -if { [ "$PHP82" = "true" ] || [ "$PHP83" = "true" ]; } && [ -n "$PHP_APKS" ]; then +if [ "$PHP84" = "true" ]; then + apk add --no-cache php84-fpm + # From https://github.com/nextcloud/all-in-one/pull/1377/files + if [ -n "$PHP84_APKS" ]; then + for apk in $(echo "$PHP84_APKS" | tr " " "\n"); do + if ! echo "$apk" | grep -q "^php84-.*$"; then + echo "$apk is a non allowed value." + echo "It needs to start with \"php84-\"." + echo "It is set to \"$apk\"." + sleep inf + fi + echo "Installing $apk via apk..." + if ! apk add --no-cache "$apk" > /dev/null 2>&1; then + echo "The apk \"$apk\" was not installed!" + fi + done + fi + mkdir -vp /data/php + cp -varnT /etc/php84 /data/php/84 + sed -i "s|#\?listen =.*|listen = /run/php84.sock|" /data/php/84/php-fpm.d/www.conf + sed -i "s|;error_log =.*|error_log = /proc/self/fd/2|g" /data/php/84/php-fpm.conf + sed -i "s|include=.*|include=/data/php/84/php-fpm.d/*.conf|g" /data/php/84/php-fpm.conf +elif [ "$FULLCLEAN" = "true" ]; then + rm -vrf /data/php/84 +fi + +if { [ "$PHP82" = "true" ] || [ "$PHP83" = "true" ] || [ "$PHP84" = "true" ]; } && [ -n "$PHP_APKS" ]; then # From https://github.com/nextcloud/all-in-one/pull/1377/files for apk in $(echo "$PHP_APKS" | tr " " "\n"); do if ! echo "$apk" | grep -q "^php-.*$"; then @@ -444,6 +537,9 @@ if { [ "$PHP82" = "true" ] || [ "$PHP83" = "true" ]; } && [ -n "$PHP_APKS" ]; th done fi +if [ "$FULLCLEAN" = "true" ] && [ "$PHP82" = "false" ] && [ "$PHP83" = "false" ] && [ "$PHP84" = "false" ]; then + rm -vrf /data/php +fi if [ "$LOGROTATE" = "true" ]; then sed -i "s|rotate [0-9]\+|rotate $LOGROTATIONS|g" /etc/logrotate @@ -457,18 +553,22 @@ elif [ "$FULLCLEAN" = "true" ]; then /data/nginx/stream.log.* fi -mkdir -p /tmp/acme-challenge \ - /tmp/certbot-work \ - /tmp/certbot-log \ - /tmp/npmhome \ - /tmp/goa - if [ -d /data/nginx/custom ]; then mv -vn /data/nginx/custom /data/nginx_custom fi -mkdir -vp /data/tls/certbot/credentials \ - /data/tls/certbot/renewal \ +#tmp +if [ -d /data/nginx_custom ]; then + mv -vn /data/nginx_custom /data/custom_nginx +fi + +mkdir -p /tmp/acme-challenge \ + /tmp/npmhome \ + /tmp/goa \ + /tmp/certbot-log \ + /tmp/certbot-work \ + /tmp/certbot-credentials +mkdir -vp /data/tls/certbot/renewal \ /data/tls/custom \ /data/etc/npm \ /data/etc/html \ @@ -480,40 +580,37 @@ mkdir -vp /data/tls/certbot/credentials \ /data/nginx/proxy_host \ /data/nginx/dead_host \ /data/nginx/stream \ - /data/nginx_custom + /data/custom_nginx +touch /tmp/ip_ranges.conf \ + /data/etc/html/index.html \ + /data/custom_nginx/events.conf \ + /data/custom_nginx/http.conf \ + /data/custom_nginx/http_top.conf \ + /data/custom_nginx/root_top.conf \ + /data/custom_nginx/root.conf \ + /data/custom_nginx/server_dead.conf \ + /data/custom_nginx/server_proxy.conf \ + /data/custom_nginx/server_redirect.conf \ + /data/custom_nginx/stream.conf \ + /data/custom_nginx/stream_top.conf \ + /data/custom_nginx/server_stream.conf \ + /data/custom_nginx/server_stream_tcp.conf \ + /data/custom_nginx/server_stream_udp.conf \ + /data/etc/modsecurity/modsecurity-extra.conf -if [ -s /data/database.sqlite ] && [ "$DB_SQLITE_FILE" != "/data/database.sqlite" ]; then - mv -vn /data/database.sqlite "$DB_SQLITE_FILE" +if [ -s /data/database.sqlite ]; then + mv -vn /data/database.sqlite /data/etc/npm/database.sqlite fi -if [ -s /data/etc/logrotate.status ]; then - mv -vn /data/etc/logrotate.status /data/etc/logrotate.state +if [ -s "$DB_SQLITE_FILE" ] && [ "$DB_SQLITE_FILE" != "/data/etc/npm/database.sqlite" ]; then + mv -vn "$DB_SQLITE_FILE" /data/etc/npm/database.sqlite + echo "DB_SQLITE_FILE is not supported." fi if [ -s /data/keys.json ]; then mv -vn /data/keys.json /data/etc/npm/keys.json fi -if [ -s /data/nginx/default_host/site.conf ]; then - mv -vn /data/nginx/default_host/site.conf /data/nginx/default.conf -fi - -if [ -s /data/nginx/default_www/index.html ]; then - mv -vn /data/nginx/default_www/index.html /data/etc/html/index.html -fi - -if [ -s /data/nginx/dummycert.pem ]; then - mv -vn /data/nginx/dummycert.pem /data/tls/dummycert.pem -fi - -if [ -s /data/nginx/dummykey.pem ]; then - mv -vn /data/nginx/dummykey.pem /data/tls/dummykey.pem -fi - -if [ -f /data/nginx_custom/root.conf ]; then - mv -vn /data/nginx_custom/root.conf /data/nginx_custom/root_top.conf -fi - if [ -n "$(ls -A /data/nginx/html 2> /dev/null)" ]; then mv -vn /data/nginx/html/* /data/etc/html fi @@ -522,25 +619,18 @@ if [ -n "$(ls -A /data/access 2> /dev/null)" ]; then mv -vn /data/access/* /data/etc/access fi -if [ -n "$(ls -A /data/nginx/access 2> /dev/null)" ]; then - mv -vn /data/nginx/access/* /data/etc/access +if [ -n "$(ls -A /data/custom_ssl 2> /dev/null)" ]; then + mv -vn /data/custom_ssl/* /data/tls/custom fi if [ -n "$(ls -A /etc/letsencrypt 2> /dev/null)" ]; then cp -van /etc/letsencrypt/* /data/tls/certbot + find /data/tls/certbot/renewal -type f -name '*.conf' -exec sed -i "s|/etc/letsencrypt|/data/tls/certbot|g" {} \; + rm -r /etc/letsencrypt/* fi -if [ -n "$(ls -A /data/letsencrypt 2> /dev/null)" ]; then - mv -vn /data/letsencrypt/* /data/tls/certbot -fi - -if [ -n "$(ls -A /data/custom_ssl 2> /dev/null)" ]; then - mv -vn /data/custom_ssl/* /data/tls/custom -fi -if [ -n "$(ls -A /data/ssl 2> /dev/null)" ]; then - mv -vn /data/ssl/* /data/tls -fi +find /data/tls/certbot/renewal -type f -name '*.conf' -exec sed -i "s|/data/tls/certbot/credentials|/tmp/certbot-credentials|g" {} \; if [ -d /data/tls/certbot/live ] && [ -d /data/tls/certbot/archive ]; then find /data/tls/certbot/live ! -name "$(printf "*\n*")" -type f -name "*.pem" > tmp @@ -552,6 +642,7 @@ if [ -d /data/tls/certbot/live ] && [ -d /data/tls/certbot/archive ]; then rm tmp fi + if [ "$CLEAN" = "true" ]; then rm -vrf /data/letsencrypt-acme-challenge \ /data/nginx/dummycert.pem \ @@ -567,16 +658,19 @@ if [ "$CLEAN" = "true" ]; then /data/custom_ssl \ /data/certbot \ /data/access \ - /data/php/8 \ - /data/php/7 \ /data/ssl \ /data/logs \ /data/error.log \ /data/nginx/error.log \ + /data/nginx/default.conf \ /data/nginx/ip_ranges.conf + + if [ -s /data/etc/npm/database.sqlite ]; then + sqlite-vaccum.js + fi + rm -vf /data/tls/certbot/crs/*.pem rm -vf /data/tls/certbot/keys/*.pem - if [ -d /data/tls/certbot/live ] && [ -d /data/tls/certbot/archive ]; then certs_in_use="$(find /data/tls/certbot/live -type l -name "*.pem" -exec readlink -f {} \;)" export certs_in_use @@ -592,76 +686,6 @@ if [ "$CLEAN" = "true" ]; then fi fi -if [ -s "$DB_SQLITE_FILE" ]; then - sqlite-vaccum.js -fi - -if [ "$FULLCLEAN" = "true" ]; then - if [ "$PHP82" != "true" ] && [ "$PHP83" != "true" ]; then - rm -vrf /data/php - fi -fi - -touch /tmp/ip_ranges.conf \ - /data/etc/html/index.html \ - /data/nginx_custom/events.conf \ - /data/nginx_custom/http.conf \ - /data/nginx_custom/http_top.conf \ - /data/nginx_custom/root_top.conf \ - /data/nginx_custom/server_dead.conf \ - /data/nginx_custom/server_proxy.conf \ - /data/nginx_custom/server_redirect.conf \ - /data/nginx_custom/stream.conf \ - /data/nginx_custom/stream_top.conf \ - /data/nginx_custom/server_stream.conf \ - /data/nginx_custom/server_stream_tcp.conf \ - /data/nginx_custom/server_stream_udp.conf \ - /data/etc/modsecurity/modsecurity-extra.conf - -find /data/nginx -type f -name '*.conf' -exec sed -i "s|nginx/custom|nginx_custom|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s| http2||g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|\(listen .*\) http3|\1 quic|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|quic reuseport;|quic;|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|security_headers on;|include conf.d/include/hsts.conf;|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|more_set_headers \"Alt-Svc: h3=':443'; ma=86400\";|more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/access|/data/nginx/access|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/nginx/access|/data/etc/access|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/nginx/html/|/data/etc/html/|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/custom_ssl|/data/tls/custom|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/etc/letsencrypt|/data/tls/certbot|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/letsencrypt|/data/tls/certbot|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/data/ssl|/data/tls|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|ssl_certificate_key /data/nginx/dummykey.pem;|ssl_certificate_key /data/tls/dummykey.pem;|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|ssl_certificate /data/nginx/dummycert.pem;|ssl_certificate /data/tls/dummycert.pem;|g" {} \; - -find /data/tls/certbot/renewal -type f -name '*.conf' -exec sed -i "s|/data/ssl|/data/tls|g" {} \; -find /data/tls/certbot/renewal -type f -name '*.conf' -exec sed -i "s|/etc/letsencrypt|/data/tls/certbot|g" {} \; -find /data/tls/certbot/renewal -type f -name '*.conf' -exec sed -i "s|/data/letsencrypt|/data/tls/certbot|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "/block-exploits.conf/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|/html/404|/html/dead|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|include conf.d/include/acme-challenge.conf;|include conf.d/include/always.conf;|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|include conf.d/include/letsencrypt-acme-challenge.conf;|include conf.d/include/always.conf;|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "s|include conf.d/include/force-ssl.conf;|include conf.d/include/force-tls.conf;|g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s|include conf.d/include/ssl-ciphers.conf;|include conf.d/include/tls-ciphers.conf;|g" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "/http3/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "/Asset Caching/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "/assets.conf/d" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "/error_log/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "/access_log/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "/proxy_http_version/d" {} \; - -find /data/nginx -type f -name '*.conf' -exec sed -i "/ssl_stapling/d" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "/ssl_stapling_verify/d" {} \; - -if [ -s /data/nginx/default.conf ]; then sed -i "/ssl_stapling/d" /data/nginx/default.conf; fi -if [ -s /data/nginx/default.conf ]; then sed -i "/ssl_stapling_verify/d" /data/nginx/default.conf; fi if [ ! -s /data/etc/modsecurity/modsecurity-default.conf ]; then cp -van /usr/local/nginx/conf/conf.d/include/modsecurity.conf.example /data/etc/modsecurity/modsecurity-default.conf @@ -687,135 +711,8 @@ if [ ! -s /data/etc/modsecurity/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.exam fi cp -a /usr/local/nginx/conf/conf.d/include/coreruleset/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example /data/etc/modsecurity/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example -cp -va /usr/local/nginx/conf/conf.d/include/coreruleset/plugins/* /data/etc/modsecurity/crs-plugins - - -sed -i "s|48693|$NIBEP|g" /app/index.js -sed -i "s|48693|$NIBEP|g" /usr/local/nginx/conf/conf.d/npm.conf - -sed -i "s|48683|$GOAIWSP|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf - -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $IPV4_BINDING:\2/g" /app/templates/_listen.conf -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $IPV4_BINDING:\2/g" /app/templates/default.conf -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\({{ incoming_port }}\)/listen $IPV4_BINDING:\2/g" /app/templates/stream.conf -find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $IPV4_BINDING:\2/g" {} \; -find /data/nginx -type f -name '*.conf' -exec sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9-]\+\)/listen $IPV4_BINDING:\2/g" {} \; - -if [ "$DISABLE_IPV6" = "true" ]; then - sed -i "s|ipv6=on;|ipv6=off;|g" /usr/local/nginx/conf/nginx.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /app/templates/_listen.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /app/templates/default.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\({{ incoming_port }}\)/#listen \[\1\]:\2/g" /app/templates/stream.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9-]\+\)/#listen \[\1\]:\2/g" {} \; -else - sed -i "s|ipv6=off;|ipv6=on;|g" /usr/local/nginx/conf/nginx.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $IPV6_BINDING:\2/g" /app/templates/_listen.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $IPV6_BINDING:\2/g" /app/templates/default.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\({{ incoming_port }}\)/listen $IPV6_BINDING:\2/g" /app/templates/stream.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $IPV6_BINDING:\2/g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9-]\+\)/listen $IPV6_BINDING:\2/g" {} \; -fi - -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $NPM_IPV4_BINDING:$NPM_PORT/g" /usr/local/nginx/conf/conf.d/npm.conf -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $NPM_IPV4_BINDING:$NPM_PORT/g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf - -if [ "$NPM_DISABLE_IPV6" = "true" ]; then - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /usr/local/nginx/conf/conf.d/npm.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf -else - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $NPM_IPV6_BINDING:$NPM_PORT/g" /usr/local/nginx/conf/conf.d/npm.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $NPM_IPV6_BINDING:$NPM_PORT/g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf -fi - -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $GOA_IPV4_BINDING:$GOA_PORT/g" /usr/local/nginx/conf/conf.d/include/goaccess.conf -sed -i "s/#\?listen \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:\)\?\([0-9]\+\)/listen $GOA_IPV4_BINDING:$GOA_PORT/g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf - -if [ "$GOA_DISABLE_IPV6" = "true" ]; then - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /usr/local/nginx/conf/conf.d/include/goaccess.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/#listen \[\1\]:\2/g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -else - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $GOA_IPV6_BINDING:$GOA_PORT/g" /usr/local/nginx/conf/conf.d/include/goaccess.conf - sed -i "s/#\?listen \[\([0-9a-f:]\+\)\]:\([0-9]\+\)/listen $GOA_IPV6_BINDING:$GOA_PORT/g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -fi - -if [ "$DISABLE_HTTP" = "true" ]; then - sed -i "s|#\?\(listen.*80\)|#\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen.*80\)|#\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*80\)|#\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*80\)|#\1|g" {} \; -elif [ "$DISABLE_IPV6" = "true" ]; then - sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:80\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:80\)|\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:80\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+:80\)|\1|g" {} \; -else - sed -i "s|#\?\(listen.*80\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen.*80\)|\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*80\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*80\)|\1|g" {} \; -fi - -if [ "$DISABLE_H3_QUIC" = "true" ]; then - sed -i "s|#\?\(listen.*quic\)|#\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|#\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen.*quic\)|#\1|g" /app/templates/default.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|#\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*quic\)|#\1|g" {} \; - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|#\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*quic\)|#\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|#\1|g" {} \; -elif [ "$DISABLE_IPV6" = "true" ]; then - sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+.*quic\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+.*quic\)|\1|g" /app/templates/default.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+.*quic\)|\1|g" {} \; - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+.*quic\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" {} \; -else - sed -i "s|#\?\(listen.*quic\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" /app/templates/_listen.conf - sed -i "s|#\?\(listen.*quic\)|\1|g" /app/templates/default.conf - sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" /app/templates/default.conf - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*quic\)|\1|g" {} \; - find /usr/local/nginx/conf/conf.d -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(listen.*quic\)|\1|g" {} \; - find /data/nginx -type f -name '*.conf' -exec sed -i "s|#\?\(more_set_headers 'Alt-Svc: h3=\":443\"; ma=86400';\)|\1|g" {} \; -fi - -if [ "$NGINX_LOG_NOT_FOUND" = "true" ]; then - sed -i "s|log_not_found.*|log_not_found on;|g" /usr/local/nginx/conf/nginx.conf -else - sed -i "s|log_not_found.*|log_not_found off;|g" /usr/local/nginx/conf/nginx.conf -fi +cp -a /usr/local/nginx/conf/conf.d/include/coreruleset/plugins/* /data/etc/modsecurity/crs-plugins -if [ "$NGINX_404_REDIRECT" = "true" ]; then - sed -i "s|#error_page 404|error_page 404|g" /usr/local/nginx/conf/nginx.conf -else - sed -i "s|error_page 404|#error_page 404|g" /usr/local/nginx/conf/nginx.conf -fi - -if [ "$NGINX_DISABLE_PROXY_BUFFERING" = "true" ]; then - sed -i "s|proxy_buffering.*|proxy_buffering off;|g" /usr/local/nginx/conf/nginx.conf - sed -i "s|proxy_request_buffering.*|proxy_request_buffering off;|g" /usr/local/nginx/conf/nginx.conf -else - sed -i "s|proxy_buffering.*|proxy_buffering on;|g" /usr/local/nginx/conf/nginx.conf - sed -i "s|proxy_request_buffering.*|proxy_request_buffering on;|g" /usr/local/nginx/conf/nginx.conf -fi - -if [ "$LOGROTATE" = "true" ]; then - sed -i "s|access_log off; # http|access_log /data/nginx/access.log log;|g" /usr/local/nginx/conf/nginx.conf - sed -i "s|access_log off; # stream|access_log /data/nginx/stream.log proxy;|g" /usr/local/nginx/conf/nginx.conf -else - sed -i "s|access_log /data/nginx/access.log log;|access_log off; # http|g" /usr/local/nginx/conf/nginx.conf - sed -i "s|access_log /data/nginx/stream.log proxy;|access_log off; # stream|g" /usr/local/nginx/conf/nginx.conf -fi - -if [ -s /data/tls/certbot/config.ini ]; then - echo "tls/certbot/config.ini is now unsupported, to remove this warning, just delete the file - some options are replaced by env." -fi if [ ! -s /data/etc/crowdsec/ban.html ]; then cp -van /usr/local/nginx/conf/conf.d/include/ban.html /data/etc/crowdsec/ban.html @@ -847,66 +744,56 @@ if [ "$DEFAULT_CERT_ID" = "0" ]; then export DEFAULT_KEY=/data/tls/dummykey.pem echo "no DEFAULT_CERT_ID set, using dummycerts." else - if [ -d "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID" ]; then - if [ ! -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/fullchain.pem ]; then - echo "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID/fullchain.pem does not exist" + if [ -d "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID" ]; then + if [ ! -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/fullchain.pem ]; then + echo "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID/fullchain.pem does not exist" + export DEFAULT_CERT=/data/tls/dummycert.pem + export DEFAULT_KEY=/data/tls/dummykey.pem + echo "using dummycerts." + else + export DEFAULT_CERT=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/fullchain.pem + echo "DEFAULT_CERT set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID/fullchain.pem" + if [ ! -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/privkey.pem ]; then + echo "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID/privkey.pem does not exist" export DEFAULT_CERT=/data/tls/dummycert.pem export DEFAULT_KEY=/data/tls/dummykey.pem echo "using dummycerts." else - export DEFAULT_CERT=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/fullchain.pem - echo "DEFAULT_CERT set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID/fullchain.pem" - - if [ ! -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/privkey.pem ]; then - echo "/data/tls/certbot/live/npm-$DEFAULT_CERT_ID/privkey.pem does not exist" - export DEFAULT_CERT=/data/tls/dummycert.pem - export DEFAULT_KEY=/data/tls/dummykey.pem - echo "using dummycerts." - else - export DEFAULT_KEY=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/privkey.pem - echo "DEFAULT_KEY set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID/privkey.pem" - - if [ -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID".der ]; then - export DEFAULT_STAPLING_FILE=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID".der - echo "DEFAULT_STAPLING_FILE set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID.der" - fi + export DEFAULT_KEY=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID"/privkey.pem + echo "DEFAULT_KEY set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID/privkey.pem" + if [ -s /data/tls/certbot/live/npm-"$DEFAULT_CERT_ID".der ] && [ "$ACME_OCSP_STAPLING" = "true" ]; then + export DEFAULT_STAPLING_FILE=/data/tls/certbot/live/npm-"$DEFAULT_CERT_ID".der + echo "DEFAULT_STAPLING_FILE set to /data/tls/certbot/live/npm-$DEFAULT_CERT_ID.der" fi fi - - elif [ -d "/data/tls/custom/npm-$DEFAULT_CERT_ID" ]; then - if [ ! -s /data/tls/custom/npm-"$DEFAULT_CERT_ID"/fullchain.pem ]; then - echo "/data/tls/custom/npm-$DEFAULT_CERT_ID/fullchain.pem does not exist" + fi + elif [ -d "/data/tls/custom/npm-$DEFAULT_CERT_ID" ]; then + if [ ! -s /data/tls/custom/npm-"$DEFAULT_CERT_ID"/fullchain.pem ]; then + echo "/data/tls/custom/npm-$DEFAULT_CERT_ID/fullchain.pem does not exist" + export DEFAULT_CERT=/data/tls/dummycert.pem + export DEFAULT_KEY=/data/tls/dummykey.pem + echo "using dummycerts." + else + export DEFAULT_CERT=/data/tls/custom/npm-"$DEFAULT_CERT_ID"/fullchain.pem + echo "DEFAULT_CERT set to /data/tls/custom/npm-$DEFAULT_CERT_ID/fullchain.pem" + if [ ! -s /data/tls/custom/npm-"$DEFAULT_CERT_ID"/privkey.pem ]; then + echo "/data/tls/custom/npm-$DEFAULT_CERT_ID/privkey.pem does not exist" export DEFAULT_CERT=/data/tls/dummycert.pem export DEFAULT_KEY=/data/tls/dummykey.pem echo "using dummycerts." else - export DEFAULT_CERT=/data/tls/custom/npm-"$DEFAULT_CERT_ID"/fullchain.pem - echo "DEFAULT_CERT set to /data/tls/custom/npm-$DEFAULT_CERT_ID/fullchain.pem" - - if [ ! -s /data/tls/custom/npm-"$DEFAULT_CERT_ID"/privkey.pem ]; then - echo "/data/tls/custom/npm-$DEFAULT_CERT_ID/privkey.pem does not exist" - export DEFAULT_CERT=/data/tls/dummycert.pem - export DEFAULT_KEY=/data/tls/dummykey.pem - echo "using dummycerts." - else - export DEFAULT_KEY=/data/tls/custom/npm-"$DEFAULT_CERT_ID"/privkey.pem - echo "DEFAULT_KEY set to /data/tls/custom/npm-$DEFAULT_CERT_ID/privkey.pem" - fi + export DEFAULT_KEY=/data/tls/custom/npm-"$DEFAULT_CERT_ID"/privkey.pem + echo "DEFAULT_KEY set to /data/tls/custom/npm-$DEFAULT_CERT_ID/privkey.pem" fi - - else - export DEFAULT_CERT=/data/tls/dummycert.pem - export DEFAULT_KEY=/data/tls/dummykey.pem - echo "cert with ID $DEFAULT_CERT_ID does not exist, using dummycerts." fi + else + export DEFAULT_CERT=/data/tls/dummycert.pem + export DEFAULT_KEY=/data/tls/dummykey.pem + echo "cert with ID $DEFAULT_CERT_ID does not exist, using dummycerts." + fi fi -if [ "$DEFAULT_CERT" = "/data/tls/dummycert.pem" ] && [ "$DEFAULT_KEY" != "/data/tls/dummykey.pem" ]; then - export DEFAULT_CERT=/data/tls/dummycert.pem - export DEFAULT_KEY=/data/tls/dummykey.pem - echo "something went wrong, using dummycerts." -fi -if [ "$DEFAULT_CERT" != "/data/tls/dummycert.pem" ] && [ "$DEFAULT_KEY" = "/data/tls/dummykey.pem" ]; then +if { [ "$DEFAULT_CERT" = "/data/tls/dummycert.pem" ] && [ "$DEFAULT_KEY" != "/data/tls/dummykey.pem" ]; } || { [ "$DEFAULT_CERT" != "/data/tls/dummycert.pem" ] && [ "$DEFAULT_KEY" = "/data/tls/dummykey.pem" ]; }; then export DEFAULT_CERT=/data/tls/dummycert.pem export DEFAULT_KEY=/data/tls/dummykey.pem echo "something went wrong, using dummycerts." @@ -915,111 +802,86 @@ fi if [ "$DEFAULT_CERT" = "/data/tls/dummycert.pem" ] || [ "$DEFAULT_KEY" = "/data/tls/dummykey.pem" ]; then if [ ! -s /data/tls/dummycert.pem ] || [ ! -s /data/tls/dummykey.pem ]; then rm -vrf /data/tls/dummycert.pem /data/tls/dummykey.pem - openssl req -new -newkey rsa:4096 -days 365000 -nodes -x509 -subj '/CN=*' -sha256 -keyout /data/tls/dummykey.pem -out /data/tls/dummycert.pem + openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 365000 -nodes -x509 -subj '/CN=*' -sha512 -keyout /data/tls/dummykey.pem -out /data/tls/dummycert.pem fi + unset DEFAULT_STAPLING_FILE else rm -vrf /data/tls/dummycert.pem /data/tls/dummykey.pem fi sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /app/templates/default.conf sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /app/templates/default.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /app/templates/default.conf +if [ -n "$DEFAULT_STAPLING_FILE" ] && [ "$ACME_OCSP_STAPLING" = "true" ]; then + sed -i "s|#\?ssl_stapling|ssl_stapling|g" /app/templates/default.conf sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /app/templates/default.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /app/templates/default.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /app/templates/default.conf -fi - -sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/include/default.conf -sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/include/default.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/include/default.conf - sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/include/default.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/include/default.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/include/default.conf -fi - -sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf -sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/no-server-name.conf fi sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/npm.conf sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/npm.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/npm.conf +if [ -n "$DEFAULT_STAPLING_FILE" ] && [ "$ACME_OCSP_STAPLING" = "true" ]; then + sed -i "s|#\?ssl_stapling|ssl_stapling|g" /usr/local/nginx/conf/conf.d/npm.conf sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/npm.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/npm.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/npm.conf -fi - -sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf -sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/npm-no-server-name.conf fi sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf +if [ -n "$DEFAULT_STAPLING_FILE" ] && [ "$ACME_OCSP_STAPLING" = "true" ]; then + sed -i "s|#\?ssl_stapling|ssl_stapling|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf fi -sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf -fi +sed -i "s|48683|$NIBEP|g" /usr/local/nginx/conf/conf.d/npm.conf +sed -i "s|48693|$GOAIWSP|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf -sed -i "s|ssl_certificate .*|ssl_certificate $DEFAULT_CERT;|g" /data/nginx/default.conf -sed -i "s|ssl_certificate_key .*|ssl_certificate_key $DEFAULT_KEY;|g" /data/nginx/default.conf -if [ -n "$DEFAULT_STAPLING_FILE" ]; then - sed -i "s|tls-ciphers-no-stapling.conf;|tls-ciphers.conf;|g" /data/nginx/default.conf - sed -i "s|#\?ssl_stapling_file .*|ssl_stapling_file $DEFAULT_STAPLING_FILE;|g" /data/nginx/default.conf -else - sed -i "s|tls-ciphers.conf;|tls-ciphers-no-stapling.conf;|g" /data/nginx/default.conf - sed -i "s|#\?ssl_stapling_file .*|#ssl_stapling_file ;|g" /data/nginx/default.conf -fi +sed -i "s|#\?listen 0.0.0.0:81|listen $NPM_IPV4_BINDING:$NPM_PORT|g" /usr/local/nginx/conf/conf.d/npm.conf +sed -i "s|#\?listen 0.0.0.0:91|listen $GOA_IPV4_BINDING:$GOA_PORT|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf -if [ ! -s /data/nginx/default.conf ]; then - cp -van /usr/local/nginx/conf/conf.d/include/default.conf /data/nginx/default.conf +if [ "$DISABLE_IPV6" = "true" ]; then + sed -i "s|ipv6=on;|ipv6=off;|g" /usr/local/nginx/conf/nginx.conf + sed -i "s|#\?listen \[::\]:81|#listen $NPM_IPV6_BINDING:$NPM_PORT|g" /usr/local/nginx/conf/conf.d/npm.conf + sed -i "s|#\?listen \[::\]:91|#listen $GOA_IPV6_BINDING:$GOA_PORT|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf +else + sed -i "s|#\?listen \[::\]:81|listen $NPM_IPV6_BINDING:$NPM_PORT|g" /usr/local/nginx/conf/conf.d/npm.conf + sed -i "s|#\?listen \[::\]:91|listen $GOA_IPV6_BINDING:$GOA_PORT|g" /usr/local/nginx/conf/conf.d/include/goaccess.conf fi -sed -i "s|quic default_server|quic reuseport default_server|g" /data/nginx/default.conf if [ "$GOA" = "true" ]; then mkdir -vp /data/etc/goaccess/data /data/etc/goaccess/geoip - cp -va /usr/local/nginx/conf/conf.d/include/goaccess.conf /usr/local/nginx/conf/conf.d/goaccess.conf - cp -va /usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf /usr/local/nginx/conf/conf.d/goaccess-no-server-name.conf + cp -van /usr/local/nginx/conf/conf.d/include/goaccess.conf /usr/local/nginx/conf/conf.d/goaccess.conf elif [ "$FULLCLEAN" = "true" ]; then rm -vrf /data/etc/goaccess fi -if [ "$DISABLE_NGINX_BEAUTIFIER" = "false" ]; then - nginxbeautifier -s 4 -r /data/nginx +if [ "$NGINX_QUIC_BPF" = "true" ]; then + sed -i "s|quic_bpf.*|quic_bpf on;|g" /usr/local/nginx/conf/nginx.conf +fi +if [ "$NGINX_LOG_NOT_FOUND" = "true" ]; then + sed -i "s|log_not_found.*|log_not_found on;|g" /usr/local/nginx/conf/nginx.conf +fi +if [ "$NGINX_404_REDIRECT" = "true" ]; then + sed -i "s|#error_page 404|error_page 404|g" /usr/local/nginx/conf/nginx.conf +fi +if [ "$NGINX_DISABLE_PROXY_BUFFERING" = "true" ]; then + sed -i "s|proxy_buffering.*|proxy_buffering off;|g" /usr/local/nginx/conf/nginx.conf + sed -i "s|proxy_request_buffering.*|proxy_request_buffering off;|g" /usr/local/nginx/conf/nginx.conf +fi +if [ "$NGINX_HSTS_SUBDMAINS" = "false" ]; then + sed -i "s|includeSubDomains; ||g" /usr/local/nginx/conf/nginx.conf +fi +if [ "$X_FRAME_OPTIONS" = "sameorigin" ]; then + sed -i "s|DENY|SAMEORIGIN|g" /usr/local/nginx/conf/conf.d/include/hsts.conf +fi +if [ "$X_FRAME_OPTIONS" = "none" ]; then + sed -i "s|#\?\(.*DENY\)|#\1|g" /usr/local/nginx/conf/conf.d/include/hsts.conf +fi +if [ "$LOGROTATE" = "true" ]; then + sed -i "s|access_log off; # http|access_log /data/nginx/access.log log;|g" /usr/local/nginx/conf/nginx.conf + sed -i "s|access_log off; # stream|access_log /data/nginx/stream.log proxy;|g" /usr/local/nginx/conf/nginx.conf fi -rm -vf /usr/local/nginx/logs/nginx.pid -rm -vf /run/*.sock +if [ "$REGENERATE_ALL" = "true" ]; then + find /data/nginx -name "*.conf" -delete +fi find /data/tls \ /data/etc/npm \ @@ -1027,6 +889,9 @@ find /data/tls \ -not -perm 770 \ -exec chmod 770 {} \; +rm -vf /usr/local/nginx/logs/nginx.pid +rm -vf /run/*.sock + if [ "$PUID" != "0" ]; then if id -u npm > /dev/null 2>&1; then usermod -u "$PUID" npm @@ -1056,12 +921,16 @@ if [ "$PUID" != "0" ]; then -not \( -uid "$PUID" -and -gid "$PGID" \) \ -exec chown "$PUID:$PGID" {} \; if [ "$PHP82" = "true" ]; then - sed -i "s|user =.*|;user = root|" /data/php/82/php-fpm.d/www.conf - sed -i "s|group =.*|;group = root|" /data/php/82/php-fpm.d/www.conf + sed -i "s|;\?user =.*|;user = root|" /data/php/82/php-fpm.d/www.conf + sed -i "s|;\?group =.*|;group = root|" /data/php/82/php-fpm.d/www.conf fi if [ "$PHP83" = "true" ]; then - sed -i "s|user =.*|;user = root|" /data/php/83/php-fpm.d/www.conf - sed -i "s|group =.*|;group = root|" /data/php/83/php-fpm.d/www.conf + sed -i "s|;\?user =.*|;user = root|" /data/php/83/php-fpm.d/www.conf + sed -i "s|;\?group =.*|;group = root|" /data/php/83/php-fpm.d/www.conf + fi + if [ "$PHP84" = "true" ]; then + sed -i "s|;\?user =.*|;user = root|" /data/php/84/php-fpm.d/www.conf + sed -i "s|;\?group =.*|;group = root|" /data/php/84/php-fpm.d/www.conf fi sed -i "s|#\?user root;|#user root;|g" /usr/local/nginx/conf/nginx.conf exec su-exec "$PUID:$PGID" launch.sh @@ -1081,6 +950,10 @@ else sed -i "s|;user =.*|user = root|" /data/php/83/php-fpm.d/www.conf sed -i "s|;group =.*|group = root|" /data/php/83/php-fpm.d/www.conf fi + if [ "$PHP84" = "true" ]; then + sed -i "s|;user =.*|user = root|" /data/php/84/php-fpm.d/www.conf + sed -i "s|;group =.*|group = root|" /data/php/84/php-fpm.d/www.conf + fi sed -i "s|#user root;|user root;|g" /usr/local/nginx/conf/nginx.conf exec launch.sh fi diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/default.conf b/rootfs/usr/local/nginx/conf/conf.d/include/default.conf deleted file mode 100644 index 796cb3423..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/include/default.conf +++ /dev/null @@ -1,31 +0,0 @@ -# ------------------------------------------------------------ -# Default Site -# ------------------------------------------------------------ -server { - listen 80 default_server; - listen [::]:80 default_server; - - listen 443 ssl default_server; - listen [::]:443 ssl default_server; - - listen 443 quic reuseport default_server; - listen [::]:443 quic reuseport default_server; - more_set_headers 'Alt-Svc: h3=":443"; ma=86400'; - - server_name _; - - include conf.d/include/brotli.conf; - include conf.d/include/force-tls.conf; - include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - - ssl_certificate ; - ssl_certificate_key ; - #ssl_stapling_file ; - - location / { - include conf.d/include/always.conf; - root /html/default; - try_files $uri /index.html; - } -} diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf b/rootfs/usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf deleted file mode 100644 index 663cca6ea..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/include/goaccess-no-server-name.conf +++ /dev/null @@ -1,17 +0,0 @@ -server { - http3 off; - listen 82 ssl; - listen [::]:82 ssl; - - server_name ""; - return 444; - - include conf.d/include/brotli.conf; - include conf.d/include/force-tls.conf; - include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - - ssl_certificate ; - ssl_certificate_key ; - #ssl_stapling_file ; -} diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/goaccess.conf b/rootfs/usr/local/nginx/conf/conf.d/include/goaccess.conf index f54b35f07..f6bf35c9b 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/goaccess.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/goaccess.conf @@ -1,19 +1,36 @@ server { - http3 off; - listen 91 ssl default_server; + listen 0.0.0.0:91 ssl; + listen [::]:91 ssl; + + server_name ""; + include conf.d/include/always.conf; + include conf.d/include/brotli.conf; + include conf.d/include/force-tls.conf; + include conf.d/include/tls-ciphers.conf; + + ssl_certificate ; + ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; + #ssl_stapling_file ; + + return 444; +} + +server { + listen 0.0.0.0:91 ssl default_server; listen [::]:91 ssl default_server; server_name _; + include conf.d/include/always.conf; include conf.d/include/brotli.conf; include conf.d/include/force-tls.conf; include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - - modsecurity on; - modsecurity_rules_file /usr/local/nginx/conf/conf.d/include/modsecurity.conf; ssl_certificate ; ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; #ssl_stapling_file ; location / { @@ -23,7 +40,7 @@ server { include conf.d/include/proxy-location.conf; if ($goaccess = "socket") { - proxy_pass http://127.0.0.1:48683$request_uri; + proxy_pass http://127.0.0.1:48693$request_uri; } root /tmp/goa; diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/hsts.conf b/rootfs/usr/local/nginx/conf/conf.d/include/hsts.conf index ad81d1d29..14915de78 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/hsts.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/hsts.conf @@ -1,7 +1,6 @@ more_set_headers "X-XSS-Protection: 0"; -more_set_headers "X-Frame-Options: SAMEORIGIN"; +more_set_headers "X-Frame-Options: DENY"; # or what ever you set using env more_set_headers "X-Content-Type-Options: nosniff"; -more_set_headers "Referrer-Policy: strict-origin-when-cross-origin"; -more_set_headers "Content-Security-Policy: $content_security_policy"; +more_set_headers "Content-Security-Policy: $content_security_policy"; # if not set by upstream: upgrade-insecure-requests, else upstreams value is used -more_set_headers "Strict-Transport-Security: $hsts_header"; +more_set_headers "Strict-Transport-Security: $hsts_header"; # means: max-age=63072000; includeSubDomains; preload (includeSubDomains not when disabled via env) diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf b/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf deleted file mode 100644 index 6cc16ebe0..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/include/proxy-location.conf +++ /dev/null @@ -1,13 +0,0 @@ -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Port $server_port; -proxy_set_header X-Forwarded-Scheme $scheme; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header X-Real-IP $remote_addr; -#proxy_set_header Accept-Encoding ""; -proxy_set_header Host $host; - -proxy_set_header Early-Data $ssl_early_data; -proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; -proxy_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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA; - -proxy_http_version 1.1; diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf b/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf index 42b694d7b..970c3777d 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/proxy.conf @@ -6,9 +6,5 @@ proxy_set_header X-Real-IP $remote_addr; #proxy_set_header Accept-Encoding ""; proxy_set_header Host $host; -proxy_set_header Early-Data $ssl_early_data; -proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; -proxy_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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA; - proxy_http_version 1.1; -proxy_pass $forward_scheme://$server:$port$request_uri; +proxy_set_header Early-Data $ssl_early_data; diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers-no-stapling.conf b/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers-no-stapling.conf deleted file mode 100644 index 9716e3bf6..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers-no-stapling.conf +++ /dev/null @@ -1,16 +0,0 @@ -ssl_early_data on; - -ssl_stapling off; -ssl_stapling_verify off; - -ssl_session_timeout 1d; -ssl_session_cache shared:SSL:10m; - -ssl_dhparam /etc/dhparam; -ssl_protocols TLSv1.2 TLSv1.3; - -ssl_ecdh_curve X25519MLKEM768:x25519_kyber768:x25519:x448:secp521r1:secp384r1:secp256r1; - -ssl_prefer_server_ciphers on; -ssl_conf_command Options PrioritizeChaCha; -ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256; diff --git a/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers.conf b/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers.conf index 42590857e..400efdbd7 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/include/tls-ciphers.conf @@ -1,16 +1,11 @@ -ssl_early_data on; - -ssl_stapling on; -ssl_stapling_verify on; - ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_dhparam /etc/dhparam; ssl_protocols TLSv1.2 TLSv1.3; +ssl_ecdh_curve X25519MLKEM768:x25519:x448:secp521r1:secp384r1:secp256r1; -ssl_ecdh_curve X25519MLKEM768:x25519_kyber768:x25519:x448:secp521r1:secp384r1:secp256r1; - +ssl_early_data on; ssl_prefer_server_ciphers on; ssl_conf_command Options PrioritizeChaCha; ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256; diff --git a/rootfs/usr/local/nginx/conf/conf.d/no-server-name.conf b/rootfs/usr/local/nginx/conf/conf.d/no-server-name.conf deleted file mode 100644 index 63090e648..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/no-server-name.conf +++ /dev/null @@ -1,24 +0,0 @@ -server { - listen 80; - listen [::]:80; - - listen 443 ssl; - listen [::]:443 ssl; - - listen 443 quic; - listen [::]:443 quic; - - server_name ""; - return 444; - - include conf.d/include/brotli.conf; - include conf.d/include/force-tls.conf; - include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - add_header Alt-Svc 'h3=":443"; ma=86400'; - http3 on; - - ssl_certificate ; - ssl_certificate_key ; - #ssl_stapling_file ; -} diff --git a/rootfs/usr/local/nginx/conf/conf.d/npm-no-server-name.conf b/rootfs/usr/local/nginx/conf/conf.d/npm-no-server-name.conf deleted file mode 100644 index 90e833948..000000000 --- a/rootfs/usr/local/nginx/conf/conf.d/npm-no-server-name.conf +++ /dev/null @@ -1,17 +0,0 @@ -server { - http3 off; - listen 81 ssl; - listen [::]:81 ssl; - - server_name ""; - return 444; - - include conf.d/include/brotli.conf; - include conf.d/include/force-tls.conf; - include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - - ssl_certificate ; - ssl_certificate_key ; - #ssl_stapling_file ; -} diff --git a/rootfs/usr/local/nginx/conf/conf.d/npm.conf b/rootfs/usr/local/nginx/conf/conf.d/npm.conf index 334b10359..50f268666 100644 --- a/rootfs/usr/local/nginx/conf/conf.d/npm.conf +++ b/rootfs/usr/local/nginx/conf/conf.d/npm.conf @@ -1,29 +1,46 @@ server { - http3 off; - listen 81 ssl default_server; + listen 0.0.0.0:81 ssl; + listen [::]:81 ssl; + + server_name ""; + include conf.d/include/always.conf; + include conf.d/include/brotli.conf; + include conf.d/include/force-tls.conf; + include conf.d/include/tls-ciphers.conf; + + ssl_certificate ; + ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; + #ssl_stapling_file ; + + return 444; +} + +server { + listen 0.0.0.0:81 ssl default_server; listen [::]:81 ssl default_server; server_name _; + include conf.d/include/always.conf; include conf.d/include/brotli.conf; include conf.d/include/force-tls.conf; include conf.d/include/tls-ciphers.conf; - include conf.d/include/always.conf; - - modsecurity on; - modsecurity_rules_file /usr/local/nginx/conf/conf.d/include/modsecurity.conf; ssl_certificate ; ssl_certificate_key ; + #ssl_stapling on; + #ssl_stapling_verify on; #ssl_stapling_file ; location /api { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; - include conf.d/include/proxy-location.conf; + include conf.d/include/proxy.conf; rewrite ^/api(/.*)$ $1 break; - proxy_pass http://127.0.0.1:48693; + proxy_pass http://127.0.0.1:48683; } location / { diff --git a/rootfs/usr/local/nginx/conf/nginx.conf b/rootfs/usr/local/nginx/conf/nginx.conf index bcb72b1b2..e7bd40d0d 100644 --- a/rootfs/usr/local/nginx/conf/nginx.conf +++ b/rootfs/usr/local/nginx/conf/nginx.conf @@ -5,12 +5,15 @@ error_log stderr warn; worker_processes auto; worker_cpu_affinity auto; +quic_bpf off; + # Custom -include /data/nginx_custom/root_top.conf; +include /data/custom_nginx/root.conf; +include /data/custom_nginx/root_top.conf; events { # Custom - include /data/nginx_custom/events.conf; + include /data/custom_nginx/events.conf; } http { @@ -36,6 +39,7 @@ http { tcp_nodelay on; client_max_body_size 0; client_body_buffer_size 512k; + http3_stream_buffer_size 512k; reset_timedout_connection on; gzip on; @@ -99,6 +103,10 @@ http { server unix:/run/php83.sock; } + upstream php84 { + server unix:/run/php84.sock; + } + # Fancy Index fancyindex off; fancyindex_localtime on; @@ -128,11 +136,10 @@ http { include /tmp/ip_ranges.conf; - include /data/nginx/default.conf; include conf.d/*.conf; # Custom - include /data/nginx_custom/http_top.conf; + include /data/custom_nginx/http_top.conf; # Files generated by NPM include /data/nginx/proxy_host/*.conf; @@ -140,7 +147,7 @@ http { include /data/nginx/dead_host/*.conf; # Custom - include /data/nginx_custom/http.conf; + include /data/custom_nginx/http.conf; } stream { @@ -149,11 +156,11 @@ stream { resolver local=on valid=10s ipv6=on; # Custom - include /data/nginx_custom/stream_top.conf; + include /data/custom_nginx/stream_top.conf; # Files generated by NPM include /data/nginx/stream/*.conf; # Custom - include /data/nginx_custom/stream.conf; + include /data/custom_nginx/stream.conf; }