diff --git a/.gitignore b/.gitignore index 568d4b98..1d856c25 100644 --- a/.gitignore +++ b/.gitignore @@ -436,7 +436,6 @@ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ -[Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ diff --git a/Dockerfile b/Dockerfile index b8207453..626262de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,21 +29,22 @@ RUN apk add --no-cache ca-certificates nodejs-current yarn && \ node-prune && \ yarn cache clean --all +FROM python:3.11.3-alpine3.17 as certbot +RUN apk add --no-cache build-base libffi-dev && \ + python3 -m venv /usr/local/certbot && \ + . /usr/local/certbot/bin/activate && \ + pip install --no-cache-dir certbot -FROM zoeyvid/nginx-quic:110 +FROM zoeyvid/nginx-quic:111 RUN apk add --no-cache ca-certificates tzdata \ nodejs-current \ openssl apache2-utils \ - coreutils grep jq curl \ - build-base libffi-dev && \ -# Install Certbot - pip install --no-cache-dir certbot && \ -# Clean - apk del --no-cache build-base libffi-dev + coreutils grep jq curl shadow sudo COPY rootfs / COPY --from=backend /build/backend /app COPY --from=frontend /build/frontend/dist /app/frontend +COPY --from=certbot /usr/local/certbot /usr/local/certbot RUN ln -s /app/password-reset.js /usr/local/bin/password-reset.js && \ ln -s /app/sqlite-vaccum.js /usr/local/bin/sqlite-vaccum.js && \ @@ -51,6 +52,7 @@ RUN ln -s /app/password-reset.js /usr/local/bin/password-reset.js && \ ENV NODE_ENV=production \ NODE_CONFIG_DIR=/data/etc/npm \ + PATH="/usr/local/certbot/bin:$PATH" \ DB_SQLITE_FILE=/data/etc/npm/database.sqlite WORKDIR /app diff --git a/README.md b/README.md index db9797cd..3bb5bbef 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,12 @@ so that the barrier for entry here is low. - Auto certbot old certs clean (FULLCLEAN=true) - Passwort reset (only sqlite) (`docker exec -it nginx-proxy-manager password-reset.js USER_EMAIL PASSWORD`) - TLS supported for MariaDB/MySQL, please set the `DB_MYSQL_TLS` env to true. If you use self signed certificates you can upload them for example to `/data/etc/npm/ca.crt` and set the `DB_MYSQL_CA` to `/data/etc/npm/ca.crt` (not tested) +- PUID/GGID support in network mode host (please add `net.ipv4.ip_unprivileged_port_start=0` at the end of `/etc/sysctl.conf`) ## Soon - disabling IPv4/IPv6 ([1](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/40-dynamic.sh) / [2](https://github.com/NginxProxyManager/nginx-proxy-manager/blob/develop/docker/rootfs/etc/s6-overlay/s6-rc.d/prepare/50-ipv6.sh) / nginx templates (nginx.js lines 200-300)) - custom IP-Bindings in nginx/backend to allow multiple instances in host network mode -- support changing the PUID/PGID (maybe) +- dark mode - more ## migration @@ -79,7 +80,6 @@ so that the barrier for entry here is low. - if you use custom certificates, you need to upload the CA/Intermediate Certificate (file name: `chain.pem`) in the `/opt/npm/tls/custom/npm-[certificate-id]` folder - some buttons have changed, check if they are still correct - please delete all dnspod certs and recreate them OR you manually change the credentialsfile (see [here](https://github.com/ZoeyVid/nginx-proxy-manager/blob/develop/global/certbot-dns-plugins.js) for the template) -- changing the PUID/PGID is not supported (since it would break running in network_mode host) # Use as webserver @@ -136,10 +136,12 @@ services: network_mode: host volumes: - "/opt/npm:/data" -# - "/opt/npm-letsencrypt:/etc/letsencrypt" # Only needed for first time migration from original nginx-proxy-manager to this fork # - "/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=Europe/Berlin" + - "TZ=Europe/Berlin" # set timezone +# - "PUID=1000" # set group id +# - "PGID=1000" # set user id # - "NGINX_LOG_NOT_FOUND=true" # Allow logging of 404 errors # - "NPM_LISTEN_LOCALHOST=true" # Bind the NPM Dashboard on Port 81 only to localhost # - "NPM_CERT_ID=1" # ID of cert, which should be used instead of dummycerts diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js index a3e93500..745eac07 100644 --- a/backend/internal/certificate.js +++ b/backend/internal/certificate.js @@ -16,7 +16,7 @@ const path = require('path'); const { isArray } = require('lodash'); const certbotConfig = '/data/tls/certbot/config.ini'; -const certbotCommand = 'certbot --config-dir /data/tls/certbot'; +const certbotCommand = 'certbot --logs-dir /tmp/certbot-log --work-dir /tmp/certbot-work --config-dir /data/tls/certbot'; function omissions() { return ['is_deleted']; @@ -875,7 +875,7 @@ const internalCertificate = { // Escape single quotes and backslashes const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\'); const credentialsCmd = 'mkdir -p /data/tls/certbot/credentials 2> /dev/null; echo \'' + escapedCredentials + '\' > \'' + credentialsLocation + '\' && chmod 600 \'' + credentialsLocation + '\''; - const prepareCmd = 'pip install --no-cache-dir ' + dns_plugin.package_name + (dns_plugin.version_requirement || '') + ' ' + dns_plugin.dependencies; + const prepareCmd = 'pip install --no-cache-dir ' + dns_plugin.package_name; // Whether the plugin has a ---credentials argument const hasConfigArg = certificate.meta.dns_provider !== 'route53'; diff --git a/backend/internal/ip_ranges.js b/backend/internal/ip_ranges.js index f74eb434..752e2566 100644 --- a/backend/internal/ip_ranges.js +++ b/backend/internal/ip_ranges.js @@ -122,7 +122,7 @@ const internalIpRanges = { const renderEngine = utils.getRenderEngine(); return new Promise((resolve, reject) => { let template = null; - let filename = '/usr/local/nginx/conf/conf.d/include/ip_ranges.conf'; + let filename = '/data/nginx/ip_ranges.conf'; try { template = fs.readFileSync(__dirname + '/../templates/ip_ranges.conf', {encoding: 'utf8'}); } catch (err) { diff --git a/backend/setup.js b/backend/setup.js index 68dc0a59..7b5f62dc 100644 --- a/backend/setup.js +++ b/backend/setup.js @@ -117,7 +117,7 @@ const setupCertbotPlugins = () => { certificates.map(function (certificate) { if (certificate.meta && certificate.meta.dns_challenge === true) { const dns_plugin = dns_plugins[certificate.meta.dns_provider]; - const packages_to_install = `${dns_plugin.package_name}${dns_plugin.version_requirement || ''} ${dns_plugin.dependencies}`; + const packages_to_install = `${dns_plugin.package_name}`; if (plugins.indexOf(packages_to_install) === -1) plugins.push(packages_to_install); diff --git a/compose.yaml b/compose.yaml index 6544b7cd..fe05007b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -7,10 +7,12 @@ services: network_mode: host volumes: - "/opt/npm:/data" -# - "/opt/npm-letsencrypt:/etc/letsencrypt" # Only needed for first time migration from original nginx-proxy-manager to this fork # - "/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=Europe/Berlin" + - "TZ=Europe/Berlin" # set timezone +# - "PUID=1000" # set group id +# - "PGID=1000" # set user id # - "NGINX_LOG_NOT_FOUND=true" # Allow logging of 404 errors # - "NPM_LISTEN_LOCALHOST=true" # Bind the NPM Dashboard on Port 81 only to localhost # - "NPM_CERT_ID=1" # ID of cert, which should be used instead of dummycerts diff --git a/rootfs/bin/launch.sh b/rootfs/bin/launch.sh new file mode 100755 index 00000000..2b838f18 --- /dev/null +++ b/rootfs/bin/launch.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +echo " +------------------------------------- + _ _ ____ __ __ +| \ | | _ \| \/ | +| \| | |_) | |\/| | +| |\ | __/| | | | +|_| \_|_| |_| |_| +------------------------------------- +User: $(whoami) +User ID: $(id -u) +Group ID: $(id -g) +------------------------------------- +" + +if ! nginx -t > /dev/null 2>&1; then + nginx -T || sleep inf + sleep inf +fi + +if [ "$PHP81" = "true" ]; then + if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then + PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf + sleep inf + fi +fi + +if [ "$PHP82" = "true" ]; then + if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then + PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf + sleep inf + fi +fi + +while (nginx -t > /dev/null 2>&1 && 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 -FORt > /dev/null 2>&1; 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 -FORt > /dev/null 2>&1; fi); do + 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 & + wait +done + +if ! nginx -t > /dev/null 2>&1; then + nginx -T || sleep inf +fi + +if [ "$PHP81" = "true" ]; then + if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then + PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf + fi +fi + +if [ "$PHP82" = "true" ]; then + if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then + PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf + fi +fi diff --git a/rootfs/bin/start.sh b/rootfs/bin/start.sh index d1251185..3d3ed462 100755 --- a/rootfs/bin/start.sh +++ b/rootfs/bin/start.sh @@ -14,6 +14,22 @@ if [ ! -d /data ]; then sleep inf || exit 1 fi +export PUID="${PUID:-0}" || exit 1 +if ! echo "$PUID" | grep -q "^[0-9]\+$"; then + echo "You've set PUID but not to an allowed value." || sleep inf + echo "It needs to be a string. Allowed are small digits 0-9" || sleep inf + echo "It is set to \"$PUID\"." || sleep inf + sleep inf || exit 1 +fi + +export PGID="${PGID:-0}" || exit 1 +if ! echo "$PGID" | grep -q "^[0-9]\+$"; then + echo "You've set PGID but not to an allowed value." || sleep inf + echo "It needs to be a string. Allowed are small digits 0-9" || sleep inf + echo "It is set to \"$PGID\"." || sleep inf + sleep inf || exit 1 +fi + if [ "$PHP81" = true ] || [ "$PHP82" = true ]; then apk add --no-cache fcgi fi @@ -100,7 +116,9 @@ else rm -vrf /data/php/82 fi -mkdir -p /tmp/acme-challenge || sleep inf +mkdir -p /tmp/acme-challenge \ + /tmp/certbot-work \ + /tmp/certbot-log || sleep inf mkdir -vp /data/tls/certbot/renewal \ /data/tls/custom \ @@ -237,6 +255,7 @@ find /data/nginx -type f -name '*.conf' -exec sed -i "/ssl_stapling_verify/d" {} touch /data/etc/html/index.html \ /data/nginx/default.conf \ + /data/nginx/ip_ranges.conf \ /data/nginx/custom/root.conf \ /data/nginx/custom/events.conf \ /data/nginx/custom/http.conf \ @@ -247,8 +266,7 @@ touch /data/etc/html/index.html \ /data/nginx/custom/stream.conf \ /data/nginx/custom/server_stream.conf \ /data/nginx/custom/server_stream_tcp.conf \ - /data/nginx/custom/server_stream_udp.conf \ - /usr/local/nginx/conf/conf.d/include/ip_ranges.conf || sleep inf + /data/nginx/custom/server_stream_udp.conf || sleep inf if [ -z "$NPM_CERT_ID" ]; then export NPM_CERT=/data/tls/dummycert.pem || sleep inf @@ -375,9 +393,6 @@ else /data/tls/dummykey.pem || sleep inf fi -chmod -R 600 /data/tls \ - /data/etc/access - if [ ! -f /data/nginx/default.conf ]; then mv -vn /usr/local/nginx/conf/conf.d/include/default.conf /data/nginx/default.conf || sleep inf fi @@ -390,59 +405,32 @@ sed -i "s|ssl_certificate .*|ssl_certificate $NPM_CERT;|g" /data/nginx/default.c sed -i "s|ssl_certificate_key .*|ssl_certificate_key $NPM_KEY;|g" /data/nginx/default.conf || sleep inf if [ -n "$NPM_CHAIN" ]; then sed -i "s|ssl_trusted_certificate .*|ssl_trusted_certificate $NPM_CHAIN;|g" /data/nginx/default.conf || sleep inf; fi -if ! nginx -t > /dev/null 2>&1; then - nginx -T || sleep inf - sleep inf || exit 1 -fi -if [ "$PHP81" = "true" ]; then - if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then - PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf - sleep inf || exit 1 - fi -fi - -if [ "$PHP82" = "true" ]; then - if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then - PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf - sleep inf || exit 1 - fi -fi - -echo " -------------------------------------- - _ _ ____ __ __ -| \ | | _ \| \/ | -| \| | |_) | |\/| | -| |\ | __/| | | | -|_| \_|_| |_| |_| -------------------------------------- -User: $(whoami) -User ID: $(id -u) -Group ID: $(id -g) -------------------------------------- -" - -while (nginx -t > /dev/null 2>&1 && 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 -FORt > /dev/null 2>&1; 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 -FORt > /dev/null 2>&1; fi); do - nginx || exit 1 & - 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 || exit 1; 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 || exit 1; fi & - index.js || exit 1 & - wait -done - -if ! nginx -t > /dev/null 2>&1; then - nginx -T || sleep inf -fi - -if [ "$PHP81" = "true" ]; then - if ! PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt > /dev/null 2>&1; then - PHP_INI_SCAN_DIR=/data/php/81/conf.d php-fpm81 -c /data/php/81 -y /data/php/81/php-fpm.conf -FORt || sleep inf - fi -fi - -if [ "$PHP82" = "true" ]; then - if ! PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt > /dev/null 2>&1; then - PHP_INI_SCAN_DIR=/data/php/82/conf.d php-fpm82 -c /data/php/82 -y /data/php/82/php-fpm.conf -FORt || sleep inf +chmod -R o-rwx /data/tls \ + /data/etc/npm \ + /data/etc/access || exit 1 + +if [ "$PUID" != "0" ]; then + if id -u npmuser > /dev/null 2>&1; then + usermod -u "$PUID" npmuser || exit 1 + else + useradd -o -u "$PUID" -U -d /tmp/npmuserhome -s /bin/false npmuser || exit 1 fi + usermod -G "$PGID" npmuser || exit 1 + groupmod -o -g "$PGID" npmuser || exit 1 + chown -R "$PUID:$PGID" /usr/local/certbot \ + /usr/local/nginx \ + /data \ + /tmp/acme-challenge \ + /tmp/certbot-work \ + /tmp/certbot-log || exit 1 + sudo -Eu npmuser launch.sh || exit 1 +else + chown -R 0:0 /usr/local/certbot \ + /usr/local/nginx \ + /data \ + /tmp/acme-challenge \ + /tmp/certbot-work \ + /tmp/certbot-log || exit 1 + launch.sh || exit 1 fi diff --git a/rootfs/usr/local/nginx/conf/nginx.conf b/rootfs/usr/local/nginx/conf/nginx.conf index f90c4d91..3237b0cc 100644 --- a/rootfs/usr/local/nginx/conf/nginx.conf +++ b/rootfs/usr/local/nginx/conf/nginx.conf @@ -1,4 +1,3 @@ -user root; daemon off; pcre_jit on; worker_processes auto; @@ -101,7 +100,7 @@ http { include fastcgi.conf; - include conf.d/include/ip_ranges.conf; + include /data/nginx/ip_ranges.conf; include /data/nginx/default.conf; include conf.d/*.conf;