mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-07-20 21: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