mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-07-31 02:10:32 +02:00
Merge pull request #2676 from ToledoEM/nginx_wp
NGINX webserver and Proxy Manager
This commit is contained in:
14
nginx_webserver_proxy/CHANGELOG.md
Normal file
14
nginx_webserver_proxy/CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- Fix Codacy style warnings: add blank lines around lists in README
|
||||||
|
|
||||||
|
## 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
|
||||||
23
nginx_webserver_proxy/Dockerfile
Normal file
23
nginx_webserver_proxy/Dockerfile
Normal file
@@ -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"]
|
||||||
85
nginx_webserver_proxy/README.md
Normal file
85
nginx_webserver_proxy/README.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
[](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://<HA_IP>: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://<HA_IP>: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://<HA_IP>: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.
|
||||||
104
nginx_webserver_proxy/apparmor.txt
Normal file
104
nginx_webserver_proxy/apparmor.txt
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include <tunables/global>
|
||||||
|
|
||||||
|
profile nginx-proxy-manager flags=(attach_disconnected,mediate_deleted) {
|
||||||
|
#include <abstractions/base>
|
||||||
|
#include <abstractions/nameservice>
|
||||||
|
#include <abstractions/openssl>
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
}
|
||||||
4
nginx_webserver_proxy/build.yaml
Normal file
4
nginx_webserver_proxy/build.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
build_from:
|
||||||
|
aarch64: jc21/nginx-proxy-manager:latest
|
||||||
|
amd64: jc21/nginx-proxy-manager:latest
|
||||||
40
nginx_webserver_proxy/config.yaml
Normal file
40
nginx_webserver_proxy/config.yaml
Normal file
@@ -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}"
|
||||||
BIN
nginx_webserver_proxy/icon.png
Normal file
BIN
nginx_webserver_proxy/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
BIN
nginx_webserver_proxy/logo.png
Normal file
BIN
nginx_webserver_proxy/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
118
nginx_webserver_proxy/run.sh
Executable file
118
nginx_webserver_proxy/run.sh
Executable file
@@ -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
|
||||||
25
nginx_webserver_proxy/translations/en.yaml
Normal file
25
nginx_webserver_proxy/translations/en.yaml
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user