From 526d66b88f5bb5d307a22dd972108507b8866217 Mon Sep 17 00:00:00 2001 From: ToledoEM <8144940+ToledoEM@users.noreply.github.com> Date: Fri, 1 May 2026 11:52:03 +0100 Subject: [PATCH] NGINX webserver and Proxy Manager --- nginx_webserver_proxy/CHANGELOG.md | 10 ++ nginx_webserver_proxy/Dockerfile | 23 ++++ nginx_webserver_proxy/README.md | 81 ++++++++++++++ nginx_webserver_proxy/apparmor.txt | 104 ++++++++++++++++++ nginx_webserver_proxy/build.yaml | 4 + nginx_webserver_proxy/config.yaml | 40 +++++++ nginx_webserver_proxy/icon.png | Bin 0 -> 9298 bytes nginx_webserver_proxy/logo.png | Bin 0 -> 9298 bytes nginx_webserver_proxy/run.sh | 118 +++++++++++++++++++++ nginx_webserver_proxy/translations/en.yaml | 25 +++++ 10 files changed, 405 insertions(+) create mode 100644 nginx_webserver_proxy/CHANGELOG.md create mode 100644 nginx_webserver_proxy/Dockerfile create mode 100644 nginx_webserver_proxy/README.md create mode 100644 nginx_webserver_proxy/apparmor.txt create mode 100644 nginx_webserver_proxy/build.yaml create mode 100644 nginx_webserver_proxy/config.yaml create mode 100644 nginx_webserver_proxy/icon.png create mode 100644 nginx_webserver_proxy/logo.png create mode 100755 nginx_webserver_proxy/run.sh create mode 100644 nginx_webserver_proxy/translations/en.yaml diff --git a/nginx_webserver_proxy/CHANGELOG.md b/nginx_webserver_proxy/CHANGELOG.md new file mode 100644 index 0000000000..44059dca3d --- /dev/null +++ b/nginx_webserver_proxy/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 2.14.0 + +- Initial release wrapping jc21/nginx-proxy-manager:latest +- NPM Admin UI on port 81; HTTP on port 80; HTTPS on port 443 +- Configurable static file server via NPM's default_host nginx config +- Supports /share, /media, /config paths; warns for /mnt; blocks dangerous system paths +- NPM state persisted via Docker volume (managed by HA Supervisor) +- Supports amd64 and aarch64 diff --git a/nginx_webserver_proxy/Dockerfile b/nginx_webserver_proxy/Dockerfile new file mode 100644 index 0000000000..e7833cec95 --- /dev/null +++ b/nginx_webserver_proxy/Dockerfile @@ -0,0 +1,23 @@ +ARG BUILD_FROM=jc21/nginx-proxy-manager:latest +FROM ${BUILD_FROM} + +# NPM is Debian-based; install jq for options parsing + stub with-contenv if absent +# hadolint ignore=DL3008 +RUN apt-get update \ + && apt-get install -y --no-install-recommends jq \ + && rm -rf /var/lib/apt/lists/* \ + && if ! command -v with-contenv >/dev/null 2>&1; then \ + printf '#!/usr/bin/env bash\nexec "$@"\n' > /usr/bin/with-contenv \ + && chmod +x /usr/bin/with-contenv; \ + fi + +COPY run.sh /npm-addon-init.sh +RUN chmod +x /npm-addon-init.sh + +ARG BUILD_VERSION +LABEL \ + io.hass.version="${BUILD_VERSION}" \ + io.hass.type="addon" \ + io.hass.arch="aarch64|amd64" + +ENTRYPOINT ["/npm-addon-init.sh"] diff --git a/nginx_webserver_proxy/README.md b/nginx_webserver_proxy/README.md new file mode 100644 index 0000000000..1c479a23c2 --- /dev/null +++ b/nginx_webserver_proxy/README.md @@ -0,0 +1,81 @@ +# Nginx Proxy Manager + Static Web Server + +[Nginx Proxy Manager](https://nginxproxymanager.com/) with a configurable static file server for Home Assistant. Manage reverse proxies and SSL certificates via the web UI (port 81) while serving static files from your HA storage (port 80). + +## Why This Add-on? + +Home Assistant's built-in folder server has limitations: +- Can only serve from a single folder at a time +- No reverse proxy capabilities +- No SSL/HTTPS support +- Limited HTTP headers and caching control +- No support for URL rewriting or advanced routing + +This add-on combines a full reverse proxy with a proper static file server, allowing you to host multiple sites, manage SSL certificates, and proxy traffic to other services from a single interface. + +[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons) + +## Features + +- Reverse proxy manager (web UI on port 81) +- Static file server (port 80) +- HTTPS support (port 443) +- Persistent configuration and SSL certificates +- Works on amd64 and aarch64 + +## Installation + +1. Add this repository to Home Assistant via Settings → Add-ons → Add-on Store → ⋮ → Manage repositories (or use the button above). +2. Install Nginx Proxy Manager + Static Web Server. +3. Configure options (defaults work for first run). +4. Start the add-on. +5. Open `http://:81` to access the admin UI. + +## Configuration + +| Option | Default | Description | +|--------|---------|-------------| +| `static_site_enabled` | `true` | Enable or disable the static file server on port 80 | +| `static_site_root` | `/share/www` | Path to serve static files from | +| `static_site_prefix` | `/` | URL prefix for the static site (e.g., `/www` for `http://host/www`) | +| `log_level` | `info` | Logging verbosity: `info`, `debug`, `warn`, or `error` | + +## Default Credentials + +First login (port 81): +- Email: `admin@example.com` +- Password: `changeme` + +Change these on first login. + +## Path Validation + +Paths are validated at startup for safe access: + +- `/share`, `/media`, `/config` – fully supported (HA maps these automatically) +- `/mnt` – allowed but not mapped by HA. Create a symlink under `/share` or `/media` if files are inaccessible. +- `/`, `/etc`, `/bin`, `/lib`, `/proc`, `/sys` – blocked (will prevent startup) + +## Examples + +**Reverse proxy:** +1. Open the admin UI at `http://:81` +2. Add a proxy host pointing to another service +3. Configure SSL via Let's Encrypt (optional) + +**Static website:** +1. Place files in `/share/www` (or your configured `static_site_root`) +2. Access at `http://:80/` (or your configured `static_site_prefix`) + +You can run both simultaneously on the same ports. + +## Notes + +- Wraps `jc21/nginx-proxy-manager` upstream image +- State persists in `/data` (managed by HA Supervisor) +- Custom AppArmor profile restricts system access +- Edit NPM's database directly via SSH if needed + +## Issues + +For problems with this add-on (not the upstream NPM software), open an issue and tag @ToledoEM. diff --git a/nginx_webserver_proxy/apparmor.txt b/nginx_webserver_proxy/apparmor.txt new file mode 100644 index 0000000000..7633db0c1b --- /dev/null +++ b/nginx_webserver_proxy/apparmor.txt @@ -0,0 +1,104 @@ +#include + +profile nginx-proxy-manager flags=(attach_disconnected,mediate_deleted) { + #include + #include + #include + + # Core capabilities + capability chown, + capability dac_override, + capability net_bind_service, + capability setfcap, + capability setgid, + capability setuid, + capability sys_chroot, + capability kill, + + # Process and memory management + capability sys_resource, + + # Deny dangerous capabilities + deny capability dac_read_search, + deny capability linux_immutable, + deny capability mac_admin, + deny capability mac_override, + deny capability sys_admin, + deny capability sys_boot, + deny capability sys_module, + deny capability sys_rawio, + deny capability syslog, + + # Network + network inet stream, + network inet dgram, + network inet6 stream, + network inet6 dgram, + network unix stream, + network unix dgram, + + # /data - addon config (read/write) + /data/ r, + /data/** rwk, + + # /share - Home Assistant storage (read/write) + /share/ r, + /share/** rwk, + + # /media - Home Assistant media (read/write) + /media/ r, + /media/** rwk, + + # /config - Home Assistant config (read/write) + /config/ r, + /config/** rwk, + + # /addon_configs - addon instance config + /addon_configs/ r, + /addon_configs/** rwk, + + # /etc/letsencrypt - SSL certs + /etc/letsencrypt/ r, + /etc/letsencrypt/** rwk, + + # /proc and /sys + @{PROC}/ r, + @{PROC}/** rw, + @{sys}/ r, + @{sys}/** rw, + + # Temporary files + /tmp/ r, + /tmp/** rwk, + /var/tmp/ r, + /var/tmp/** rwk, + + # Basic system access + /bin/bash ix, + /bin/sh ix, + /bin/ls ix, + /bin/cat ix, + /bin/sed ix, + /usr/bin/jq ix, + + # Nginx binary and libraries + /usr/sbin/nginx ix, + /usr/local/sbin/nginx ix, + /usr/lib/** rm, + /lib/** rm, + /usr/local/lib/** rm, + + # Allow reading app-specific configs (read-only) + /etc/nginx/ r, + /etc/nginx/** r, + /var/log/ r, + /var/log/** w, + + # Deny sensitive system areas + deny /root/** rwkl, + deny /home/** rwkl, + deny /proc/sysrq-trigger rwkl, + deny /sys/firmware/** rwkl, + deny /sys/kernel/security/** rwkl, + deny /sys/kernel/debug/** rwkl, +} diff --git a/nginx_webserver_proxy/build.yaml b/nginx_webserver_proxy/build.yaml new file mode 100644 index 0000000000..001eebf302 --- /dev/null +++ b/nginx_webserver_proxy/build.yaml @@ -0,0 +1,4 @@ +--- +build_from: + aarch64: jc21/nginx-proxy-manager:latest + amd64: jc21/nginx-proxy-manager:latest diff --git a/nginx_webserver_proxy/config.yaml b/nginx_webserver_proxy/config.yaml new file mode 100644 index 0000000000..33d1495c2c --- /dev/null +++ b/nginx_webserver_proxy/config.yaml @@ -0,0 +1,40 @@ +name: "Nginx Proxy Manager + Static Web Server" +slug: nginx_webserver_proxy +description: "Nginx Proxy Manager with a built-in configurable static file server. Manage reverse proxies via NPM UI on port 81 while serving files from HA storage on port 80." +version: "2.14.0" +url: "https://github.com/alexbelgium/hassio-addons/tree/master/nginx_webserver_proxy" +arch: + - amd64 + - aarch64 +startup: services +init: false + +ports: + 80/tcp: 80 + 81/tcp: 81 + 443/tcp: 443 +ports_description: + 80/tcp: "HTTP (static site + NPM proxy hosts)" + 81/tcp: "NPM Admin Web UI" + 443/tcp: "HTTPS (NPM proxy hosts)" + +webui: "http://[HOST]:[PORT:81]" + +map: + - addon_config:rw + - share:rw + - media:rw + +options: + static_site_enabled: true + static_site_root: "/share/www" + static_site_prefix: "/" + log_level: "info" + +schema: + static_site_enabled: bool + static_site_root: str + static_site_prefix: str + log_level: list(info|debug|warn|error) + +image: "ghcr.io/alexbelgium/nginx_webserver_proxy-{arch}" diff --git a/nginx_webserver_proxy/icon.png b/nginx_webserver_proxy/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7db87bfb185a66964e1557d2132b9212be3de4cd GIT binary patch literal 9298 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 HMd<$n@$>;z literal 0 HcmV?d00001 diff --git a/nginx_webserver_proxy/logo.png b/nginx_webserver_proxy/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7db87bfb185a66964e1557d2132b9212be3de4cd GIT binary patch literal 9298 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 HMd<$n@$>;z literal 0 HcmV?d00001 diff --git a/nginx_webserver_proxy/run.sh b/nginx_webserver_proxy/run.sh new file mode 100755 index 0000000000..3742218214 --- /dev/null +++ b/nginx_webserver_proxy/run.sh @@ -0,0 +1,118 @@ +#!/usr/bin/with-contenv bash +# shellcheck shell=bash +set -Eeuo pipefail + +# HA Supervisor places options.json at /data/options.json. +# NPM also uses /data for its database and generated configs. +# The /data Docker VOLUME is persisted automatically by HA Supervisor between restarts. +OPTIONS_JSON="/data/options.json" + +log() { echo "[nginx-proxy-manager-addon] $*"; } +warn() { echo "[nginx-proxy-manager-addon] WARN: $*" >&2; } +die() { + echo "[nginx-proxy-manager-addon] ERROR: $*" >&2 + exit 1 +} + +read_opt() { + jq -er --arg k "$1" '.[$k]' "$OPTIONS_JSON" 2> /dev/null || true +} + +# --------------------------------------------------------------------------- +# Step 1: Read add-on options +# --------------------------------------------------------------------------- +[[ -f "$OPTIONS_JSON" ]] || die "Missing options file at ${OPTIONS_JSON}" + +STATIC_ENABLED="$(read_opt static_site_enabled)" +STATIC_ENABLED="${STATIC_ENABLED:-true}" +STATIC_ROOT_RAW="$(read_opt static_site_root)" +STATIC_ROOT_RAW="${STATIC_ROOT_RAW:-/share/www}" +STATIC_PREFIX="$(read_opt static_site_prefix)" +STATIC_PREFIX="${STATIC_PREFIX:-/}" +LOG_LEVEL="$(read_opt log_level)" +LOG_LEVEL="${LOG_LEVEL:-info}" + +# --------------------------------------------------------------------------- +# Step 2: Validate static_site_root +# --------------------------------------------------------------------------- +normalize_path() { + if command -v realpath > /dev/null 2>&1; then + realpath -m -- "$1" + else + local p="${1%/}" + [[ "$p" == /* ]] || p="/$p" + printf '%s\n' "$p" + fi +} + +STATIC_ROOT="$(normalize_path "$STATIC_ROOT_RAW")" + +case "$STATIC_ROOT" in + / | /etc | /etc/* | /bin | /bin/* | /sbin | /sbin/* | /lib | /lib/* | /proc | /proc/* | /sys | /sys/*) + die "static_site_root '${STATIC_ROOT}' is a dangerous system path. Use /share, /media, /config, or /mnt." + ;; +esac + +case "$STATIC_ROOT" in + /share | /share/* | /media | /media/* | /config | /config/*) + log "static_site_root: ${STATIC_ROOT}" + ;; + /mnt | /mnt/*) + warn "static_site_root '${STATIC_ROOT}' is under /mnt — HA cannot map /mnt." + warn "If files are inaccessible, create a symlink under /share or /media pointing to your /mnt path." + ;; + *) + warn "static_site_root '${STATIC_ROOT}' is outside standard HA-mapped paths — may not be accessible." + ;; +esac + +[[ "$STATIC_PREFIX" == /* ]] || die "static_site_prefix must start with '/'. Got: '${STATIC_PREFIX}'" + +# --------------------------------------------------------------------------- +# Step 3: Write static-site server block into NPM's default_host dir +# NPM includes /data/nginx/default_host/*.conf for the port 80 default server. +# Writing here replaces NPM's "Congratulations" page with our static file server. +# --------------------------------------------------------------------------- +DEFAULT_HOST_DIR="/data/nginx/default_host" +mkdir -p "$DEFAULT_HOST_DIR" +STATIC_CONF="${DEFAULT_HOST_DIR}/static_site.conf" + +if [[ "$STATIC_ENABLED" == "true" ]]; then + mkdir -p "$STATIC_ROOT" 2> /dev/null \ + || warn "Could not create '${STATIC_ROOT}' (may not be mounted yet)" + + cat > "$STATIC_CONF" << NGINX_EOF +# Managed by nginx_webserver_proxy add-on — regenerated on every container start. +# Edit options in the HA add-on configuration UI, not here. +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + location ${STATIC_PREFIX} { + alias ${STATIC_ROOT}/; + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + try_files \$uri \$uri/ =404; + access_log /proc/1/fd/1; + error_log /proc/1/fd/1 warn; + } +} +NGINX_EOF + log "Static site config written → ${STATIC_CONF}" +else + printf '# Static site disabled by add-on options\n' > "$STATIC_CONF" + log "Static site disabled" +fi + +# --------------------------------------------------------------------------- +# Step 4: Hand off to NPM's own s6-overlay boot +# --------------------------------------------------------------------------- +log "static_site_root=${STATIC_ROOT} prefix=${STATIC_PREFIX} log_level=${LOG_LEVEL}" +# NPM's prepare service requires /etc/letsencrypt to exist. +# HA Supervisor maps the ssl volume there automatically; for other environments create it. +mkdir -p /etc/letsencrypt + +log "Handing off to NPM: exec /init" +exec /init diff --git a/nginx_webserver_proxy/translations/en.yaml b/nginx_webserver_proxy/translations/en.yaml new file mode 100644 index 0000000000..04da0af551 --- /dev/null +++ b/nginx_webserver_proxy/translations/en.yaml @@ -0,0 +1,25 @@ +configuration: + static_site_enabled: + name: Enable static file server + description: Serve files from static_site_root on port 80. NPM proxy functionality is always active regardless of this setting. + static_site_root: + name: Static site root path + description: > + Absolute path to the directory to serve as the static site. + /share, /media, and /config are fully mapped by HA. + /mnt is allowed with a warning — if files are inaccessible, create a symlink under /share or /media pointing to your /mnt path. + Dangerous system paths (/, /etc, /bin, /lib, /proc, /sys) are blocked and will prevent startup. + static_site_prefix: + name: URL prefix + description: > + The URL path at which static files are served on port 80. + Default "/" serves files at the root. Use a sub-path like "/files/" to restrict + static serving to that location, leaving other paths available for NPM proxy hosts. + log_level: + name: Log level + description: Controls the verbosity of add-on logging. + +network: + 80/tcp: HTTP — static file server and NPM proxy hosts + 81/tcp: NPM Admin Web UI + 443/tcp: HTTPS — NPM proxy hosts