Gateway Route Backend HTTPS
Since v1.41.11, the Home Gateway container honors the existing
Backend HTTPS toggle for gateway routes as well. The gateway then
speaks HTTPS on the LAN hop to the target (e.g. DSM on :5001, Fritzbox
UI on :443, TR-064 endpoint) instead of plain HTTP.
Why
Many LAN services today are HTTPS-only:
- Synology DSM 7 (
:5001— HTTP port 5000 often disabled) - Fritzbox with MyFRITZ + "HTTPS only" enabled
- Unraid / TrueNAS with enforced HTTPS
- Self-hosted web UIs behind Caddy/Traefik in the LAN
- Legacy routers with an HTTPS-only admin interface
Without the toggle, the gateway container could not reach these
services — every request failed with 400 Bad Request or similar.
Data flow
Browser ──HTTPS──▶ Caddy (VPS)
│
│ HTTP over WG tunnel
│ Header: X-Gateway-Target: <lan_host>:<lan_port>
│ X-Gateway-Target-Domain: <domain>
▼
Gateway container (home network)
│
│ scheme depends on the route's backend_https flag:
│ backend_https = false → http://
│ backend_https = true → https:// (rejectUnauthorized off)
▼
LAN target (e.g. 192.168.2.228:5001)
The first hop (Caddy → Gateway) is always HTTP, because it is encrypted inside the WG tunnel — TLS on top would be double encryption without added value. The second hop (Gateway → LAN) leaves the tunnel and talks directly to the LAN target; that is where the flag matters.
Enabling
- Edit the route in the Admin UI (or create a new one)
- Set
Target typetoHome Gateway (LAN) - Enter
LAN host+LAN port - Enable the existing Backend HTTPS toggle
- Save
The gateway container receives the change via config sync
(POST /api/config-changed from server → gateway polls immediately).
New routes take effect after ~2 seconds.
Self-signed certificates
The gateway uses rejectUnauthorized: false (via http-proxy
option secure: false). This means it accepts:
- Self-signed certificates (default on DSM, Fritzbox, Pi-hole)
- Expired certificates
- Hostname mismatches (e.g. IP instead of hostname in the request)
Why is that ok? The hop lies entirely within the home LAN between the gateway container and the target device. The path is:
- not reachable over the public internet
- already authenticated by WireGuard to the gateway
- typically an Ethernet/WiFi connection to the router in the same room
Per-route TLS pinning would be UX overhead without any security gain.
If you want it stricter: set gateway targets to fully qualified LAN domain names instead of IPs and issue an ACME cert via DNS-01 inside the LAN (e.g. Caddy in the LAN in front of the target). The gateway will then verify cleanly again. This already works today, the toggle stays active (the gateway simply also accepts valid certs).
Compat / hashing
The flag is only included in the config-sync JSON when it is
true:
...(r.backend_https ? { backend_https: true } : {}),
Effect: Routes without the flag produce the exactly identical config hash as before the feature — old gateway versions do not diverge on a server upgrade. Only routes with the flag enabled get a new hash value, which automatically triggers a re-fetch of the config at the gateway.
No CONFIG_HASH_VERSION bump required.
Relevant files
Server
src/services/gateways.js—getGatewayConfig()adds the flagsrc/services/caddyConfig.js— TLS transport is never applied to the Caddy→Gateway hop for gateway routes- i18n:
src/i18n/{de,en}.jsonkeyroutes.backend_https_desc
Gateway
src/proxy/router.js— storesbackendHttpsper routesrc/proxy/http.js— pickshttp://vshttps://based on the flag,secure:falsefor self-signed
Tests
- Server:
tests/gateways_getConfig.test.jsomits backend_https on routes without the flagsends backend_https=true when route targets a HTTPS LAN service
- Gateway:
tests/router.test.jscarries backend_https flag so LAN target can be HTTPSbackendHttps defaults to false when flag absent
Deploy order
The changes are backwards compatible in both directions:
- New server, old gateway: Server sends
backend_https=truefor routes that have it set. Old gateway ignores the unknown field, proxies plain HTTP → user gets 400 as before. No crash. - Old server, new gateway: Server does not send the field. New
gateway defaults to
false→ plain HTTP. Identical behavior to before.
For the full feature both sides must be updated, but partial upgrades do not break anything.