diff --git a/Dockerfile b/Dockerfile index a29648a..1eb1ccf 100755 --- a/Dockerfile +++ b/Dockerfile @@ -2,5 +2,7 @@ FROM nginx:alpine RUN rm -rf /usr/share/nginx/html/* COPY . /usr/share/nginx/html/ COPY default.conf /etc/nginx/conf.d/default.conf +COPY docker/entrypoint/10-generate-config.sh /docker-entrypoint.d/10-generate-config.sh +RUN chmod +x /docker-entrypoint.d/10-generate-config.sh EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/README.md b/README.md index 3acbc75..82d37a2 100755 --- a/README.md +++ b/README.md @@ -54,9 +54,9 @@ Hestia comes with a suite of built-in apps. You can add as many as you like\! ## 🚀 Getting Started -### Option 1: Docker (Recommended) +### Option 1: Docker Compose (Recommended) -This is the best way to run Hestia if you plan to use the **API integrations** (Glances, Pi-hole, etc.), as the included Nginx config handles CORS permissions for you. +This is the fastest way to get Hestia (and its homelab proxies) online. The Compose file wires up Nginx, health checks, and optional proxy snippets for you. 1. Clone the repository: @@ -65,16 +65,40 @@ This is the best way to run Hestia if you plan to use the **API integrations** ( cd hestia-core ``` -2. Build and Run: +2. Copy the default environment file and tweak anything you need (host port, proxy targets, etc.): ```bash - docker build -t hestia-core . - docker run -d -p 8080:80 --name hestia hestia-core + cp compose.env.example .env + # edit .env to point at your Pi-hole / Deluge / Jellyfin hosts ``` -3. Visit `http://localhost:8080`\! + > The upstream proxy blocks are **disabled by default** so the dashboard can boot without external services. Flip `ENABLE_*_PROXY` to `true` and set the `*_TARGET` values when you're ready to wire them up. -### Option 2: Static / Manual +3. (Optional) Drop any extra Nginx snippets into `config/nginx/` if you need to proxy additional apps. + +4. Build and start the stack: + + ```bash + docker compose up -d --build + # Use --build only the first time or when updating + ``` + + > Need Hestia to reach services defined in another Compose project? Add its network name under `services.hestia.networks` in `compose.yaml`, or connect the container later with `docker network connect`. + +5. Visit `http://localhost:8080` (or whatever `HOST_PORT` you set). + +### Option 2: Docker CLI + +Prefer raw `docker build`/`docker run`? The classic workflow still works and now ships with the same dynamic config generator used by Compose. + +```bash +docker build -t hestia-core . +docker run -d -p 8080:80 --name hestia --env-file .env hestia-core +``` + +Set any of the variables shown in `compose.env.example` (e.g., `PIHOLE_PROXY_TARGET`) to customize the generated Nginx config before starting the container. + +### Option 3: Static / Manual Since Hestia is vanilla JavaScript, you can run it on any web server. @@ -91,13 +115,26 @@ python3 -m http.server 8000 ### Using the Proxy (Docker Only) -To make the integrations work smoothly, Hestia's `default.conf` sets up internal proxies. When configuring apps in the dashboard, use these relative paths: +Hestia's container publishes a small reverse proxy for the integrations, so the UI can talk to your homelab services without CORS issues. When configuring apps inside the dashboard, point them at these relative paths: * **Pi-hole URL:** `/pi-api/admin/api.php` (instead of `http://192.168.x.x/...`) * **Deluge URL:** `/deluge-api/json` * **Jellyfin URL:** `/jellyfin-api/` -*Note: You will need to update `default.conf` to point to your actual server IPs before building the Docker image\!* +All of the proxy blocks are generated from environment variables at container start-up. The most common knobs live in `.env`: + +| Variable | Purpose | +| --- | --- | +| `ENABLE_PIHOLE_PROXY` | Toggle the Pi-hole proxy block without editing Nginx (default `false`). | +| `PIHOLE_PROXY_TARGET` | Upstream URL for your Pi-hole instance (required when `ENABLE_PIHOLE_PROXY=true`). | +| `ENABLE_DELUGE_PROXY` | Toggle the Deluge proxy block (default `false`). | +| `DELUGE_PROXY_TARGET` | RPC endpoint for Deluge (default `http://deluge:8112/`). | +| `ENABLE_JELLYFIN_PROXY` | Toggle the Jellyfin proxy block (default `false`). | +| `JELLYFIN_PROXY_TARGET` | Base URL for Jellyfin (default `http://jellyfin:8096/`). | + +> Leave `PIHOLE_HOST_HEADER`, `DELUGE_HOST_HEADER`, and `JELLYFIN_HOST_HEADER` blank unless you need to override them—the entrypoint falls back to Nginx's `$host` variable automatically. + +You can also change the exposed paths (`*_PROXY_PATH`) or disable any integration with `ENABLE_*_PROXY=false`. For additional services, drop custom `.conf` snippets into `config/nginx/`—they are loaded automatically on container start. --- diff --git a/compose.env.example b/compose.env.example new file mode 100644 index 0000000..8a3a9a8 --- /dev/null +++ b/compose.env.example @@ -0,0 +1,24 @@ +# Copy this file to `.env` and adjust the values you need before running docker compose. +HOST_PORT=8080 +NGINX_LISTEN_PORT=80 + +# Pi-hole proxy passthrough +ENABLE_PIHOLE_PROXY=false +PIHOLE_PROXY_PATH=/pi-api/ +PIHOLE_PROXY_TARGET= +PIHOLE_HOST_HEADER=pi.hole # leave blank to fall back to Nginx's $host +PIHOLE_SSL_VERIFY=off + +# Deluge proxy passthrough +ENABLE_DELUGE_PROXY=false +DELUGE_PROXY_PATH=/deluge-api/ +DELUGE_PROXY_TARGET=http://deluge:8112/ +# Leave empty to default to Nginx's $host variable +DELUGE_HOST_HEADER= + +# Jellyfin proxy passthrough +ENABLE_JELLYFIN_PROXY=false +JELLYFIN_PROXY_PATH=/jellyfin-api/ +JELLYFIN_PROXY_TARGET=http://jellyfin:8096/ +# Leave empty to default to Nginx's $host variable +JELLYFIN_HOST_HEADER= diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..58b601c --- /dev/null +++ b/compose.yaml @@ -0,0 +1,38 @@ +services: + hestia: + container_name: hestia-core + build: + context: . + dockerfile: Dockerfile + ports: + - "${HOST_PORT:-8080}:80" + environment: + NGINX_LISTEN_PORT: ${NGINX_LISTEN_PORT:-80} + ENABLE_PIHOLE_PROXY: ${ENABLE_PIHOLE_PROXY:-false} + PIHOLE_PROXY_PATH: ${PIHOLE_PROXY_PATH:-/pi-api/} + PIHOLE_PROXY_TARGET: ${PIHOLE_PROXY_TARGET:-} + PIHOLE_HOST_HEADER: ${PIHOLE_HOST_HEADER:-pi.hole} + PIHOLE_SSL_VERIFY: ${PIHOLE_SSL_VERIFY:-off} + ENABLE_DELUGE_PROXY: ${ENABLE_DELUGE_PROXY:-false} + DELUGE_PROXY_PATH: ${DELUGE_PROXY_PATH:-/deluge-api/} + DELUGE_PROXY_TARGET: ${DELUGE_PROXY_TARGET:-http://deluge:8112/} + DELUGE_HOST_HEADER: ${DELUGE_HOST_HEADER:-} + ENABLE_JELLYFIN_PROXY: ${ENABLE_JELLYFIN_PROXY:-false} + JELLYFIN_PROXY_PATH: ${JELLYFIN_PROXY_PATH:-/jellyfin-api/} + JELLYFIN_PROXY_TARGET: ${JELLYFIN_PROXY_TARGET:-http://jellyfin:8096/} + JELLYFIN_HOST_HEADER: ${JELLYFIN_HOST_HEADER:-} + volumes: + - ./config/nginx:/etc/nginx/server.d:ro + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:${NGINX_LISTEN_PORT:-80} > /dev/null"] + interval: 30s + timeout: 5s + retries: 5 + start_period: 5s + networks: + - hestia + +networks: + hestia: + driver: bridge diff --git a/config/nginx/.gitkeep b/config/nginx/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker/entrypoint/10-generate-config.sh b/docker/entrypoint/10-generate-config.sh new file mode 100644 index 0000000..cb2d8ee --- /dev/null +++ b/docker/entrypoint/10-generate-config.sh @@ -0,0 +1,136 @@ +#!/bin/sh +set -e + +CONF_DIR="/etc/nginx/conf.d" +CONF_FILE="${CONF_DIR}/default.conf" +SNIPPETS_DIR="/etc/nginx/server.d" + +mkdir -p "${CONF_DIR}" "${SNIPPETS_DIR}" + +normalize_path() { + value="$1" + if [ -z "${value}" ]; then + value="/" + fi + case "${value}" in + /*) : ;; + *) value="/${value}" ;; + esac + printf "%s" "${value}" +} + +path_with_slash() { + value=$(normalize_path "$1") + case "${value}" in + */) : ;; + *) value="${value}/" ;; + esac + printf "%s" "${value}" +} + +path_no_slash() { + value=$(normalize_path "$1") + value="${value%/}" + if [ -z "${value}" ]; then + value="/" + fi + printf "%s" "${value}" +} + +listen_port="${NGINX_LISTEN_PORT:-80}" +root_dir="${NGINX_ROOT:-/usr/share/nginx/html}" + +cat > "${CONF_FILE}" <> "${CONF_FILE}" <> "${CONF_FILE}" <<'EOF' + + include /etc/nginx/server.d/*.conf; +} +EOF