From e61133c557d30d5722bd7c09588ea79b97f72c8f Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sun, 25 Jan 2026 12:29:35 +1100 Subject: [PATCH] DOCS: reverse proxy Signed-off-by: jokob-sk --- docs/REVERSE_PROXY.md | 893 +--------------------------------- docs/REVERSE_PROXY_CADDY.md | 892 +++++++++++++++++++++++++++++++++ docs/REVERSE_PROXY_TRAEFIK.md | 86 ++++ mkdocs.yml | 5 +- 4 files changed, 991 insertions(+), 885 deletions(-) create mode 100644 docs/REVERSE_PROXY_CADDY.md create mode 100644 docs/REVERSE_PROXY_TRAEFIK.md diff --git a/docs/REVERSE_PROXY.md b/docs/REVERSE_PROXY.md index 84f6d176..d7c4d098 100755 --- a/docs/REVERSE_PROXY.md +++ b/docs/REVERSE_PROXY.md @@ -3,6 +3,9 @@ > [!NOTE] > This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it. +> [!NOTE] +> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports. +> Ensure your reverse proxy allows traffic to both for proper functionality. > [!IMPORTANT] > You will need to specify 2 entries in your reverse proxy, one for the front end, one for the backend URL. The custom backend URL, including the `GRAPHQL_PORT`, needs to be aslo specified in the `BACKEND_API_URL` setting.This is the URL that points to the backend API server. @@ -11,6 +14,12 @@ > > ![NPM set up](./img/REVERSE_PROXY/nginx_proxy_manager_npm.png) +See also: + +- [CADDY + AUTHENTIK](./REVERSE_PROXY_CADDY.md) +- [TRAEFIK](./REVERSE_PROXY_TRAEFIK.md) + + ## NGINX HTTP Configuration (Direct Path) > Submitted by amazing [cvc90](https://github.com/cvc90) 🙏 @@ -514,888 +523,4 @@ Mapping the updated file (on the local filesystem at `/appl/docker/netalertx/def ... ``` -## Caddy + Authentik Outpost Proxy SSO -> Submitted by [luckylinux](https://github.com/luckylinux) 🙏. -### Introduction - -This Setup assumes: - -1. Authentik Installation running on a separate Host at `https://authentik.MYDOMAIN.TLD` -2. Container Management is done on Baremetal OR in a Virtual Machine (KVM/Xen/ESXi/..., no LXC Containers !): - i. Docker and Docker Compose configured locally running as Root (needed for `network_mode: host`) OR - ii. Podman (optionally `podman-compose`) configured locally running as Root (needed for `network_mode: host`) -3. TLS Certificates are already pre-obtained and located at `/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD`. - I use the `certbot/dns-cloudflare` Podman Container on a separate Host to obtain the Certificates which I then distribute internally. - This Container uses the Wildcard Top-Level Domain Certificate which is valid for `MYDOMAIN.TLD` and `*.MYDOMAIN.TLD`. -4. Proxied Access - i. NetAlertX Web Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD` (default HTTPS Port 443: `https://netalertx.MYDOMAIN.TLD:443`) with `REPORT_DASHBOARD_URL=https://netalertx.MYDOMAIN.TLD` - ii. NetAlertX GraphQL Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:20212` with `BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212` - iii. Authentik Proxy Outpost is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:9443` -5. Internal Ports - i. NGINX Web Server is set to listen on internal Port 20211 set via `PORT=20211` - ii. Python Web Server is set to listen on internal Port `GRAPHQL_PORT=20219` - iii. Authentik Proxy Outpost is listening on internal Port `AUTHENTIK_LISTEN__HTTP=[::1]:6000` (unencrypted) and Port `AUTHENTIK_LISTEN__HTTPS=[::1]:6443` (encrypted) - -8. Some further Configuration for Caddy is performed in Terms of Logging, SSL Certificates, etc - -It's also possible to [let Caddy automatically request & keep TLS Certificates up-to-date](https://caddyserver.com/docs/automatic-https), although please keep in mind that: - -1. You risk enumerating your LAN. Every Domain/Subdomain for which Caddy requests a TLS Certificate for you will result in that Host to be listed on [List of Letsencrypt Certificates issued](https://crt.sh/). -2. You need to either: - i. Open Port 80 for external Access ([HTTP challenge](https://caddyserver.com/docs/automatic-https#http-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain - ii. Open Port 443 for external Access ([TLS-ALPN challenge](https://caddyserver.com/docs/automatic-https#tls-alpn-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain - iii. Give Caddy the Credentials to update the DNS Records at your DNS Provider ([DNS challenge](https://caddyserver.com/docs/automatic-https#dns-challenge)) - -You can also decide to deploy your own Certificates & Certification Authority, either manually with OpenSSL, or by using something like [mkcert](https://github.com/FiloSottile/mkcert). - -In Terms of IP Stack Used: -- External: Caddy listens on both IPv4 and IPv6. -- Internal: - - Authentik Outpost Proxy listens on IPv6 `[::1]` - - NetAlertX listens on IPv4 `0.0.0.0` - -### Flow -The Traffic Flow will therefore be as follows: - -- Web GUI: - i. Client accesses `http://authentik.MYDOMAIN.TLD:80`: default (built-in Caddy) Redirect to `https://authentik.MYDOMAIN.TLD:443` - ii. Client accesses `https://authentik.MYDOMAIN.TLD:443` -> reverse Proxy to internal Port 20211 (NetAlertX Web GUI / NGINX - unencrypted) -- GraphQL: Client accesses `https://authentik.MYDOMAIN.TLD:20212` -> reverse Proxy to internal Port 20219 (NetAlertX GraphQL - unencrypted) -- Authentik Outpost: Client accesses `https://authentik.MYDOMAIN.TLD:9443` -> reverse Proxy to internal Port 6000 (Authentik Outpost Proxy - unencrypted) - -An Overview of the Flow is provided in the Picture below: - -![Reverse Proxy Traffic Flow with Authentik SSSO](./img/REVERSE_PROXY/reverse_proxy_flow.svg) - -### Security Considerations - -#### Caddy should be run rootless - -> [!WARNING] -> By default Caddy runs as `root` which is a Security Risk. -> In order to solve this, it's recommended to create an unprivileged User `caddy` and Group `caddy` on the Host: -> ``` -> groupadd --gid 980 caddy -> useradd --shell /usr/sbin/nologin --gid 980 --uid 980 -c "Caddy web server" --base-dir /var/lib/caddy -> ``` - -At least using Quadlets with Usernames (NOT required with UID/GID), but possibly using Compose in certain Cases as well, a custom `/etc/passwd` and `/etc/group` might need to be bind-mounted inside the Container. -`passwd`: -``` -root:x:0:0:root:/root:/bin/sh -bin:x:1:1:bin:/bin:/sbin/nologin -daemon:x:2:2:daemon:/sbin:/sbin/nologin -lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin -sync:x:5:0:sync:/sbin:/bin/sync -shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown -halt:x:7:0:halt:/sbin:/sbin/halt -mail:x:8:12:mail:/var/mail:/sbin/nologin -news:x:9:13:news:/usr/lib/news:/sbin/nologin -uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin -cron:x:16:16:cron:/var/spool/cron:/sbin/nologin -ftp:x:21:21::/var/lib/ftp:/sbin/nologin -sshd:x:22:22:sshd:/dev/null:/sbin/nologin -games:x:35:35:games:/usr/games:/sbin/nologin -ntp:x:123:123:NTP:/var/empty:/sbin/nologin -guest:x:405:100:guest:/dev/null:/sbin/nologin -nobody:x:65534:65534:nobody:/:/sbin/nologin -caddy:x:980:980:caddy:/var/lib/caddy:/bin/sh -``` - -`group`: -``` -root:x:0:root -bin:x:1:root,bin,daemon -daemon:x:2:root,bin,daemon -sys:x:3:root,bin -adm:x:4:root,daemon -tty:x:5: -disk:x:6:root -lp:x:7:lp -kmem:x:9: -wheel:x:10:root -floppy:x:11:root -mail:x:12:mail -news:x:13:news -uucp:x:14:uucp -cron:x:16:cron -audio:x:18: -cdrom:x:19: -dialout:x:20:root -ftp:x:21: -sshd:x:22: -input:x:23: -tape:x:26:root -video:x:27:root -netdev:x:28: -kvm:x:34:kvm -games:x:35: -shadow:x:42: -www-data:x:82: -users:x:100:games -ntp:x:123: -abuild:x:300: -utmp:x:406: -ping:x:999: -nogroup:x:65533: -nobody:x:65534: -caddy:x:980: -``` - -#### Authentication of GraphQL Endpoint - -> [!WARNING] -> Currently the GraphQL Endpoint is NOT authenticated ! - -### Environment Files -Depending on the Preference of the User (Environment Variables defined in Compose/Quadlet or in external `.env` File[s]), it might be prefereable to place at least some Environment Variables in external `.env` and `.env.` Files. - -The following is proposed: - -- `.env`: common Settings (empty by Default) -- `.env.caddy`: Caddy Settings -- `.env.server`: NetAlertX Server/Application Settings -- `.env.outpost.proxy`: Authentik Proxy Outpost Settings - -The following Contents is assumed. - -`.env.caddy`: -``` -# Define Application Hostname -APPLICATION_HOSTNAME=netalertx.MYDOMAIN.TLD - -# Define Certificate Domain -# In this case: use Wildcard Certificate -APPLICATION_CERTIFICATE_DOMAIN=MYDOMAIN.TLD -APPLICATION_CERTIFICATE_CERT_FILE=fullchain.pem -APPLICATION_CERTIFICATE_KEY_FILE=privkey.pem - -# Define Outpost Hostname -OUTPOST_HOSTNAME=netalertx.MYDOMAIN.TLD - -# Define Outpost External Port (TLS) -OUTPOST_EXTERNAL_PORT=9443 -``` - -`.env.server`: -``` -PORT=20211 -PORT_SSL=443 -NETALERTX_NETWORK_MODE=host -LISTEN_ADDR=0.0.0.0 -GRAPHQL_PORT=20219 -NETALERTX_DEBUG=1 -BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212 -``` - -`.env.outpost.proxy`: -``` -AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -AUTHENTIK_LISTEN__HTTP=[::1]:6000 -AUTHENTIK_LISTEN__HTTPS=[::1]:6443 -``` - -### Compose Setup -``` -version: "3.8" -services: - netalertx-caddy: - container_name: netalertx-caddy - - network_mode: host - image: docker.io/library/caddy:latest - pull: missing - - env_file: - - .env - - .env.caddy - - environment: - CADDY_DOCKER_CADDYFILE_PATH: "/etc/caddy/Caddyfile" - - volumes: - - ./Caddyfile:/etc/caddy/Caddyfile:ro,z - - /var/lib/containers/data/netalertx/caddy:/data/caddy:rw,z - - /var/lib/containers/log/netalertx/caddy:/var/log:rw,z - - /var/lib/containers/config/netalertx/caddy:/config/caddy:rw,z - - /var/lib/containers/certificates/letsencrypt:/certificates:ro,z - - # Set User - user: "caddy:caddy" - - # Automatically restart Container - restart: unless-stopped - - netalertx-server: - container_name: netalertx-server # The name when you docker contiainer ls - - network_mode: host # Use host networking for ARP scanning and other services - - depends_on: - netalertx-caddy: - condition: service_started - restart: true - netalertx-outpost-proxy: - condition: service_started - restart: true - - # Local built Image including latest Changes - image: localhost/netalertx-dev:dev-20260109-232454 - - read_only: true # Make the container filesystem read-only - - # It is most secure to start with user 20211, but then we lose provisioning capabilities. - # user: "${NETALERTX_UID:-20211}:${NETALERTX_GID:-20211}" - cap_drop: # Drop all capabilities for enhanced security - - ALL - cap_add: # Add only the necessary capabilities - - NET_ADMIN # Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf - - NET_RAW # Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf - - NET_BIND_SERVICE # Required to bind to privileged ports with nbtscan - - CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges - - SETUID # Required for root-entrypoint to switch to non-root user - - SETGID # Required for root-entrypoint to switch to non-root group - volumes: - - # Override NGINX Configuration Template - - type: bind - source: /var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template - target: /services/config/nginx/netalertx.conf.template - read_only: true - bind: - selinux: Z - - # Letsencrypt Certificates - - type: bind - source: /var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD - target: /certificates - read_only: true - bind: - selinux: Z - - # Data Storage for NetAlertX - - type: bind # Persistent Docker-managed Named Volume for storage - source: /var/lib/containers/data/netalertx/server - target: /data # consolidated configuration and database storage - read_only: false # writable volume - bind: - selinux: Z - - # Set the Timezone - - type: bind # Bind mount for timezone consistency - source: /etc/localtime - target: /etc/localtime - read_only: true - bind: - selinux: Z - - # tmpfs mounts for writable directories in a read-only container and improve system performance - # All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts - # mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh - - type: tmpfs - target: /tmp - tmpfs-mode: 1700 - uid: 0 - gid: 0 - rw: true - noexec: true - nosuid: true - nodev: true - async: true - noatime: true - nodiratime: true - bind: - selinux: Z - - env_file: - - .env - - .env.server - - environment: - PUID: ${NETALERTX_UID:-20211} # Runtime UID after priming (Synology/no-copy-up safe) - PGID: ${NETALERTX_GID:-20211} # Runtime GID after priming (Synology/no-copy-up safe) - LISTEN_ADDR: ${LISTEN_ADDR:-0.0.0.0} # Listen for connections on all interfaces - PORT: ${PORT:-20211} # Application port - PORT_SSL: ${PORT_SSL:-443} - GRAPHQL_PORT: ${GRAPHQL_PORT:-20212} # GraphQL API port - ALWAYS_FRESH_INSTALL: ${ALWAYS_FRESH_INSTALL:-false} # Set to true to reset your config and database on each container start - NETALERTX_DEBUG: ${NETALERTX_DEBUG:-0} # 0=kill all services and restart if any dies. 1 keeps running dead services. - BACKEND_API_URL: ${BACKEND_API_URL-"https://netalertx.MYDOMAIN.TLD:20212"} - - # Resource limits to prevent resource exhaustion - mem_limit: 4096m # Maximum memory usage - mem_reservation: 2048m # Soft memory limit - cpu_shares: 512 # Relative CPU weight for CPU contention scenarios - pids_limit: 512 # Limit the number of processes/threads to prevent fork bombs - logging: - driver: "json-file" # Use JSON file logging driver - options: - max-size: "10m" # Rotate log files after they reach 10MB - max-file: "3" # Keep a maximum of 3 log files - - # Always restart the container unless explicitly stopped - restart: unless-stopped - - # To sign Out, you need to visit - # {$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT}/outpost.goauthentik.io/sign_out - netalertx-outpost-proxy: - container_name: netalertx-outpost-proxy - - network_mode: host - - depends_on: - netalertx-caddy: - condition: service_started - restart: true - - restart: unless-stopped - - image: ghcr.io/goauthentik/proxy:2025.10 - pull: missing - - env_file: - - .env - - .env.outpost.proxy - - environment: - AUTHENTIK_HOST: "https://authentik.MYDOMAIN.TLD" - AUTHENTIK_INSECURE: false - AUTHENTIK_LISTEN__HTTP: "[::1]:6000" - AUTHENTIK_LISTEN__HTTPS: "[::1]:6443" -``` - -### Quadlet Setup -`netalertx.pod`: -``` -[Pod] -# Name of the Pod -PodName=netalertx - -# Network Mode Host is required for ARP to work -Network=host - -# Automatically start Pod at Boot Time -[Install] -WantedBy=default.target -``` - -`netalertx-caddy.container`: -``` -[Unit] -Description=NetAlertX Caddy Container - -[Service] -Restart=always - -[Container] -ContainerName=netalertx-caddy - -Pod=netalertx.pod -StartWithPod=true - -# Generic Environment Configuration -EnvironmentFile=.env - -# Caddy Specific Environment Configuration -EnvironmentFile=.env.caddy - -Environment=CADDY_DOCKER_CADDYFILE_PATH=/etc/caddy/Caddyfile - -Image=docker.io/library/caddy:latest -Pull=missing - -# Run as rootless -# Specifying User & Group by Name requires to mount a custom passwd & group File inside the Container -# Otherwise an Error like the following will result: netalertx-caddy[593191]: Error: unable to find user caddy: no matching entries in passwd file -# User=caddy -# Group=caddy -# Volume=/var/lib/containers/config/netalertx/caddy-rootless/passwd:/etc/passwd:ro,z -# Volume=/var/lib/containers/config/netalertx/caddy-rootless/group:/etc/group:ro,z - -# Run as rootless -# Specifying User & Group by UID/GID will NOT require a custom passwd / group File to be bind-mounted inside the Container -User=980 -Group=980 - -Volume=./Caddyfile:/etc/caddy/Caddyfile:ro,z -Volume=/var/lib/containers/data/netalertx/caddy:/data/caddy:z -Volume=/var/lib/containers/log/netalertx/caddy:/var/log:z -Volume=/var/lib/containers/config/netalertx/caddy:/config/caddy:z -Volume=/var/lib/containers/certificates/letsencrypt:/certificates:ro,z -``` - -`netalertx-server.container`: -``` -[Unit] -Description=NetAlertX Server Container -Requires=netalertx-caddy.service netalertx-outpost-proxy.service -After=netalertx-caddy.service netalertx-outpost-proxy.service - -[Service] -Restart=always - -[Container] -ContainerName=netalertx-server - -Pod=netalertx.pod -StartWithPod=true - -# Local built Image including latest Changes -Image=localhost/netalertx-dev:dev-20260109-232454 -Pull=missing - -# Make the container filesystem read-only -ReadOnly=true - -# Drop all capabilities for enhanced security -DropCapability=ALL - -# It is most secure to start with user 20211, but then we lose provisioning capabilities. -# User=20211:20211 - -# Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf -AddCapability=NET_ADMIN - -# Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf -AddCapability=NET_RAW - -# Required to bind to privileged ports with nbtscan -AddCapability=NET_BIND_SERVICE - -# Required for root-entrypoint to chown /data + /tmp before dropping privileges -AddCapability=CHOWN - -# Required for root-entrypoint to switch to non-root user -AddCapability=SETUID - -# Required for root-entrypoint to switch to non-root group -AddCapability=SETGID - -# Override the Configuration Template -Volume=/var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template:/services/config/nginx/netalertx.conf.template:ro,Z - -# Letsencrypt Certificates -Volume=/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD:/certificates:ro,Z - -# Data Storage for NetAlertX -Volume=/var/lib/containers/data/netalertx/server:/data:rw,Z - -# Set the Timezone -Volume=/etc/localtime:/etc/localtime:ro,Z - -# tmpfs mounts for writable directories in a read-only container and improve system performance -# All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts -# mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh -# Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,uid=0,gid=0,rw=true,noexec=true,nosuid=true,nodev=true,async=true,noatime=true,nodiratime=true,relabel=private -Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,rw=true,noexec=true,nosuid=true,nodev=true - -# Environment Configuration -EnvironmentFile=.env -EnvironmentFile=.env.server - -# Runtime UID after priming (Synology/no-copy-up safe) -Environment=PUID=20211 - -# Runtime GID after priming (Synology/no-copy-up safe) -Environment=PGID=20211 - -# Listen for connections on all interfaces (IPv4) -Environment=LISTEN_ADDR=0.0.0.0 - -# Application port -Environment=PORT=20211 - -# SSL Port -Environment=PORT_SSL=443 - -# GraphQL API port -Environment=GRAPHQL_PORT=20212 - -# Set to true to reset your config and database on each container start -Environment=ALWAYS_FRESH_INSTALL=false - -# 0=kill all services and restart if any dies. 1 keeps running dead services. -Environment=NETALERTX_DEBUG=0 - -# Set the GraphQL URL for external Access (via Caddy Reverse Proxy) -Environment=BACKEND_API_URL=https://netalertx-fedora.MYDOMAIN.TLD:20212 - -# Resource limits to prevent resource exhaustion -# Maximum memory usage -Memory=4g - -# Limit the number of processes/threads to prevent fork bombs -PidsLimit=512 - -# Relative CPU weight for CPU contention scenarios -PodmanArgs=--cpus=2 -PodmanArgs=--cpu-shares=512 - -# Soft memory limit -PodmanArgs=--memory-reservation=2g - -# !! The following Keys are unfortunately not [yet] supported !! - -# Relative CPU weight for CPU contention scenarios -#CpuShares=512 - -# Soft memory limit -#MemoryReservation=2g -``` - -`netalertx-outpost-proxy.container`: -``` -[Unit] -Description=NetAlertX Authentik Proxy Outpost Container -Requires=netalertx-caddy.service -After=netalertx-caddy.service - -[Service] -Restart=always - -[Container] -ContainerName=netalertx-outpost-proxy - -Pod=netalertx.pod -StartWithPod=true - -# General Configuration -EnvironmentFile=.env - -# Authentik Outpost Proxy Specific Configuration -EnvironmentFile=.env.outpost.proxy - -Environment=AUTHENTIK_HOST=https://authentik.MYDOMAIN.TLD -Environment=AUTHENTIK_INSECURE=false - -# Overrides Value from .env.outpost.rac -# Environment=AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - -# Optional setting to be used when `authentik_host` for internal communication doesn't match the public URL -# Environment=AUTHENTIK_HOST_BROWSER=https://authentik.MYDOMAIN.TLD - -# Container Image -Image=ghcr.io/goauthentik/proxy:2025.10 -Pull=missing - -# Network Configuration -Network=container:supermicro-ikvm-pve031-caddy - -# Security Configuration -NoNewPrivileges=true -``` - -### Firewall Setup - -Depending on which GNU/Linux Distribution you are running, it might be required to open up some Firewall Ports in order to be able to access the Endpoints from outside the Host itself. - -This is for instance the Case for Fedora Linux, where I had to open: - -- Port 20212 for external GraphQL Access (both TCP & UDP are open, unsure if UDP is required) -- Port 9443 for external Authentik Outpost Proxy Access (both TCP & UDP are open, unsure if UDP is required) - -![Fedora Firewall Configuration](./img/REVERSE_PROXY/fedora-firewall.png) - -### Authentik Setup - -In order to enable Single Sign On (SSO) with Authentik, you will need to create a Provider, an Application and an Outpost. - -![Authentik Left Sidebar](./img/REVERSE_PROXY/authentik-sidebar.png) - -First of all, using the Left Sidebar, navigate to `Applications` → `Providers`, click on `Create` (Blue Button at the Top of the Screen), select `Proxy Provider`, then click `Next`: -![Authentik Provider Setup (Part 1)](./img/REVERSE_PROXY/authentik-provider-setup-01.png) - -Fill in the required Fields: - -- Name: choose a Name for the Provider (e.g. `netalertx`) -- Authorization Flow: choose the Authorization Flow. I typically use `default-provider-authorization-implicit-consent (Authorize Application)`. If you select the `default-provider-authorization-explicit-consent (Authorize Application)` you will need to authorize Authentik every Time you want to log in NetAlertX, which can make the Experience less User-friendly -- Type: Click on `Forward Auth (single application)` -- External Host: set to `https://netalertx.MYDOMAIN.TLD` - -Click `Finish`. - -![Authentik Provider Setup (Part 2)](./img/REVERSE_PROXY/authentik-provider-setup-02.png) - -Now, using the Left Sidebar, navigate to `Applications` → `Applications`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields: - -- Name: choose a Name for the Application (e.g. `netalertx`) -- Slug: choose a Slug for the Application (e.g. `netalertx`) -- Group: optionally you can assign this Application to a Group of Applications of your Choosing (for grouping Purposes within Authentik User Interface) -- Provider: select the Provider you created the the `Providers` Section previosly (e.g. `netalertx`) - -Then click `Create`. - -![Authentik Application Setup (Part 1)](./img/REVERSE_PROXY/authentik-application-setup-01.png) - -Now, using the Left Sidebar, navigate to `Applications` → `Outposts`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields: - -- Name: choose a Name for the Outpost (e.g. `netalertx`) -- Type: `Proxy` -- Integration: open the Dropdown and click on `---------`. Make sure it is NOT set to `Local Docker connection` ! - -In the `Available Applications` Section, select the Application you created in the Previous Step, then click the right Arrow (approx. located in the Center of the Screen), so that it gets copied in the `Selected Applications` Section. - -Then click `Create`. - -![Authentik Outpost Setup (Part 1)](./img/REVERSE_PROXY/authentik-outpost-setup-01.png) - -Wait a few Seconds for the Outpost to be created. Once it appears in the List, click on `Deployment Info` on the Right Side of the relevant Line. - -![Authentik Outpost Setup (Part 2)](./img/REVERSE_PROXY/authentik-outpost-setup-02.png) - -Take note of that Token. You will need it for the Authentik Outpost Proxy Container, which will read it as the `AUTHENTIK_TOKEN` Environment Variable. - -### NGINX Configuration inside NetAlertX Container -> [!NOTE] -> This is something that was implemented based on the previous Content of this Reverse Proxy Document. -> Due to some Buffer Warnings/Errors in the Logs as well as some other Issues I was experiencing, I increased a lot the client_body_buffer_size and large_client_header_buffers Parameters, although these might not be required anymore. -> Further Testing might be required. - -``` -# Set number of worker processes automatically based on number of CPU cores. -worker_processes auto; - -# Enables the use of JIT for regular expressions to speed-up their processing. -pcre_jit on; - -# Configures default error logger. -error_log /tmp/log/nginx-error.log warn; - -pid /tmp/run/nginx.pid; - -events { - # The maximum number of simultaneous connections that can be opened by - # a worker process. - worker_connections 1024; -} - -http { - - # Mapping of temp paths for various nginx modules. - client_body_temp_path /tmp/nginx/client_body; - proxy_temp_path /tmp/nginx/proxy; - fastcgi_temp_path /tmp/nginx/fastcgi; - uwsgi_temp_path /tmp/nginx/uwsgi; - scgi_temp_path /tmp/nginx/scgi; - - # Includes mapping of file name extensions to MIME types of responses - # and defines the default type. - include /services/config/nginx/mime.types; - default_type application/octet-stream; - - # Name servers used to resolve names of upstream servers into addresses. - # It's also needed when using tcpsocket and udpsocket in Lua modules. - #resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001]; - - # Don't tell nginx version to the clients. Default is 'on'. - server_tokens off; - - # Specifies the maximum accepted body size of a client request, as - # indicated by the request header Content-Length. If the stated content - # length is greater than this size, then the client receives the HTTP - # error code 413. Set to 0 to disable. Default is '1m'. - client_max_body_size 1m; - - # Sendfile copies data between one FD and other from within the kernel, - # which is more efficient than read() + write(). Default is off. - sendfile on; - - # Causes nginx to attempt to send its HTTP response head in one packet, - # instead of using partial frames. Default is 'off'. - tcp_nopush on; - - - # Enables the specified protocols. Default is TLSv1 TLSv1.1 TLSv1.2. - # TIP: If you're not obligated to support ancient clients, remove TLSv1.1. - ssl_protocols TLSv1.2 TLSv1.3; - - # Path of the file with Diffie-Hellman parameters for EDH ciphers. - # TIP: Generate with: `openssl dhparam -out /etc/ssl/nginx/dh2048.pem 2048` - #ssl_dhparam /etc/ssl/nginx/dh2048.pem; - - # Specifies that our cipher suits should be preferred over client ciphers. - # Default is 'off'. - ssl_prefer_server_ciphers on; - - # Enables a shared SSL cache with size that can hold around 8000 sessions. - # Default is 'none'. - ssl_session_cache shared:SSL:2m; - - # Specifies a time during which a client may reuse the session parameters. - # Default is '5m'. - ssl_session_timeout 1h; - - # Disable TLS session tickets (they are insecure). Default is 'on'. - ssl_session_tickets off; - - - # Enable gzipping of responses. - gzip on; - - # Set the Vary HTTP header as defined in the RFC 2616. Default is 'off'. - gzip_vary on; - - - # Specifies the main log format. - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - # Sets the path, format, and configuration for a buffered log write. - access_log /tmp/log/nginx-access.log main; - - - # Virtual host config (unencrypted) - server { - listen ${LISTEN_ADDR}:${PORT} default_server; - root /app/front; - index index.php; - add_header X-Forwarded-Prefix "/app" always; - - server_name netalertx-server; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - client_body_buffer_size 512k; - large_client_header_buffers 64 128k; - - location ~* \.php$ { - # Set Cache-Control header to prevent caching on the first load - add_header Cache-Control "no-store"; - fastcgi_pass unix:/tmp/run/php.sock; - include /services/config/nginx/fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_connect_timeout 75; - fastcgi_send_timeout 600; - fastcgi_read_timeout 600; - } - } -} -``` - -### Caddyfile -``` -# Example and Guide -# https://caddyserver.com/docs/caddyfile/options - -# General Options -{ - # (Optional) Debug Mode - # debug - - # (Optional ) Enable / Disable Admin API - admin off - - # TLS Options - # (Optional) Disable Certificates Management (only if SSL/TLS Certificates are managed by certbot or other external Tools) - auto_https disable_certs -} - -# (Optional Enable Admin API) -# localhost { -# reverse_proxy /api/* localhost:9001 -# } - -# NetAlertX Web GUI (HTTPS Port 443) -# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required -{$APPLICATION_HOSTNAME}:443 { - tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} - - log { - output file /var/log/{$APPLICATION_HOSTNAME}/access_web.json { - roll_size 100MiB - roll_keep 5000 - roll_keep_for 720h - roll_uncompressed - } - - format json - } - - route { - # Always forward outpost path to actual outpost - reverse_proxy /outpost.goauthentik.io/* https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { - header_up Host {http.reverse_proxy.upstream.hostport} - } - - # Forward authentication to outpost - forward_auth https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { - uri /outpost.goauthentik.io/auth/caddy - - # Capitalization of the headers is important, otherwise they will be empty - copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version - - # (Optional) - # If not set, trust all private ranges, but for Security Reasons, this should be set to the outposts IP - trusted_proxies private_ranges - } - } - - # IPv4 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host) - reverse_proxy http://0.0.0.0:20211 - - # IPv6 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host) - # reverse_proxy http://[::1]:20211 -} - -# NetAlertX GraphQL Endpoint (HTTPS Port 20212) -# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required -{$APPLICATION_HOSTNAME}:20212 { - tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} - - log { - output file /var/log/{$APPLICATION_HOSTNAME}/access_graphql.json { - roll_size 100MiB - roll_keep 5000 - roll_keep_for 720h - roll_uncompressed - } - - format json - } - - # IPv4 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host) - reverse_proxy http://0.0.0.0:20219 - - # IPv6 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host) - # reverse_proxy http://[::1]:6000 -} - -# Authentik Outpost -# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required -{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { - tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} - - log { - output file /var/log/outpost/{$OUTPOST_HOSTNAME}/access.json { - roll_size 100MiB - roll_keep 5000 - roll_keep_for 720h - roll_uncompressed - } - - format json - } - - # IPv4 Reverse Proxy to internal unencrypted Host - # reverse_proxy http://0.0.0.0:6000 - - # IPv6 Reverse Proxy to internal unencrypted Host - reverse_proxy http://[::1]:6000 -} -``` - -### Login -Now try to login by visiting `https://netalertx.MYDOMAIN.TLD`. - -You should be greeted with a Login Screen by Authentik. - -If you are already logged in Authentik, log out first. You can do that by visiting `https://netalertx.MYDOMAIN.TLD/outpost.goauthentik.io/sign_out`, then click on `Log out of authentik` (2nd Button). Or you can just sign out from your Authentik Admin Panel at `https://authentik.MYDOMAIN.TLD`. - -If everything works as expected, then you can now set `SETPWD_enable_password=false` to disable double Authentication. - -![Authentik Login Screen](./img/REVERSE_PROXY/authentik-login.png) diff --git a/docs/REVERSE_PROXY_CADDY.md b/docs/REVERSE_PROXY_CADDY.md new file mode 100644 index 00000000..0bde799d --- /dev/null +++ b/docs/REVERSE_PROXY_CADDY.md @@ -0,0 +1,892 @@ +## Caddy + Authentik Outpost Proxy SSO +> Submitted by [luckylinux](https://github.com/luckylinux) 🙏. + +> [!NOTE] +> This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it. + +> [!NOTE] +> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports. +> Ensure your reverse proxy allows traffic to both for proper functionality. + +### Introduction + +This Setup assumes: + +1. Authentik Installation running on a separate Host at `https://authentik.MYDOMAIN.TLD` +2. Container Management is done on Baremetal OR in a Virtual Machine (KVM/Xen/ESXi/..., no LXC Containers !): + i. Docker and Docker Compose configured locally running as Root (needed for `network_mode: host`) OR + ii. Podman (optionally `podman-compose`) configured locally running as Root (needed for `network_mode: host`) +3. TLS Certificates are already pre-obtained and located at `/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD`. + I use the `certbot/dns-cloudflare` Podman Container on a separate Host to obtain the Certificates which I then distribute internally. + This Container uses the Wildcard Top-Level Domain Certificate which is valid for `MYDOMAIN.TLD` and `*.MYDOMAIN.TLD`. +4. Proxied Access + i. NetAlertX Web Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD` (default HTTPS Port 443: `https://netalertx.MYDOMAIN.TLD:443`) with `REPORT_DASHBOARD_URL=https://netalertx.MYDOMAIN.TLD` + ii. NetAlertX GraphQL Interface is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:20212` with `BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212` + iii. Authentik Proxy Outpost is accessible via Caddy Reverse Proxy at `https://netalertx.MYDOMAIN.TLD:9443` +5. Internal Ports + i. NGINX Web Server is set to listen on internal Port 20211 set via `PORT=20211` + ii. Python Web Server is set to listen on internal Port `GRAPHQL_PORT=20219` + iii. Authentik Proxy Outpost is listening on internal Port `AUTHENTIK_LISTEN__HTTP=[::1]:6000` (unencrypted) and Port `AUTHENTIK_LISTEN__HTTPS=[::1]:6443` (encrypted) + +8. Some further Configuration for Caddy is performed in Terms of Logging, SSL Certificates, etc + +It's also possible to [let Caddy automatically request & keep TLS Certificates up-to-date](https://caddyserver.com/docs/automatic-https), although please keep in mind that: + +1. You risk enumerating your LAN. Every Domain/Subdomain for which Caddy requests a TLS Certificate for you will result in that Host to be listed on [List of Letsencrypt Certificates issued](https://crt.sh/). +2. You need to either: + i. Open Port 80 for external Access ([HTTP challenge](https://caddyserver.com/docs/automatic-https#http-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain + ii. Open Port 443 for external Access ([TLS-ALPN challenge](https://caddyserver.com/docs/automatic-https#tls-alpn-challenge)) in order for Letsencrypt to verify the Ownership of the Domain/Subdomain + iii. Give Caddy the Credentials to update the DNS Records at your DNS Provider ([DNS challenge](https://caddyserver.com/docs/automatic-https#dns-challenge)) + +You can also decide to deploy your own Certificates & Certification Authority, either manually with OpenSSL, or by using something like [mkcert](https://github.com/FiloSottile/mkcert). + +In Terms of IP Stack Used: +- External: Caddy listens on both IPv4 and IPv6. +- Internal: + - Authentik Outpost Proxy listens on IPv6 `[::1]` + - NetAlertX listens on IPv4 `0.0.0.0` + +### Flow +The Traffic Flow will therefore be as follows: + +- Web GUI: + i. Client accesses `http://authentik.MYDOMAIN.TLD:80`: default (built-in Caddy) Redirect to `https://authentik.MYDOMAIN.TLD:443` + ii. Client accesses `https://authentik.MYDOMAIN.TLD:443` -> reverse Proxy to internal Port 20211 (NetAlertX Web GUI / NGINX - unencrypted) +- GraphQL: Client accesses `https://authentik.MYDOMAIN.TLD:20212` -> reverse Proxy to internal Port 20219 (NetAlertX GraphQL - unencrypted) +- Authentik Outpost: Client accesses `https://authentik.MYDOMAIN.TLD:9443` -> reverse Proxy to internal Port 6000 (Authentik Outpost Proxy - unencrypted) + +An Overview of the Flow is provided in the Picture below: + +![Reverse Proxy Traffic Flow with Authentik SSSO](./img/REVERSE_PROXY/reverse_proxy_flow.svg) + +### Security Considerations + +#### Caddy should be run rootless + +> [!WARNING] +> By default Caddy runs as `root` which is a Security Risk. +> In order to solve this, it's recommended to create an unprivileged User `caddy` and Group `caddy` on the Host: +> ``` +> groupadd --gid 980 caddy +> useradd --shell /usr/sbin/nologin --gid 980 --uid 980 -c "Caddy web server" --base-dir /var/lib/caddy +> ``` + +At least using Quadlets with Usernames (NOT required with UID/GID), but possibly using Compose in certain Cases as well, a custom `/etc/passwd` and `/etc/group` might need to be bind-mounted inside the Container. +`passwd`: +``` +root:x:0:0:root:/root:/bin/sh +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/mail:/sbin/nologin +news:x:9:13:news:/usr/lib/news:/sbin/nologin +uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin +cron:x:16:16:cron:/var/spool/cron:/sbin/nologin +ftp:x:21:21::/var/lib/ftp:/sbin/nologin +sshd:x:22:22:sshd:/dev/null:/sbin/nologin +games:x:35:35:games:/usr/games:/sbin/nologin +ntp:x:123:123:NTP:/var/empty:/sbin/nologin +guest:x:405:100:guest:/dev/null:/sbin/nologin +nobody:x:65534:65534:nobody:/:/sbin/nologin +caddy:x:980:980:caddy:/var/lib/caddy:/bin/sh +``` + +`group`: +``` +root:x:0:root +bin:x:1:root,bin,daemon +daemon:x:2:root,bin,daemon +sys:x:3:root,bin +adm:x:4:root,daemon +tty:x:5: +disk:x:6:root +lp:x:7:lp +kmem:x:9: +wheel:x:10:root +floppy:x:11:root +mail:x:12:mail +news:x:13:news +uucp:x:14:uucp +cron:x:16:cron +audio:x:18: +cdrom:x:19: +dialout:x:20:root +ftp:x:21: +sshd:x:22: +input:x:23: +tape:x:26:root +video:x:27:root +netdev:x:28: +kvm:x:34:kvm +games:x:35: +shadow:x:42: +www-data:x:82: +users:x:100:games +ntp:x:123: +abuild:x:300: +utmp:x:406: +ping:x:999: +nogroup:x:65533: +nobody:x:65534: +caddy:x:980: +``` + +#### Authentication of GraphQL Endpoint + +> [!WARNING] +> Currently the GraphQL Endpoint is NOT authenticated ! + +### Environment Files +Depending on the Preference of the User (Environment Variables defined in Compose/Quadlet or in external `.env` File[s]), it might be prefereable to place at least some Environment Variables in external `.env` and `.env.` Files. + +The following is proposed: + +- `.env`: common Settings (empty by Default) +- `.env.caddy`: Caddy Settings +- `.env.server`: NetAlertX Server/Application Settings +- `.env.outpost.proxy`: Authentik Proxy Outpost Settings + +The following Contents is assumed. + +`.env.caddy`: +``` +# Define Application Hostname +APPLICATION_HOSTNAME=netalertx.MYDOMAIN.TLD + +# Define Certificate Domain +# In this case: use Wildcard Certificate +APPLICATION_CERTIFICATE_DOMAIN=MYDOMAIN.TLD +APPLICATION_CERTIFICATE_CERT_FILE=fullchain.pem +APPLICATION_CERTIFICATE_KEY_FILE=privkey.pem + +# Define Outpost Hostname +OUTPOST_HOSTNAME=netalertx.MYDOMAIN.TLD + +# Define Outpost External Port (TLS) +OUTPOST_EXTERNAL_PORT=9443 +``` + +`.env.server`: +``` +PORT=20211 +PORT_SSL=443 +NETALERTX_NETWORK_MODE=host +LISTEN_ADDR=0.0.0.0 +GRAPHQL_PORT=20219 +NETALERTX_DEBUG=1 +BACKEND_API_URL=https://netalertx.MYDOMAIN.TLD:20212 +``` + +`.env.outpost.proxy`: +``` +AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +AUTHENTIK_LISTEN__HTTP=[::1]:6000 +AUTHENTIK_LISTEN__HTTPS=[::1]:6443 +``` + +### Compose Setup +``` +version: "3.8" +services: + netalertx-caddy: + container_name: netalertx-caddy + + network_mode: host + image: docker.io/library/caddy:latest + pull: missing + + env_file: + - .env + - .env.caddy + + environment: + CADDY_DOCKER_CADDYFILE_PATH: "/etc/caddy/Caddyfile" + + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro,z + - /var/lib/containers/data/netalertx/caddy:/data/caddy:rw,z + - /var/lib/containers/log/netalertx/caddy:/var/log:rw,z + - /var/lib/containers/config/netalertx/caddy:/config/caddy:rw,z + - /var/lib/containers/certificates/letsencrypt:/certificates:ro,z + + # Set User + user: "caddy:caddy" + + # Automatically restart Container + restart: unless-stopped + + netalertx-server: + container_name: netalertx-server # The name when you docker contiainer ls + + network_mode: host # Use host networking for ARP scanning and other services + + depends_on: + netalertx-caddy: + condition: service_started + restart: true + netalertx-outpost-proxy: + condition: service_started + restart: true + + # Local built Image including latest Changes + image: localhost/netalertx-dev:dev-20260109-232454 + + read_only: true # Make the container filesystem read-only + + # It is most secure to start with user 20211, but then we lose provisioning capabilities. + # user: "${NETALERTX_UID:-20211}:${NETALERTX_GID:-20211}" + cap_drop: # Drop all capabilities for enhanced security + - ALL + cap_add: # Add only the necessary capabilities + - NET_ADMIN # Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf + - NET_RAW # Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf + - NET_BIND_SERVICE # Required to bind to privileged ports with nbtscan + - CHOWN # Required for root-entrypoint to chown /data + /tmp before dropping privileges + - SETUID # Required for root-entrypoint to switch to non-root user + - SETGID # Required for root-entrypoint to switch to non-root group + volumes: + + # Override NGINX Configuration Template + - type: bind + source: /var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template + target: /services/config/nginx/netalertx.conf.template + read_only: true + bind: + selinux: Z + + # Letsencrypt Certificates + - type: bind + source: /var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD + target: /certificates + read_only: true + bind: + selinux: Z + + # Data Storage for NetAlertX + - type: bind # Persistent Docker-managed Named Volume for storage + source: /var/lib/containers/data/netalertx/server + target: /data # consolidated configuration and database storage + read_only: false # writable volume + bind: + selinux: Z + + # Set the Timezone + - type: bind # Bind mount for timezone consistency + source: /etc/localtime + target: /etc/localtime + read_only: true + bind: + selinux: Z + + # tmpfs mounts for writable directories in a read-only container and improve system performance + # All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts + # mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh + - type: tmpfs + target: /tmp + tmpfs-mode: 1700 + uid: 0 + gid: 0 + rw: true + noexec: true + nosuid: true + nodev: true + async: true + noatime: true + nodiratime: true + bind: + selinux: Z + + env_file: + - .env + - .env.server + + environment: + PUID: ${NETALERTX_UID:-20211} # Runtime UID after priming (Synology/no-copy-up safe) + PGID: ${NETALERTX_GID:-20211} # Runtime GID after priming (Synology/no-copy-up safe) + LISTEN_ADDR: ${LISTEN_ADDR:-0.0.0.0} # Listen for connections on all interfaces + PORT: ${PORT:-20211} # Application port + PORT_SSL: ${PORT_SSL:-443} + GRAPHQL_PORT: ${GRAPHQL_PORT:-20212} # GraphQL API port + ALWAYS_FRESH_INSTALL: ${ALWAYS_FRESH_INSTALL:-false} # Set to true to reset your config and database on each container start + NETALERTX_DEBUG: ${NETALERTX_DEBUG:-0} # 0=kill all services and restart if any dies. 1 keeps running dead services. + BACKEND_API_URL: ${BACKEND_API_URL-"https://netalertx.MYDOMAIN.TLD:20212"} + + # Resource limits to prevent resource exhaustion + mem_limit: 4096m # Maximum memory usage + mem_reservation: 2048m # Soft memory limit + cpu_shares: 512 # Relative CPU weight for CPU contention scenarios + pids_limit: 512 # Limit the number of processes/threads to prevent fork bombs + logging: + driver: "json-file" # Use JSON file logging driver + options: + max-size: "10m" # Rotate log files after they reach 10MB + max-file: "3" # Keep a maximum of 3 log files + + # Always restart the container unless explicitly stopped + restart: unless-stopped + + # To sign Out, you need to visit + # {$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT}/outpost.goauthentik.io/sign_out + netalertx-outpost-proxy: + container_name: netalertx-outpost-proxy + + network_mode: host + + depends_on: + netalertx-caddy: + condition: service_started + restart: true + + restart: unless-stopped + + image: ghcr.io/goauthentik/proxy:2025.10 + pull: missing + + env_file: + - .env + - .env.outpost.proxy + + environment: + AUTHENTIK_HOST: "https://authentik.MYDOMAIN.TLD" + AUTHENTIK_INSECURE: false + AUTHENTIK_LISTEN__HTTP: "[::1]:6000" + AUTHENTIK_LISTEN__HTTPS: "[::1]:6443" +``` + +### Quadlet Setup +`netalertx.pod`: +``` +[Pod] +# Name of the Pod +PodName=netalertx + +# Network Mode Host is required for ARP to work +Network=host + +# Automatically start Pod at Boot Time +[Install] +WantedBy=default.target +``` + +`netalertx-caddy.container`: +``` +[Unit] +Description=NetAlertX Caddy Container + +[Service] +Restart=always + +[Container] +ContainerName=netalertx-caddy + +Pod=netalertx.pod +StartWithPod=true + +# Generic Environment Configuration +EnvironmentFile=.env + +# Caddy Specific Environment Configuration +EnvironmentFile=.env.caddy + +Environment=CADDY_DOCKER_CADDYFILE_PATH=/etc/caddy/Caddyfile + +Image=docker.io/library/caddy:latest +Pull=missing + +# Run as rootless +# Specifying User & Group by Name requires to mount a custom passwd & group File inside the Container +# Otherwise an Error like the following will result: netalertx-caddy[593191]: Error: unable to find user caddy: no matching entries in passwd file +# User=caddy +# Group=caddy +# Volume=/var/lib/containers/config/netalertx/caddy-rootless/passwd:/etc/passwd:ro,z +# Volume=/var/lib/containers/config/netalertx/caddy-rootless/group:/etc/group:ro,z + +# Run as rootless +# Specifying User & Group by UID/GID will NOT require a custom passwd / group File to be bind-mounted inside the Container +User=980 +Group=980 + +Volume=./Caddyfile:/etc/caddy/Caddyfile:ro,z +Volume=/var/lib/containers/data/netalertx/caddy:/data/caddy:z +Volume=/var/lib/containers/log/netalertx/caddy:/var/log:z +Volume=/var/lib/containers/config/netalertx/caddy:/config/caddy:z +Volume=/var/lib/containers/certificates/letsencrypt:/certificates:ro,z +``` + +`netalertx-server.container`: +``` +[Unit] +Description=NetAlertX Server Container +Requires=netalertx-caddy.service netalertx-outpost-proxy.service +After=netalertx-caddy.service netalertx-outpost-proxy.service + +[Service] +Restart=always + +[Container] +ContainerName=netalertx-server + +Pod=netalertx.pod +StartWithPod=true + +# Local built Image including latest Changes +Image=localhost/netalertx-dev:dev-20260109-232454 +Pull=missing + +# Make the container filesystem read-only +ReadOnly=true + +# Drop all capabilities for enhanced security +DropCapability=ALL + +# It is most secure to start with user 20211, but then we lose provisioning capabilities. +# User=20211:20211 + +# Required for scanning with arp-scan, nmap, nbtscan, traceroute, and zero-conf +AddCapability=NET_ADMIN + +# Required for raw socket operations with arp-scan, nmap, nbtscan, traceroute and zero-conf +AddCapability=NET_RAW + +# Required to bind to privileged ports with nbtscan +AddCapability=NET_BIND_SERVICE + +# Required for root-entrypoint to chown /data + /tmp before dropping privileges +AddCapability=CHOWN + +# Required for root-entrypoint to switch to non-root user +AddCapability=SETUID + +# Required for root-entrypoint to switch to non-root group +AddCapability=SETGID + +# Override the Configuration Template +Volume=/var/lib/containers/config/netalertx/server/nginx/netalertx.conf.template:/services/config/nginx/netalertx.conf.template:ro,Z + +# Letsencrypt Certificates +Volume=/var/lib/containers/certificates/letsencrypt/MYDOMAIN.TLD:/certificates:ro,Z + +# Data Storage for NetAlertX +Volume=/var/lib/containers/data/netalertx/server:/data:rw,Z + +# Set the Timezone +Volume=/etc/localtime:/etc/localtime:ro,Z + +# tmpfs mounts for writable directories in a read-only container and improve system performance +# All writes now live under /tmp/* subdirectories which are created dynamically by entrypoint.d scripts +# mode=1700 gives rwx------ permissions; ownership is set by /root-entrypoint.sh +# Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,uid=0,gid=0,rw=true,noexec=true,nosuid=true,nodev=true,async=true,noatime=true,nodiratime=true,relabel=private +Mount=type=tmpfs,destination=/tmp,tmpfs-mode=1700,rw=true,noexec=true,nosuid=true,nodev=true + +# Environment Configuration +EnvironmentFile=.env +EnvironmentFile=.env.server + +# Runtime UID after priming (Synology/no-copy-up safe) +Environment=PUID=20211 + +# Runtime GID after priming (Synology/no-copy-up safe) +Environment=PGID=20211 + +# Listen for connections on all interfaces (IPv4) +Environment=LISTEN_ADDR=0.0.0.0 + +# Application port +Environment=PORT=20211 + +# SSL Port +Environment=PORT_SSL=443 + +# GraphQL API port +Environment=GRAPHQL_PORT=20212 + +# Set to true to reset your config and database on each container start +Environment=ALWAYS_FRESH_INSTALL=false + +# 0=kill all services and restart if any dies. 1 keeps running dead services. +Environment=NETALERTX_DEBUG=0 + +# Set the GraphQL URL for external Access (via Caddy Reverse Proxy) +Environment=BACKEND_API_URL=https://netalertx-fedora.MYDOMAIN.TLD:20212 + +# Resource limits to prevent resource exhaustion +# Maximum memory usage +Memory=4g + +# Limit the number of processes/threads to prevent fork bombs +PidsLimit=512 + +# Relative CPU weight for CPU contention scenarios +PodmanArgs=--cpus=2 +PodmanArgs=--cpu-shares=512 + +# Soft memory limit +PodmanArgs=--memory-reservation=2g + +# !! The following Keys are unfortunately not [yet] supported !! + +# Relative CPU weight for CPU contention scenarios +#CpuShares=512 + +# Soft memory limit +#MemoryReservation=2g +``` + +`netalertx-outpost-proxy.container`: +``` +[Unit] +Description=NetAlertX Authentik Proxy Outpost Container +Requires=netalertx-caddy.service +After=netalertx-caddy.service + +[Service] +Restart=always + +[Container] +ContainerName=netalertx-outpost-proxy + +Pod=netalertx.pod +StartWithPod=true + +# General Configuration +EnvironmentFile=.env + +# Authentik Outpost Proxy Specific Configuration +EnvironmentFile=.env.outpost.proxy + +Environment=AUTHENTIK_HOST=https://authentik.MYDOMAIN.TLD +Environment=AUTHENTIK_INSECURE=false + +# Overrides Value from .env.outpost.rac +# Environment=AUTHENTIK_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +# Optional setting to be used when `authentik_host` for internal communication doesn't match the public URL +# Environment=AUTHENTIK_HOST_BROWSER=https://authentik.MYDOMAIN.TLD + +# Container Image +Image=ghcr.io/goauthentik/proxy:2025.10 +Pull=missing + +# Network Configuration +Network=container:supermicro-ikvm-pve031-caddy + +# Security Configuration +NoNewPrivileges=true +``` + +### Firewall Setup + +Depending on which GNU/Linux Distribution you are running, it might be required to open up some Firewall Ports in order to be able to access the Endpoints from outside the Host itself. + +This is for instance the Case for Fedora Linux, where I had to open: + +- Port 20212 for external GraphQL Access (both TCP & UDP are open, unsure if UDP is required) +- Port 9443 for external Authentik Outpost Proxy Access (both TCP & UDP are open, unsure if UDP is required) + +![Fedora Firewall Configuration](./img/REVERSE_PROXY/fedora-firewall.png) + +### Authentik Setup + +In order to enable Single Sign On (SSO) with Authentik, you will need to create a Provider, an Application and an Outpost. + +![Authentik Left Sidebar](./img/REVERSE_PROXY/authentik-sidebar.png) + +First of all, using the Left Sidebar, navigate to `Applications` → `Providers`, click on `Create` (Blue Button at the Top of the Screen), select `Proxy Provider`, then click `Next`: +![Authentik Provider Setup (Part 1)](./img/REVERSE_PROXY/authentik-provider-setup-01.png) + +Fill in the required Fields: + +- Name: choose a Name for the Provider (e.g. `netalertx`) +- Authorization Flow: choose the Authorization Flow. I typically use `default-provider-authorization-implicit-consent (Authorize Application)`. If you select the `default-provider-authorization-explicit-consent (Authorize Application)` you will need to authorize Authentik every Time you want to log in NetAlertX, which can make the Experience less User-friendly +- Type: Click on `Forward Auth (single application)` +- External Host: set to `https://netalertx.MYDOMAIN.TLD` + +Click `Finish`. + +![Authentik Provider Setup (Part 2)](./img/REVERSE_PROXY/authentik-provider-setup-02.png) + +Now, using the Left Sidebar, navigate to `Applications` → `Applications`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields: + +- Name: choose a Name for the Application (e.g. `netalertx`) +- Slug: choose a Slug for the Application (e.g. `netalertx`) +- Group: optionally you can assign this Application to a Group of Applications of your Choosing (for grouping Purposes within Authentik User Interface) +- Provider: select the Provider you created the the `Providers` Section previosly (e.g. `netalertx`) + +Then click `Create`. + +![Authentik Application Setup (Part 1)](./img/REVERSE_PROXY/authentik-application-setup-01.png) + +Now, using the Left Sidebar, navigate to `Applications` → `Outposts`, click on `Create` (Blue Button at the Top of the Screen) and fill in the required Fields: + +- Name: choose a Name for the Outpost (e.g. `netalertx`) +- Type: `Proxy` +- Integration: open the Dropdown and click on `---------`. Make sure it is NOT set to `Local Docker connection` ! + +In the `Available Applications` Section, select the Application you created in the Previous Step, then click the right Arrow (approx. located in the Center of the Screen), so that it gets copied in the `Selected Applications` Section. + +Then click `Create`. + +![Authentik Outpost Setup (Part 1)](./img/REVERSE_PROXY/authentik-outpost-setup-01.png) + +Wait a few Seconds for the Outpost to be created. Once it appears in the List, click on `Deployment Info` on the Right Side of the relevant Line. + +![Authentik Outpost Setup (Part 2)](./img/REVERSE_PROXY/authentik-outpost-setup-02.png) + +Take note of that Token. You will need it for the Authentik Outpost Proxy Container, which will read it as the `AUTHENTIK_TOKEN` Environment Variable. + +### NGINX Configuration inside NetAlertX Container +> [!NOTE] +> This is something that was implemented based on the previous Content of this Reverse Proxy Document. +> Due to some Buffer Warnings/Errors in the Logs as well as some other Issues I was experiencing, I increased a lot the client_body_buffer_size and large_client_header_buffers Parameters, although these might not be required anymore. +> Further Testing might be required. + +``` +# Set number of worker processes automatically based on number of CPU cores. +worker_processes auto; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +# Configures default error logger. +error_log /tmp/log/nginx-error.log warn; + +pid /tmp/run/nginx.pid; + +events { + # The maximum number of simultaneous connections that can be opened by + # a worker process. + worker_connections 1024; +} + +http { + + # Mapping of temp paths for various nginx modules. + client_body_temp_path /tmp/nginx/client_body; + proxy_temp_path /tmp/nginx/proxy; + fastcgi_temp_path /tmp/nginx/fastcgi; + uwsgi_temp_path /tmp/nginx/uwsgi; + scgi_temp_path /tmp/nginx/scgi; + + # Includes mapping of file name extensions to MIME types of responses + # and defines the default type. + include /services/config/nginx/mime.types; + default_type application/octet-stream; + + # Name servers used to resolve names of upstream servers into addresses. + # It's also needed when using tcpsocket and udpsocket in Lua modules. + #resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001]; + + # Don't tell nginx version to the clients. Default is 'on'. + server_tokens off; + + # Specifies the maximum accepted body size of a client request, as + # indicated by the request header Content-Length. If the stated content + # length is greater than this size, then the client receives the HTTP + # error code 413. Set to 0 to disable. Default is '1m'. + client_max_body_size 1m; + + # Sendfile copies data between one FD and other from within the kernel, + # which is more efficient than read() + write(). Default is off. + sendfile on; + + # Causes nginx to attempt to send its HTTP response head in one packet, + # instead of using partial frames. Default is 'off'. + tcp_nopush on; + + + # Enables the specified protocols. Default is TLSv1 TLSv1.1 TLSv1.2. + # TIP: If you're not obligated to support ancient clients, remove TLSv1.1. + ssl_protocols TLSv1.2 TLSv1.3; + + # Path of the file with Diffie-Hellman parameters for EDH ciphers. + # TIP: Generate with: `openssl dhparam -out /etc/ssl/nginx/dh2048.pem 2048` + #ssl_dhparam /etc/ssl/nginx/dh2048.pem; + + # Specifies that our cipher suits should be preferred over client ciphers. + # Default is 'off'. + ssl_prefer_server_ciphers on; + + # Enables a shared SSL cache with size that can hold around 8000 sessions. + # Default is 'none'. + ssl_session_cache shared:SSL:2m; + + # Specifies a time during which a client may reuse the session parameters. + # Default is '5m'. + ssl_session_timeout 1h; + + # Disable TLS session tickets (they are insecure). Default is 'on'. + ssl_session_tickets off; + + + # Enable gzipping of responses. + gzip on; + + # Set the Vary HTTP header as defined in the RFC 2616. Default is 'off'. + gzip_vary on; + + + # Specifies the main log format. + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + # Sets the path, format, and configuration for a buffered log write. + access_log /tmp/log/nginx-access.log main; + + + # Virtual host config (unencrypted) + server { + listen ${LISTEN_ADDR}:${PORT} default_server; + root /app/front; + index index.php; + add_header X-Forwarded-Prefix "/app" always; + + server_name netalertx-server; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + client_body_buffer_size 512k; + large_client_header_buffers 64 128k; + + location ~* \.php$ { + # Set Cache-Control header to prevent caching on the first load + add_header Cache-Control "no-store"; + fastcgi_pass unix:/tmp/run/php.sock; + include /services/config/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_connect_timeout 75; + fastcgi_send_timeout 600; + fastcgi_read_timeout 600; + } + } +} +``` + +### Caddyfile +``` +# Example and Guide +# https://caddyserver.com/docs/caddyfile/options + +# General Options +{ + # (Optional) Debug Mode + # debug + + # (Optional ) Enable / Disable Admin API + admin off + + # TLS Options + # (Optional) Disable Certificates Management (only if SSL/TLS Certificates are managed by certbot or other external Tools) + auto_https disable_certs +} + +# (Optional Enable Admin API) +# localhost { +# reverse_proxy /api/* localhost:9001 +# } + +# NetAlertX Web GUI (HTTPS Port 443) +# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required +{$APPLICATION_HOSTNAME}:443 { + tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} + + log { + output file /var/log/{$APPLICATION_HOSTNAME}/access_web.json { + roll_size 100MiB + roll_keep 5000 + roll_keep_for 720h + roll_uncompressed + } + + format json + } + + route { + # Always forward outpost path to actual outpost + reverse_proxy /outpost.goauthentik.io/* https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { + header_up Host {http.reverse_proxy.upstream.hostport} + } + + # Forward authentication to outpost + forward_auth https://{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { + uri /outpost.goauthentik.io/auth/caddy + + # Capitalization of the headers is important, otherwise they will be empty + copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version + + # (Optional) + # If not set, trust all private ranges, but for Security Reasons, this should be set to the outposts IP + trusted_proxies private_ranges + } + } + + # IPv4 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host) + reverse_proxy http://0.0.0.0:20211 + + # IPv6 Reverse Proxy to NetAlertX Web GUI (internal unencrypted Host) + # reverse_proxy http://[::1]:20211 +} + +# NetAlertX GraphQL Endpoint (HTTPS Port 20212) +# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required +{$APPLICATION_HOSTNAME}:20212 { + tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} + + log { + output file /var/log/{$APPLICATION_HOSTNAME}/access_graphql.json { + roll_size 100MiB + roll_keep 5000 + roll_keep_for 720h + roll_uncompressed + } + + format json + } + + # IPv4 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host) + reverse_proxy http://0.0.0.0:20219 + + # IPv6 Reverse Proxy to NetAlertX GraphQL Endpoint (internal unencrypted Host) + # reverse_proxy http://[::1]:6000 +} + +# Authentik Outpost +# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required +{$OUTPOST_HOSTNAME}:{$OUTPOST_EXTERNAL_PORT} { + tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem} + + log { + output file /var/log/outpost/{$OUTPOST_HOSTNAME}/access.json { + roll_size 100MiB + roll_keep 5000 + roll_keep_for 720h + roll_uncompressed + } + + format json + } + + # IPv4 Reverse Proxy to internal unencrypted Host + # reverse_proxy http://0.0.0.0:6000 + + # IPv6 Reverse Proxy to internal unencrypted Host + reverse_proxy http://[::1]:6000 +} +``` + +### Login +Now try to login by visiting `https://netalertx.MYDOMAIN.TLD`. + +You should be greeted with a Login Screen by Authentik. + +If you are already logged in Authentik, log out first. You can do that by visiting `https://netalertx.MYDOMAIN.TLD/outpost.goauthentik.io/sign_out`, then click on `Log out of authentik` (2nd Button). Or you can just sign out from your Authentik Admin Panel at `https://authentik.MYDOMAIN.TLD`. + +If everything works as expected, then you can now set `SETPWD_enable_password=false` to disable double Authentication. + +![Authentik Login Screen](./img/REVERSE_PROXY/authentik-login.png) \ No newline at end of file diff --git a/docs/REVERSE_PROXY_TRAEFIK.md b/docs/REVERSE_PROXY_TRAEFIK.md new file mode 100644 index 00000000..8766cfc6 --- /dev/null +++ b/docs/REVERSE_PROXY_TRAEFIK.md @@ -0,0 +1,86 @@ +# Guide: Routing NetAlertX API via Traefik v3 + +> [!NOTE] +> NetAlertX requires access to both the **web UI** (default `20211`) and the **GraphQL backend `GRAPHQL_PORT`** (default `20212`) ports. +> Ensure your reverse proxy allows traffic to both for proper functionality. + + +> [!NOTE] +> This is community-contributed. Due to environment, setup, or networking differences, results may vary. Please open a PR to improve it instead of creating an issue, as the maintainer is not actively maintaining it. + + +Traefik v3 requires the following setup to route traffic properly. This guide shows a working configuration using a dedicated `PathPrefix`. + +--- + +## 1. Configure NetAlertX Backend URL + +1. Open the NetAlertX UI: **Settings → Core → General**. +2. Set the `BACKEND_API_URL` to include a custom path prefix, for example: + +``` +https://netalertx.yourdomain.com/netalertx-api +``` + +This tells the frontend where to reach the backend API. + +--- + +## 2. Create a Traefik Router for the API + +Define a router specifically for the API with a higher priority and a `PathPrefix` rule: + +```yaml +netalertx-api: + rule: "Host(`netalertx.yourdomain.com`) && PathPrefix(`/netalertx-api`)" + service: netalertx-api-service + middlewares: + - netalertx-stripprefix + priority: 100 +``` + +**Notes:** + +* `Host(...)` ensures requests are only routed for your domain. +* `PathPrefix(...)` routes anything under `/netalertx-api` to the backend. +* Priority `100` ensures this router takes precedence over other routes. + +--- + +## 3. Add a Middleware to Strip the Prefix + +NetAlertX expects requests at the root (`/`). Use Traefik’s `StripPrefix` middleware: + +```yaml +middlewares: + netalertx-stripprefix: + stripPrefix: + prefixes: + - "/netalertx-api" +``` + +This removes `/netalertx-api` before forwarding the request to the backend container. + +--- + +## 4. Map the API Service to the Backend Container + +Point the service to the internal GraphQL/Backend port (20212): + +```yaml +netalertx-api-service: + loadBalancer: + servers: + - url: "http://:20212" +``` + +Replace `` with your NetAlertX container’s internal address. + +--- + +âś… With this setup: + +* `https://netalertx.yourdomain.com` → Web interface (port 20211) +* `https://netalertx.yourdomain.com/netalertx-api` → API/GraphQL backend (port 20212) + +This cleanly separates API requests from frontend requests while keeping everything under the same domain. diff --git a/mkdocs.yml b/mkdocs.yml index 6e964b88..62ef64e0 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -57,7 +57,10 @@ nav: - Authelia: AUTHELIA.md - Performance: PERFORMANCE.md - Reverse DNS: REVERSE_DNS.md - - Reverse Proxy: REVERSE_PROXY.md + - Reverse Proxy: + - Reverse Proxy Overview: REVERSE_PROXY.md + - Caddy and Authentik: REVERSE_PROXY_CADDY.md + - Traefik: REVERSE_PROXY_TRAEFIK.md - Webhooks (n8n): WEBHOOK_N8N.md - Workflows: WORKFLOWS.md - Workflow Examples: WORKFLOW_EXAMPLES.md