diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index ab20d44c..1afc8ac2 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -1,14 +1,18 @@ -name: reviewdog -on: [pull_request] +name: spellcheck +on: + push: + pull_request: + workflow_dispatch: jobs: - misspell: - name: runner / misspell + spellcheck: + name: spellcheck runs-on: ubuntu-latest steps: - name: Check out code. uses: actions/checkout@v3 - - name: misspell - uses: reviewdog/action-misspell@v1 + - name: Check spelling + uses: codespell-project/actions-codespell@v2 with: - github_token: ${{ secrets.github_token }} - locale: "US" + check_filenames: true + check_hidden: true + skip: .gitignore,block-exploits.conf,showdown.min.js,jquery.min.js,xregexp-all.js diff --git a/.gitignore b/.gitignore index 1d856c25..5fa0e3bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +backend/certbot-dns-plugins.js +frontend/certbot-dns-plugins.js + # User-specific stuff .idea desktop.files.json @@ -780,4 +783,4 @@ node_modules/ # ignore log files and databases *.log *.sql -*.sqlite \ No newline at end of file +*.sqlite diff --git a/Dockerfile b/Dockerfile index 734fcb72..6938a526 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,10 +50,10 @@ RUN apk add --no-cache ca-certificates git build-base && \ sed -i "s|ENABLED=.*|ENABLED=false|g" lua-mod/config_example.conf && \ sed -i "s|API_URL=.*|API_URL=http://127.0.0.1:8080|g" lua-mod/config_example.conf && \ sed -i "s|BAN_TEMPLATE_PATH=.*|BAN_TEMPLATE_PATH=/data/etc/crowdsec/ban.html|g" lua-mod/config_example.conf && \ - sed -i "s|CAPTCHA_TEMPLATE_PATH=.*|CAPTCHA_TEMPLATE_PATH=/data/etc/crowdsec/crowdsec.conf|g" lua-mod/config_example.conf + sed -i "s|CAPTCHA_TEMPLATE_PATH=.*|CAPTCHA_TEMPLATE_PATH=/data/etc/crowdsec/captcha.html|g" lua-mod/config_example.conf -FROM zoeyvid/nginx-quic:157 +FROM zoeyvid/nginx-quic:176 COPY rootfs / RUN apk add --no-cache ca-certificates tzdata \ lua5.1-lzlib \ diff --git a/README.md b/README.md index 19594e30..1de5afc5 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ running at home or otherwise, including free TLS, without having to know too muc - [Screenshots](https://nginxproxymanager.com/screenshots) +# Note: To fix [this issue](https://github.com/SpiderLabs/ModSecurity/issues/2848), instead of running `nginx -s reload`, this fork kills nginx and starts it again. This will result in a 502 error when you update your hosts. See https://github.com/ZoeyVid/nginx-proxy-manager/issues/296 and https://github.com/ZoeyVid/nginx-proxy-manager/issues/283. + + ## Project Goal I created this project to fill a personal need to provide users with a easy way to accomplish reverse @@ -127,7 +130,7 @@ b) Custom Nginx Configuration (advanced tab), which looks the following for file - Note: the slash at the end of the file path is important - Note: first enable `PHP81` and/or `PHP82` inside your compose file - Note: you can replace `fastcgi_pass php82;` with `fastcgi_pass` `php81`/`php82` `;` -- Note: to add more php extension use the packes from [here](https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php8*-*) and add them using the `PHP_APKS` env (see compose file) +- Note: to add more php extension use the packages from [here](https://pkgs.alpinelinux.org/packages?branch=v3.17&repo=community&arch=x86_64&name=php8*-*) and add them using the `PHP_APKS` env (see compose file) ``` location / { alias /var/www//; diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index 4a562748..4eb92496 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -1,7 +1,6 @@ const _ = require('lodash'); const fs = require('fs'); const https = require('https'); -const tempWrite = require('temp-write'); const moment = require('moment'); const logger = require('../logger').ssl; const error = require('../lib/error'); @@ -11,6 +10,7 @@ const dnsPlugins = require('../certbot-dns-plugins'); const internalAuditLog = require('./audit-log'); const internalNginx = require('./nginx'); const archiver = require('archiver'); +const crypto = require('crypto'); const path = require('path'); const { isArray } = require('lodash'); @@ -29,7 +29,7 @@ const internalCertificate = { intervalProcessing: false, initTimer: () => { - logger.info('Certbot Encrypt Renewal Timer initialized'); + logger.info('Certbot Renewal Timer initialized'); internalCertificate.interval = setInterval(internalCertificate.processExpiringHosts, internalCertificate.intervalTimeout); // And do this now as well internalCertificate.processExpiringHosts(); @@ -637,8 +637,10 @@ const internalCertificate = { * @param {String} private_key This is the entire key contents as a string */ checkPrivateKey: (private_key) => { - return tempWrite(private_key, '/tmp') - .then((filepath) => { + const randomName = crypto.randomBytes(8).toString('hex'); + const filepath = path.join('/tmp', 'certificate_' + randomName); + return fs.writeFileSync(filepath, private_key) + .then(() => { return new Promise((resolve, reject) => { const failTimeout = setTimeout(() => { reject(new error.ValidationError('Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.')); @@ -670,8 +672,10 @@ const internalCertificate = { * @param {Boolean} [throw_expired] Throw when the certificate is out of date */ getCertificateInfo: (certificate, throw_expired) => { - return tempWrite(certificate, '/tmp') - .then((filepath) => { + const randomName = crypto.randomBytes(8).toString('hex'); + const filepath = path.join('/root', 'certificate_' + randomName); + return fs.writeFileSync(filepath, certificate) + .then(() => { return internalCertificate.getCertificateInfoFromFile(filepath, throw_expired) .then((certData) => { fs.unlinkSync(filepath); diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 510403fe..2a08adce 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -5,6 +5,8 @@ const config = require('../lib/config'); const utils = require('../lib/utils'); const error = require('../lib/error'); +const NgxPidFilePath = '/usr/local/nginx/logs/nginx.pid'; + const internalNginx = { /** @@ -111,11 +113,21 @@ const internalNginx = { /** * @returns {Promise} */ + reload: () => { return internalNginx.test() .then(() => { - logger.info('Restarting Nginx'); - return utils.exec('kill $(cat /usr/local/nginx/logs/nginx.pid); nginx'); + if (fs.existsSync(NgxPidFilePath)) { + const ngxPID = fs.readFileSync(NgxPidFilePath, 'utf8').trim(); + if (ngxPID.length > 0) { + logger.info('Killing Nginx'); + utils.exec(`kill ${ngxPID}`); + } + } + logger.info('Starting Nginx in three seconds'); + setTimeout(() => { + utils.execfg('nginx'); + }, 3000); }); }, @@ -159,10 +171,10 @@ const internalNginx = { {certificate: host.certificate}, host.locations[i]); if (locationCopy.forward_host.indexOf('/') > -1) { - const splitted = locationCopy.forward_host.split('/'); + const split = locationCopy.forward_host.split('/'); - locationCopy.forward_host = splitted.shift(); - locationCopy.forward_path = `/${splitted.join('/')}`; + locationCopy.forward_host = split.shift(); + locationCopy.forward_path = `/${split.join('/')}`; } // eslint-disable-next-line diff --git a/backend/lib/config.js b/backend/lib/config.js index e8b4a16b..ad4eb614 100644 --- a/backend/lib/config.js +++ b/backend/lib/config.js @@ -96,7 +96,7 @@ const generateKeys = () => { try { fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2)); } catch (err) { - logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message); + logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' + err.message); process.exit(1); } logger.info('Wrote JWT key pair to config file: ' + keysFile); @@ -150,7 +150,7 @@ module.exports = { }, /** - * Are we running in debug mdoe? + * Are we running in debug mode? * * @returns {boolean} */ diff --git a/backend/lib/utils.js b/backend/lib/utils.js index 2a184ee1..ec7d97fd 100644 --- a/backend/lib/utils.js +++ b/backend/lib/utils.js @@ -1,5 +1,6 @@ const _ = require('lodash'); const exec = require('child_process').exec; +const spawn = require('child_process').spawn; const execFile = require('child_process').execFile; const { Liquid } = require('liquidjs'); const logger = require('../logger').global; @@ -22,6 +23,33 @@ module.exports = { }); }, + /** + * @param {String} cmd + * @returns {Promise} + */ + execfg: function (cmd) { + return new Promise((resolve, reject) => { + const childProcess = spawn(cmd, { + shell: true, + detached: true, + stdio: 'inherit' // Use the same stdio as the current process + }); + + childProcess.on('error', (err) => { + reject(err); + }); + + childProcess.on('close', (code) => { + if (code !== 0) { + reject(new Error(`Command '${cmd}' exited with code ${code}`)); + } else { + resolve(); + } + }); + }); + }, + + /** * @param {String} cmd * @param {Array} args diff --git a/backend/package.json b/backend/package.json index f30d137a..72ee3b45 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,23 +14,25 @@ "express": "4.18.2", "express-fileupload": "1.4.0", "gravatar": "1.8.2", - "jsonwebtoken": "9.0.0", + "jsonwebtoken": "9.0.1", "knex": "2.4.2", - "liquidjs": "10.8.2", + "liquidjs": "10.8.4", "lodash": "4.17.21", "moment": "2.29.4", "mysql": "2.18.1", "node-rsa": "1.1.1", - "objection": "3.0.1", + "objection": "3.0.4", "path": "0.12.7", "signale": "1.4.0", - "sqlite3": "5.1.6", - "temp-write": "4.0.0" + "sqlite3": "5.1.6" + }, + "resolutions": { + "semver": "7.5.4" }, "author": "Jamie Curnow ", "license": "MIT", "devDependencies": { - "eslint": "8.42.0", + "eslint": "8.44.0", "eslint-plugin-align-assignments": "1.1.2" } } diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json index 159c8036..c52fec34 100644 --- a/backend/schema/endpoints/streams.json +++ b/backend/schema/endpoints/streams.json @@ -88,7 +88,7 @@ "links": [ { "title": "List", - "description": "Returns a list of Steams", + "description": "Returns a list of Streams", "href": "/nginx/streams", "access": "private", "method": "GET", diff --git a/frontend/js/app/nginx/proxy/form.js b/frontend/js/app/nginx/proxy/form.js index bb0a7b5d..a6910153 100644 --- a/frontend/js/app/nginx/proxy/form.js +++ b/frontend/js/app/nginx/proxy/form.js @@ -346,7 +346,7 @@ module.exports = Mn.View.extend({ collection: this.locationsCollection })); - // Check wether there are any location defined + // Check whether there are any location defined if (options.model && Array.isArray(options.model.attributes.locations)) { options.model.attributes.locations.forEach((location) => { let m = new ProxyLocationModel.Model(location); diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 117ed905..c8364ea8 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -228,7 +228,7 @@ "authorization": "Authorization", "access": "Access", "satisfy": "Satisfy", - "satisfy-any": "Allow access if at least one authorization method succseeded", + "satisfy-any": "Allow access if at least one authorization method succeeded", "pass-auth": "Don't pass credentials to backend of host", "access-add": "Add", "auth-add": "Add", diff --git a/frontend/package.json b/frontend/package.json index ddd64ece..7ef545f3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,7 +4,7 @@ "description": "A beautiful interface for creating Nginx endpoints", "main": "js/index.js", "dependencies": { - "@babel/core": "7.22.5", + "@babel/core": "7.22.8", "babel-core": "6.26.3", "babel-loader": "8.3.0", "babel-preset-env": "1.7.0", diff --git a/rootfs/bin/launch.sh b/rootfs/bin/launch.sh index 85323b8f..2dcc2141 100755 --- a/rootfs/bin/launch.sh +++ b/rootfs/bin/launch.sh @@ -35,7 +35,6 @@ if [ "$PHP82" = "true" ]; then fi fi -nginx & if [ "$PHP81" = "true" ]; then PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FOR; fi & 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 & index.js & diff --git a/rootfs/bin/start.sh b/rootfs/bin/start.sh index dd253806..16e0f61b 100755 --- a/rootfs/bin/start.sh +++ b/rootfs/bin/start.sh @@ -565,6 +565,8 @@ find /data/nginx -type f -name '*.conf' -exec sed -i "/^[[:space:]]*ma=86400';[[ nginxbeautifier -s 4 -r /data/nginx +rm -f /usr/local/nginx/logs/nginx.pid + chmod -R 770 /data/tls \ /data/etc/npm \ /data/etc/access diff --git a/rootfs/usr/local/nginx/conf/nginx.conf b/rootfs/usr/local/nginx/conf/nginx.conf index 9e6fa2b6..99eceea1 100644 --- a/rootfs/usr/local/nginx/conf/nginx.conf +++ b/rootfs/usr/local/nginx/conf/nginx.conf @@ -42,6 +42,7 @@ http { http2 on; http3 on; quic_retry on; + ssl_dyn_rec_enable on; #resolver ; fastcgi_index index.php;