You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
swag: auto-configure reverse proxy for software modules + SWAG-aware menu URLs
Wires SWAG into the configng software stack so that installing any of the
supported modules on a host running SWAG also enables the matching nginx
proxy-conf, and the menu UI shows the SWAG subfolder URL instead of the
direct host:port whenever the proxy is live.
Core helpers (module_docker_utils.sh, runtime/config.runtime.sh,
module_env_init.sh):
- SWAG_URL is read from ${SOFTWARE_FOLDER}/swag/config/SWAG_URL at env
init and exposed to all modules. DISPLAY_URL=${SWAG_URL:-$LOCALIPADD}
is the single source of truth for the menu's right column.
- get_service_url <service> <port>: returns
https://$DISPLAY_URL/<service> when SWAG is up and the
proxy-conf for <service> is
enabled,
http://$DISPLAY_URL:<port> otherwise.
- docker_configure_swag_proxy <service> [port] [proto]: copies the
SWAG sample to its enabled .conf, sed-rewrites $upstream_port and
$upstream_proto, touches the .enabled marker, and reloads nginx.
Silent no-op (returns 1) if the sample isn't present, returns 2 if
SWAG isn't installed — modules can call it unconditionally.
- docker_seed_swag_proxy_conf <service>: reads an nginx subfolder
proxy-conf from stdin and writes it as
/config/nginx/proxy-confs/<service>.subfolder.conf.sample inside
the SWAG container, for services where linuxserver/reverse-proxy-
confs:master doesn't ship a stock sample (currently netbox; same
pattern applicable to immich, vaultwarden, …). Skips writing if a
sample is already present so an upstream sample or hand-edited
admin override wins on the next install.
Per-module wiring:
- 22 modules whose dockername matches a stock proxy-conf in
linuxserver/reverse-proxy-confs:master gain a
docker_configure_swag_proxy call after their docker run:
bazarr, deluge, domoticz, dozzle, duplicati, embyserver→emby,
filebrowser, ghost, grafana, jellyfin, lidarr, medusa, netdata,
nextcloud (https), phpmyadmin, pi-hole→pihole, prowlarr,
qbittorrent, radarr, sabnzbd, sonarr, syncthing, transmission.
- homepage / immich / netbox / portainer pre-existing custom paths
are folded in, with portainer correctly using HTTPS+9443.
netbox SWAG support (subfolder mode):
- Seeds a hand-authored netbox.subfolder.conf.sample into SWAG via
docker_seed_swag_proxy_conf so docker_configure_swag_proxy has
something to enable. The conf does not rewrite the path —
upstream NetBox sees /netbox unchanged.
- When the swag container is present at install time, bakes
BASE_PATH = 'netbox/' and CSRF_TRUSTED_ORIGINS = ['https://$SWAG_URL']
into the generated configuration.py. Without BASE_PATH, Django
emits absolute URLs (form action=/login/?next=/netbox, /static/…)
that 404 once SWAG strips them at /netbox; without
CSRF_TRUSTED_ORIGINS, login POSTs 403 even with paths fixed.
These settings live in configuration.py because netboxcommunity/
netbox does not consume BASE_PATH= / CSRF_TRUSTED_ORIGINS= from
the container env. Trade-off: with BASE_PATH set, direct port
access at / no longer works — only http://host:port/netbox/.
netbox postgres args:
- module_postgres install takes six positional args
(<user> <pass> <db> <image-repo> <image-tag> <container-name>);
netbox was passing five and fusing image+tag into one. The result
was Docker 404'ing on 'postgres:17-alpine:postgres-netbox' and the
postgres container defaulting to the name 'postgres' (collision
with any standalone postgres install). Split DATABASE_IMAGE into
DATABASE_IMAGE + DATABASE_TAG and pass DATABASE_HOST in its
proper sixth slot, matching the pattern module_immich already uses.
Menu URL routing (config.runtime.sh):
- 23 update_sub_submenu_data lines (the SWAG-applicable subset) now
go through get_service_url — flipping each menu's right-column URL
from 'http://host:port' to 'https://host/<service>' the moment
that service's proxy-conf is enabled in SWAG, and back if it ever
isn't. pi-hole and ghost retain their /admin and /ghost subpaths
by appending the suffix after the helper output.
- NCT002 (nextcloud) and CPT002 (cockpit) intentionally untouched —
direct URLs are HTTPS-only on a self-signed port; helper falls
back to plain http otherwise. Worth a follow-up that gives the
helper a fallback-protocol arg.
No regression for users without SWAG: get_service_url,
docker_configure_swag_proxy and docker_seed_swag_proxy_conf all fall
back to existing behaviour when the swag container isn't present.
update_sub_submenu_data "Software""Media""STC002""http://$LOCALIPADD:${module_options["module_syncthing,port"]%%*}"# removing second port from url
153
+
update_sub_submenu_data "Software""Media""STC002""$(get_service_url "syncthing""${module_options["module_syncthing,port"]%%*}")"# removing second port from url
update_sub_submenu_data "Software""Containers""POR002""http://$LOCALIPADD:${module_options["module_portainer,port"]%%*}"# removing second port from url
161
+
# Portainer uses HTTPS on port 9443 (not the edge agent port 9000)
162
+
if docker container ls -a --format "{{.Names}}"2>/dev/null | grep -q "^swag$"&& \
163
+
docker exec swag test -f "/config/nginx/proxy-confs/portainer.subfolder.conf.enabled"2>/dev/null;then
update_sub_submenu_data "Software""Backup""DPL002""http://$LOCALIPADD:${module_options["module_duplicati,port"]%%*}"# removing second port from url
170
+
update_sub_submenu_data "Software""Backup""DPL002""$(get_service_url "duplicati""${module_options["module_duplicati,port"]%%*}")"# removing second port from url
update_sub_submenu_data "Software""DNS""PIH003""http://$LOCALIPADD:${module_options["module_pi_hole,port"]%%*}/admin"# removing second port from url
185
+
update_sub_submenu_data "Software""DNS""PIH003""$(get_service_url "pihole""${module_options["module_pi_hole,port"]%%*}")/admin"# removing second port from url
145
186
update_sub_submenu_data "Software""DNS""ADG002""http://$LOCALIPADD:${module_options["module_adguardhome,port"]%%*}"# removing second port from url
update_sub_submenu_data "Software""Downloaders""DOW002""http://$LOCALIPADD:${module_options["module_qbittorrent,port"]%%*}"# removing second port from url
161
-
update_sub_submenu_data "Software""Downloaders""DEL002""http://$LOCALIPADD:${module_options["module_deluge,port"]%%*}"# removing second port from url
162
-
update_sub_submenu_data "Software""Downloaders""TRA002""http://$LOCALIPADD:${module_options["module_transmission,port"]%%*}"# removing second port from url
update_sub_submenu_data "Software""Downloaders""DOW002""$(get_service_url "qbittorrent""${module_options["module_qbittorrent,port"]%%*}")"# removing second port from url
203
+
update_sub_submenu_data "Software""Downloaders""DEL002""$(get_service_url "deluge""${module_options["module_deluge,port"]%%*}")"# removing second port from url
204
+
update_sub_submenu_data "Software""Downloaders""TRA002""$(get_service_url ${module_options["module_transmission,servicename"]}${module_options["module_transmission,port"]})"# removing second port from url
0 commit comments