Files
hassio-addons/sabnzbd/rootfs/etc
Alexandre 8341e542fb feat(sabnzbd): enable Home Assistant ingress (#3019)
* feat(sabnzbd): enable Home Assistant ingress

The add-on already carried a complete but disabled nginx ingress scaffold:
`etc/nginx/` with its includes and a `servers/ingress.conf`, a
`cont-init.d/32-nginx_ingress.sh` short-circuited by `exit 0`, and
`ENV PACKAGES="nginx"` in a Dockerfile byte-identical to nzbget's. Only
`ingress: true` and the s6 service that starts nginx were missing.

What SABnzbd 5.1.1 actually needs from the proxy, measured against the
running add-on rather than assumed:

- Its interface emits only relative links (`href="../../config/general/"`,
  `href="../../staticcfg/css/Auto.css"`, `action="./one"`), and grepping the
  5.1.1 source for `(href|src|action)="/` across `interfaces/{Glitter,Config,
  wizard}` and for absolute `url:` literals in the Glitter JavaScript returns
  nothing. A plain pass-through proxy preserves path depth, so no `sub_filter`
  is warranted. The previous config's `sub_filter /sabnzbd ...` would also have
  mangled the `https://sabnzbd.org/wiki/...` help links present on every
  config page.
- Redirects are the one exception: `Raiser()` prefixes `cfg.url_base()`, so
  `GET /` answers `303 Location: /sabnzbd/wizard/`. One `proxy_redirect`
  handles every observed case; all of them were path-absolute, never a full
  URL. Login redirects and logout go through the same `Raiser()`, and the
  session cookie's path is hardcoded to `/` (`interface.py:316`), so it is
  still sent under the ingress path.
- SABnzbd rejects a Host header that is not an IP literal:
  `Host: homeassistant` answers 403 "Hostname verification failed", while
  `Host: 192.168.1.5:8123` answers 200. nginx therefore sends `$proxy_host`
  instead of including the shared `proxy_params.conf`, which forwards
  `$http_host`.

`ingress_entry: sabnzbd` is dropped rather than kept: Supervisor appends it to
the ingress URL, which only resolves while the user's `url_base` is literally
`/sabnzbd`, and that is a setting they can change. SABnzbd serves the same
interface at `/` as under its `url_base` (verified for `/config/general/`,
`/static/`, `/staticcfg/` and `/wizard/`), so entering at the ingress root
works for any value, including the empty code default.

Ingress traffic reaches SABnzbd as `127.0.0.1:8080` and so is not filtered by
a user's host whitelist; direct ip:port access is unchanged and still is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(sabnzbd): keep the ingress Location relative and scope the login cookie

Exercising the shipped config against the running add-on caught a bug that
reading it did not. With nginx's default `absolute_redirect on`, rewriting
`Location: /sabnzbd/wizard/` produced
`http://homeassistant.local:18099/api/hassio_ingress/<token>/sabnzbd/wizard/`
— nginx expands a scheme-less replacement using the browser's Host and its own
listen port, which is the add-on's internal ingress port and is not reachable
from the browser. `absolute_redirect off` keeps it a path, which the browser
resolves against the Home Assistant origin.

`proxy_cookie_path` comes from Codex's review of the diff. SABnzbd hardcodes
the login cookie to `Path=/` (`interface.py:316`), so on the shared ingress
origin the browser would send it to every other add-on's ingress path as well.

Verified end to end by running the shipped nginx.conf and ingress.conf against
the live add-on, with the browser Host set to a non-IP hostname throughout:
all five redirect cases return a path under the ingress entry, the config
pages, wizard, API and both static roots return 200, and a stub upstream
emitting `Path=/` comes back rewritten to the ingress path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(sabnzbd): drop webui, which the add-on linter forbids alongside ingress

frenck/action-addon-linter fails the PR with "'webui' should be removed,
Ingress is enabled." No other ingress add-on in this repo keeps the key. The
"Open Web UI" button now opens ingress; the ports mapping is untouched, so
direct ip:port still works, it just has to be typed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(sabnzbd): make the nginx finish script actually work on s6-overlay v3

CodeRabbit is right that the execline finish script copied from nzbget is
inert on this image. s6-portable-utils dropped `s6-test` in favour of
execline's `eltest` — s6-overlay 3.2.1.0 ships no `s6-test` at all — so
execlineb cannot run the first `if` block and never reaches s6-svscanctl.
`/var/run/s6/services` is also the v2 scandir path; v3's legacy services.d
compatibility layer uses /run/service.

Rather than port it to eltest, use the shell form the scrutiny add-on already
ships: `kill -15 1` signals s6-overlay's init directly, so it depends on
neither the s6 tool set nor the scandir path, and it is three lines shorter.
The 0 and 256 exclusions are kept, so a normal shutdown does not trigger it.

Also fix the CHANGELOG date to YYYY-MM-DD per Copilot: that is what this file
and 7705 of the repo's 8068 dated headings use.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 15:46:36 +02:00
..