mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-03-31 07:12:23 -07:00
@@ -3,6 +3,9 @@
|
|||||||
> [!NOTE]
|
> [!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.
|
> 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]
|
> [!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.
|
> 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 @@
|
|||||||
>
|
>
|
||||||
> 
|
> 
|
||||||
|
|
||||||
|
See also:
|
||||||
|
|
||||||
|
- [CADDY + AUTHENTIK](./REVERSE_PROXY_CADDY.md)
|
||||||
|
- [TRAEFIK](./REVERSE_PROXY_TRAEFIK.md)
|
||||||
|
|
||||||
|
|
||||||
## NGINX HTTP Configuration (Direct Path)
|
## NGINX HTTP Configuration (Direct Path)
|
||||||
|
|
||||||
> Submitted by amazing [cvc90](https://github.com/cvc90) 🙏
|
> 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:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 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.<application>` 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)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Authentik Setup
|
|
||||||
|
|
||||||
In order to enable Single Sign On (SSO) with Authentik, you will need to create a Provider, an Application and an Outpost.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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`:
|
|
||||||

|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
892
docs/REVERSE_PROXY_CADDY.md
Normal file
892
docs/REVERSE_PROXY_CADDY.md
Normal file
@@ -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:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 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.<application>` 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)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Authentik Setup
|
||||||
|
|
||||||
|
In order to enable Single Sign On (SSO) with Authentik, you will need to create a Provider, an Application and an Outpost.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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`:
|
||||||
|

|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
86
docs/REVERSE_PROXY_TRAEFIK.md
Normal file
86
docs/REVERSE_PROXY_TRAEFIK.md
Normal file
@@ -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://<INTERNAL_IP>:20212"
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `<INTERNAL_IP>` 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.
|
||||||
@@ -57,7 +57,10 @@ nav:
|
|||||||
- Authelia: AUTHELIA.md
|
- Authelia: AUTHELIA.md
|
||||||
- Performance: PERFORMANCE.md
|
- Performance: PERFORMANCE.md
|
||||||
- Reverse DNS: REVERSE_DNS.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
|
- Webhooks (n8n): WEBHOOK_N8N.md
|
||||||
- Workflows: WORKFLOWS.md
|
- Workflows: WORKFLOWS.md
|
||||||
- Workflow Examples: WORKFLOW_EXAMPLES.md
|
- Workflow Examples: WORKFLOW_EXAMPLES.md
|
||||||
|
|||||||
Reference in New Issue
Block a user