From f6c98abe9086cc6bfd0fb4b26770ced924114ee0 Mon Sep 17 00:00:00 2001 From: Franzz Date: Mon, 14 Sep 2026 22:16:30 +0200 Subject: [PATCH] Add an nginx version of the /heos proxy Same contract as the Apache one -- strip the prefix off the request, tell the app about it with X-Forwarded-Prefix, keep it to the local network -- with the two things nginx needs that Apache did not: a redirect for the bare /heos, which would otherwise miss the location and fall through to the filesystem, and the trailing slash on proxy_pass that does the stripping. Co-Authored-By: Claude Opus 5 --- README.md | 21 ++++++++++------ deploy/heos.nginx.conf | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 deploy/heos.nginx.conf diff --git a/README.md b/README.md index c3ec34c..2488232 100644 --- a/README.md +++ b/README.md @@ -104,9 +104,9 @@ WantedBy=multi-user.target sudo systemctl enable --now heos-panel ``` -## Behind Apache, at /heos +## Behind a reverse proxy, at /heos -`deploy/heos.conf` reverse-proxies `/heos` to the panel: +`deploy/heos.conf` reverse-proxies `/heos` to the panel with Apache: ```bash sudo a2enmod proxy proxy_http headers @@ -115,11 +115,16 @@ sudo a2enconf heos sudo apachectl configtest && sudo systemctl reload apache2 ``` -It ships restricted to the local network — it controls the speakers, and -it usually hangs off a vhost with a public certificate. Delete the -`RequireAny` block to open it up. +`deploy/heos.nginx.conf` is the same thing for nginx: copy it to +`/etc/nginx/snippets/heos.conf`, `include snippets/heos.conf;` inside the +`server` block, then `sudo nginx -t && sudo systemctl reload nginx`. -The app works at either address without being told which. Apache sends +Both ship restricted to the local network — this controls the speakers, and +it usually hangs off a host with a public certificate. Delete the +`RequireAny` block (Apache) or the `allow`/`deny` lines (nginx) to open it +up. + +The app works at either address without being told which. The proxy sends `X-Forwarded-Prefix: /heos`, and every URL the app generates — stylesheet, icons, the manifest's `start_url`, every `fetch` — picks up that prefix. Serve it straight from port 5005 and the same URLs come out as `/...`. @@ -128,8 +133,8 @@ and nothing on it works. Two things worth knowing: -- The `` block takes `/heos` away from the filesystem, so the - source under `/var/www/html/heos` stops being served as static files. +- The proxy block takes `/heos` away from the filesystem, so the source + under `/var/www/html/heos` stops being served as static files. - The panel still answers directly on `:5005`. Start it with `--host 127.0.0.1` if you want Apache to be the only way in. diff --git a/deploy/heos.nginx.conf b/deploy/heos.nginx.conf new file mode 100644 index 0000000..241d1e4 --- /dev/null +++ b/deploy/heos.nginx.conf @@ -0,0 +1,57 @@ +# HEOS panel behind nginx, at /heos +# +# sudo cp /var/www/html/heos/deploy/heos.nginx.conf /etc/nginx/snippets/heos.conf +# then inside the server { } block that serves the site: +# include snippets/heos.conf; +# sudo nginx -t && sudo systemctl reload nginx +# +# nginx reaches the panel on port 5005 (WEB_PORT in config.py). If you want +# it reachable ONLY through nginx, start it with --host 127.0.0.1; by +# default it also answers directly on the LAN at :5005. + +# A bare /heos would miss the location below and fall through to the +# filesystem, so send it to the slashed form first. +location = /heos { + return 301 /heos/; +} + +location /heos/ { + # The panel controls the speakers, and it usually hangs off a host + # with a public certificate. Keep it to the house unless you mean + # otherwise: drop these four lines to let it answer from anywhere. + allow 192.168.0.0/24; + allow 127.0.0.1; + allow ::1; + deny all; + + # The trailing slash on proxy_pass is what strips /heos/ back off + # before the request reaches the app. + proxy_pass http://127.0.0.1:5005/; + + # Tells the app it is mounted on a sub-path, so every link, icon and + # fetch it generates is /heos/... rather than /... Without this the + # page loads and nothing on it works. + proxy_set_header X-Forwarded-Prefix /heos; + + 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; + + proxy_http_version 1.1; + proxy_set_header Connection ""; +} + +# Giving it a host of its own instead? Then it is not on a sub-path, and +# the X-Forwarded-Prefix line above is the one thing to leave out: +# +# server { +# server_name heos.example.com; +# location / { +# proxy_pass http://127.0.0.1:5005; +# 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; +# } +# }