@@ -26,7 +26,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DEPLOY_PATH: /var/www/html/heos
|
DEPLOY_PATH: /var/www/html/heos
|
||||||
SERVICE: heos-panel
|
SERVICE: heos-panel
|
||||||
PANEL_URL: http://127.0.0.1:5005/ # WEB_PORT in config.py
|
PANEL_URL: http://127.0.0.1:5443/ # WEB_PORT in config.py
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pip install -r requirements.txt
|
|||||||
python3 app.py
|
python3 app.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Then open `http://<pi-ip>:5005/`.
|
Then open `http://<pi-ip>:5443/`.
|
||||||
|
|
||||||
The virtual environment is not optional on a current Raspberry Pi OS:
|
The virtual environment is not optional on a current Raspberry Pi OS:
|
||||||
`pip install` straight into the system Python is refused there with
|
`pip install` straight into the system Python is refused there with
|
||||||
@@ -49,7 +49,7 @@ below calls the environment's Python directly, so it does not care.
|
|||||||
|
|
||||||
## Configure
|
## Configure
|
||||||
|
|
||||||
Open `http://<pi-ip>:5005/api/targets` and copy the exact `name` HEOS reports
|
Open `http://<pi-ip>:5443/api/targets` and copy the exact `name` HEOS reports
|
||||||
for each device into `TARGETS` in `config.py`. The names come from whatever
|
for each device into `TARGETS` in `config.py`. The names come from whatever
|
||||||
you typed in the HEOS app, so they rarely match the model names.
|
you typed in the HEOS app, so they rarely match the model names.
|
||||||
|
|
||||||
@@ -158,18 +158,27 @@ deployed copy.
|
|||||||
|
|
||||||
## Behind a reverse proxy, at /heos
|
## Behind a reverse proxy, at /heos
|
||||||
|
|
||||||
`deploy/heos.conf` reverse-proxies `/heos` to the panel with Apache:
|
`deploy/heos.apache.conf` reverse-proxies `/heos` to the panel with Apache:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo a2enmod proxy proxy_http headers
|
sudo a2enmod proxy proxy_http headers
|
||||||
sudo cp deploy/heos.conf /etc/apache2/conf-available/heos.conf
|
sudo cp deploy/heos.apache.conf /etc/apache2/conf-available/heos.conf
|
||||||
sudo a2enconf heos
|
sudo a2enconf heos
|
||||||
sudo apachectl configtest && sudo systemctl reload apache2
|
sudo apachectl configtest && sudo systemctl reload apache2
|
||||||
```
|
```
|
||||||
|
|
||||||
`deploy/heos.nginx.conf` is the same thing for nginx: copy it to
|
`deploy/heos.nginx.conf` is the same thing for nginx — a whole `server`
|
||||||
`/etc/nginx/snippets/heos.conf`, `include snippets/heos.conf;` inside the
|
block for `rpioffice.nest.domain.com`, ready for `sites-available`:
|
||||||
`server` block, then `sudo nginx -t && sudo systemctl reload nginx`.
|
|
||||||
|
```bash
|
||||||
|
sudo cp deploy/heos.nginx.conf /etc/nginx/sites-available/heos
|
||||||
|
sudo ln -s /etc/nginx/sites-available/heos /etc/nginx/sites-enabled/heos
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
sudo certbot --nginx -d rpioffice.nest.domain.com # optional, adds the 443 block
|
||||||
|
```
|
||||||
|
|
||||||
|
It serves the panel at `/heos` and refuses everything else on that host;
|
||||||
|
the file ends with the two-line change that puts it at the root instead.
|
||||||
|
|
||||||
Both ship restricted to the local network — this controls the speakers, and
|
Both ship restricted to the local network — this controls the speakers, and
|
||||||
it usually hangs off a host with a public certificate. Delete the
|
it usually hangs off a host with a public certificate. Delete the
|
||||||
@@ -179,7 +188,7 @@ up.
|
|||||||
The app works at either address without being told which. The proxy sends
|
The app works at either address without being told which. The proxy sends
|
||||||
`X-Forwarded-Prefix: /heos`, and every URL the app generates — stylesheet,
|
`X-Forwarded-Prefix: /heos`, and every URL the app generates — stylesheet,
|
||||||
icons, the manifest's `start_url`, every `fetch` — picks up that prefix.
|
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 `/...`.
|
Serve it straight from port 5443 and the same URLs come out as `/...`.
|
||||||
That header is what the `headers` module is for; without it the page loads
|
That header is what the `headers` module is for; without it the page loads
|
||||||
and nothing on it works.
|
and nothing on it works.
|
||||||
|
|
||||||
@@ -187,7 +196,7 @@ Two things worth knowing:
|
|||||||
|
|
||||||
- The proxy block takes `/heos` away from the filesystem, so the source
|
- The proxy block takes `/heos` away from the filesystem, so the source
|
||||||
under `/var/www/html/heos` stops being served as static files.
|
under `/var/www/html/heos` stops being served as static files.
|
||||||
- The panel still answers directly on `<pi-ip>:5005`. Start it with
|
- The panel still answers directly on `<pi-ip>:5443`. Start it with
|
||||||
`--host 127.0.0.1` if you want Apache to be the only way in.
|
`--host 127.0.0.1` if you want Apache to be the only way in.
|
||||||
|
|
||||||
## How the grouping actually works
|
## How the grouping actually works
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"""HEOS panel: a phone-sized web remote plus the HTTP bridge it runs on.
|
"""HEOS panel: a phone-sized web remote plus the HTTP bridge it runs on.
|
||||||
|
|
||||||
pip3 install -r requirements.txt
|
pip3 install -r requirements.txt
|
||||||
python3 app.py # http://<pi-ip>:5005/
|
python3 app.py # http://<pi-ip>:5443/
|
||||||
|
|
||||||
Everything the UI does goes through /api/*. The flatter, query-string
|
Everything the UI does goes through /api/*. The flatter, query-string
|
||||||
endpoints from the original heos_bridge.py (/volume/up?target=..., and
|
endpoints from the original heos_bridge.py (/volume/up?target=..., and
|
||||||
@@ -22,7 +22,7 @@ from heos import HeosError
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Served straight from port 5005 this changes nothing. Behind a reverse
|
# Served straight from port 5443 this changes nothing. Behind a reverse
|
||||||
# proxy that mounts us on a sub-path (Apache at /heos, say) it reads the
|
# proxy that mounts us on a sub-path (Apache at /heos, say) it reads the
|
||||||
# X-Forwarded-Prefix that proxy sets, so every URL the app generates is
|
# X-Forwarded-Prefix that proxy sets, so every URL the app generates is
|
||||||
# /heos/... instead of /..., and the page works either way.
|
# /heos/... instead of /..., and the page works either way.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ AVR_HOST = "192.168.0.10"
|
|||||||
AVR_PORT = 23
|
AVR_PORT = 23
|
||||||
|
|
||||||
# Port the panel itself listens on.
|
# Port the panel itself listens on.
|
||||||
WEB_PORT = 5005
|
WEB_PORT = 5443
|
||||||
|
|
||||||
# --- Rooms ------------------------------------------------------------
|
# --- Rooms ------------------------------------------------------------
|
||||||
# key -> how to find it on the network, and how to label it in the UI.
|
# key -> how to find it on the network, and how to label it in the UI.
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# HEOS panel behind Apache, at /heos
|
# HEOS panel behind Apache, at /heos
|
||||||
#
|
#
|
||||||
# sudo a2enmod proxy proxy_http headers
|
# sudo a2enmod proxy proxy_http headers
|
||||||
# sudo cp /var/www/html/heos/deploy/heos.conf /etc/apache2/conf-available/heos.conf
|
# sudo cp /var/www/html/heos/deploy/heos.apache.conf /etc/apache2/conf-available/heos.conf
|
||||||
# sudo a2enconf heos
|
# sudo a2enconf heos
|
||||||
# sudo apachectl configtest && sudo systemctl reload apache2
|
# sudo apachectl configtest && sudo systemctl reload apache2
|
||||||
#
|
#
|
||||||
# Apache reaches the panel on port 5005 (WEB_PORT in config.py). If you
|
# Apache reaches the panel on port 5443 (WEB_PORT in config.py). If you
|
||||||
# want it reachable ONLY through Apache, start it with --host 127.0.0.1;
|
# want it reachable ONLY through Apache, start it with --host 127.0.0.1;
|
||||||
# by default it also answers directly on the LAN at <pi-ip>:5005.
|
# by default it also answers directly on the LAN at <pi-ip>:5443.
|
||||||
# This block also takes /heos away from the filesystem, so the source in
|
# This block also takes /heos away from the filesystem, so the source in
|
||||||
# /var/www/html/heos stops being reachable as static files.
|
# /var/www/html/heos stops being reachable as static files.
|
||||||
|
|
||||||
@@ -26,6 +26,6 @@
|
|||||||
# page loads and nothing on it works.
|
# page loads and nothing on it works.
|
||||||
RequestHeader set X-Forwarded-Prefix /heos
|
RequestHeader set X-Forwarded-Prefix /heos
|
||||||
|
|
||||||
ProxyPass http://127.0.0.1:5005
|
ProxyPass http://127.0.0.1:5443
|
||||||
ProxyPassReverse http://127.0.0.1:5005
|
ProxyPassReverse http://127.0.0.1:5443
|
||||||
</Location>
|
</Location>
|
||||||
+97
-53
@@ -1,57 +1,101 @@
|
|||||||
# HEOS panel behind nginx, at /heos
|
# The HEOS panel at https://domain.com/heos
|
||||||
#
|
#
|
||||||
# sudo cp /var/www/html/heos/deploy/heos.nginx.conf /etc/nginx/snippets/heos.conf
|
# sudo cp /var/www/html/heos/deploy/heos.nginx.conf /etc/nginx/sites-available/heos
|
||||||
# then inside the server { } block that serves the site:
|
# sudo ln -s /etc/nginx/sites-available/heos /etc/nginx/sites-enabled/heos
|
||||||
# include snippets/heos.conf;
|
|
||||||
# sudo nginx -t && sudo systemctl reload nginx
|
# sudo nginx -t && sudo systemctl reload nginx
|
||||||
#
|
#
|
||||||
# nginx reaches the panel on port 5005 (WEB_PORT in config.py). If you want
|
# server_name and the certificate paths have to agree: the paths are the
|
||||||
# it reachable ONLY through nginx, start it with --host 127.0.0.1; by
|
# directory certbot made for that name.
|
||||||
# default it also answers directly on the LAN at <pi-ip>: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 {
|
# nginx reaches the panel on port 5443 (WEB_PORT in config.py). To make
|
||||||
# server_name heos.example.com;
|
# nginx the only way in, add --host 127.0.0.1 to ExecStart in
|
||||||
# location / {
|
# deploy/heos-panel.service; by default the panel also answers directly on
|
||||||
# proxy_pass http://127.0.0.1:5005;
|
# the LAN at <server-ip>:5443.
|
||||||
# proxy_set_header Host $host;
|
|
||||||
# proxy_set_header X-Real-IP $remote_addr;
|
server {
|
||||||
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
listen 80;
|
||||||
# proxy_set_header X-Forwarded-Proto $scheme;
|
listen [::]:80;
|
||||||
# }
|
|
||||||
# }
|
server_name domain.com;
|
||||||
|
|
||||||
|
# Nothing is served in the clear. certbot's nginx plugin works through
|
||||||
|
# this block when it renews, so the redirect does not get in its way.
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
# http2 on; # nginx 1.25.1+. Older builds: listen 443 ssl http2;
|
||||||
|
|
||||||
|
server_name domain.com;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
|
||||||
|
|
||||||
|
# certbot's own settings, kept current by it -- the same thing the maui
|
||||||
|
# Apache vhost does with options-ssl-apache.conf. Both files appear when
|
||||||
|
# certbot configures a host; if this cert came another way (DNS
|
||||||
|
# challenge, standalone, copied from elsewhere) they may not exist and
|
||||||
|
# nginx -t will say so. Then drop these two lines for:
|
||||||
|
# ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
# ssl_session_cache shared:SSL:10m;
|
||||||
|
# ssl_session_timeout 1d;
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
|
||||||
|
# This host is the panel and nothing else, so refuse the rest rather
|
||||||
|
# than falling back on nginx's default root and serving whatever
|
||||||
|
# happens to sit there. Drop this block if the machine serves more.
|
||||||
|
location / {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# A bare /heos misses the location below -- it would fall through to
|
||||||
|
# the 404 above -- so send it to the slashed form first.
|
||||||
|
location = /heos {
|
||||||
|
return 301 /heos/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /heos/ {
|
||||||
|
# The panel controls the speakers, and this hostname may well
|
||||||
|
# resolve from outside. 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 is what strips /heos/ back off before the
|
||||||
|
# request reaches the app.
|
||||||
|
proxy_pass http://127.0.0.1:5443/;
|
||||||
|
|
||||||
|
# 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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Want the panel at the root of this host instead of under /heos? Replace
|
||||||
|
# the three location blocks in the 443 server with the one below, and leave
|
||||||
|
# X-Forwarded-Prefix out of it -- the app is not on a sub-path then, and
|
||||||
|
# generates /static/... and /api/... just as it does on port 5443.
|
||||||
|
#
|
||||||
|
# location / {
|
||||||
|
# proxy_pass http://127.0.0.1:5443;
|
||||||
|
# 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 "";
|
||||||
|
# }
|
||||||
|
|||||||
Reference in New Issue
Block a user