Skip to content

Commit

Permalink
WIP (summary later)
Browse files Browse the repository at this point in the history
Signed-off-by: Zoey <[email protected]>
  • Loading branch information
Zoey2936 committed Jan 6, 2025
1 parent b091ad0 commit f93a33f
Show file tree
Hide file tree
Showing 81 changed files with 1,050 additions and 2,181 deletions.
38 changes: 21 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ RUN apk upgrade --no-cache -a && \
tar xzf crowdsec-nginx-bouncer.tgz && \
mv crowdsec-nginx-bouncer-* crowdsec-nginx-bouncer && \
sed -i "/lua_package_path/d" /src/crowdsec-nginx-bouncer/nginx/crowdsec_nginx.conf && \
sed -i "s|/etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf|/data/etc/crowdsec/crowdsec.conf|g" /src/crowdsec-nginx-bouncer/nginx/crowdsec_nginx.conf && \
sed -i "s|/etc/crowdsec/bouncers/crowdsec-nginx-bouncer.conf|/data/crowdsec/crowdsec.conf|g" /src/crowdsec-nginx-bouncer/nginx/crowdsec_nginx.conf && \
sed -i "s|crowdsec-nginx-bouncer|crowdsec-npmplus-bouncer|g" /src/crowdsec-nginx-bouncer/nginx/crowdsec_nginx.conf && \
sed -i "s|API_KEY=.*|API_KEY=|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|ENABLED=.*|ENABLED=false|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|API_URL=.*|API_URL=http://127.0.0.1:8080|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|BAN_TEMPLATE_PATH=.*|BAN_TEMPLATE_PATH=/data/etc/crowdsec/ban.html|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|CAPTCHA_TEMPLATE_PATH=.*|CAPTCHA_TEMPLATE_PATH=/data/etc/crowdsec/captcha.html|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|BAN_TEMPLATE_PATH=.*|BAN_TEMPLATE_PATH=/data/crowdsec/ban.html|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|CAPTCHA_TEMPLATE_PATH=.*|CAPTCHA_TEMPLATE_PATH=/data/crowdsec/captcha.html|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|APPSEC_URL=.*|APPSEC_URL=http://127.0.0.1:7422|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|APPSEC_FAILURE_ACTION=.*|APPSEC_FAILURE_ACTION=deny|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
sed -i "s|REQUEST_TIMEOUT=.*|REQUEST_TIMEOUT=2500|g" /src/crowdsec-nginx-bouncer/lua-mod/config_example.conf && \
Expand All @@ -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 \
Expand Down Expand Up @@ -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 \

Check warning on line 119 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "ACME_KEY_TYPE") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
TV=1a \
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 \
Expand All @@ -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 \
Expand All @@ -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"]
Expand Down
71 changes: 33 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
# 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.** <br>
**Note: Other Databases like MariaDB may work, but are unsupported.** <br>
**Note: watchtower does NOT update NPMplus, you need to do it yourself (it will only pull the image, but not update the container itself).** <br>
**Note: access.log/stream.log, logrotate and goaccess are NOT enabled by default bceuase of GDPR, you can enable them in the compose.yaml.** <br>

**Note: add `net.ipv4.ip_unprivileged_port_start=0` at the end of `/etc/sysctl.conf` to support PUID/PGID in network mode host.** <br>
**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).** <br>
**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).** <br>
**MOZILLA_PKIX_ERROR_REQUIRED_TLS_FEATURE_MISSING: please see/read/use the ACME_MUST_STAPLE env option of the compose.yaml** <br>

**Note: no armv7, route53 and aws cloudfront ip ranges support.** <br>
**Note: other Databases like MariaDB/MySQL or PostgreSQL may work, but are unsupported and have no advantage over SQLite.** <br>
**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).** <br>
**Note: remember to add your domain to the hsts preload list if you use security headers: https://hstspreload.org** <br>

## Project Goal
I created this project to fill a personal need to provide users with an easy way to accomplish reverse
proxying hosts with TLS termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
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
Expand All @@ -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://<ip>: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/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/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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -112,9 +107,9 @@ Immediately after logging in with this default user you will be asked to modify

# Crowdsec
Note: Using Immich behind NPMplus with enabled appsec causes issues, see here: [#1241](https://github.com/ZoeyVid/NPMplus/discussions/1241)
1. set LOGROTATE to `true` in your `compose.yaml` and redeploy
2. Install crowdsec using this compose file: https://github.com/ZoeyVid/NPMplus/blob/develop/compose.crowdsec.yaml and set the timezone for it
3. open `/opt/crowdsec/conf/acquis.d/npmplus.yaml` and fill it with:
1. Install crowdsec and the ZoeyVid/npmplus collection for example by using crowdsec container at the end of the compose.yaml
2. set LOGROTATE to `true` in your `compose.yaml` and redeploy
3. open `/opt/crowdsec/conf/acquis.d/npmplus.yaml` (path may be different depending how you installed crowdsec) and fill it with:
```yaml
filenames:
- /opt/npm/nginx/access.log
Expand Down Expand Up @@ -142,16 +137,16 @@ labels:
```
4. make sure to use `network_mode: host` in your compose file
5. run `docker exec crowdsec cscli bouncers add npmplus -o raw` and save the output
6. open `/opt/npm/etc/crowdsec/crowdsec.conf`
6. open `/opt/npm/crowdsec/crowdsec.conf`
7. set `ENABLED` to `true`
8. use the output of step 5 as `API_KEY`
9. save the file
10. redeploy the `compose.yaml`

# coreruleset plugins
1. Download the plugin (all files inside the `plugins` folder of the git repo), most time: `<plugin-name>-before.conf`, `<plugin-name>-config.conf` and `<plugin-name>-after.conf` and sometimes `<plugin-name>.data` and/or `<plugin-name>.lua` or somilar files
2. put them into the `/opt/npm/etc/modsecurity/crs-plugins` folder
3. maybe open the `/opt/npm/etc/modsecurity/crs-plugins/<plugin-name>-config.conf` and configure the plugin
2. put them into the `/opt/npm/modsecurity/crs-plugins` folder
3. maybe open the `/opt/npm/modsecurity/crs-plugins/<plugin-name>-config.conf` and configure the plugin

# Use as webserver
1. Create a new Proxy Host
Expand All @@ -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 / {
Expand All @@ -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 <br>
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) <br>
if you need to run scripts before NPMplus launches put them under: `/opt/npm/prerun/*.sh` (please add `#!/usr/bin/env sh` / `#!/usr/bin/env bash` to the top of the script) <br>
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
Expand Down
4 changes: 2 additions & 2 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
2 changes: 1 addition & 1 deletion backend/internal/access-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ const internalAccessList = {
* @returns {String}
*/
getFilename: (list) => {
return '/data/etc/access/' + list.id;
return '/data/access/' + list.id;
},

/**
Expand Down
Loading

0 comments on commit f93a33f

Please sign in to comment.