TVHeadend behind Caddy: Proxying Basic Auth/Digest and RTSP

Hello, it’s me again! =)

1. Output of caddy version:

v2.6.2 h1:wKoFIxpmOJLGl3QXoo6PNbYvGW4xLEgo32GPBEjWL8o=

2. How I run Caddy:

OpenWrt via rc.local. Quite basic, but keeps it alive (enough).

a. System environment:

OpenWrt 22.03 on FriendlyElec NanoPi R6s

b. Command:

# rc.local
/usr/bin/caddy start --resume --config /srv/Caddyfile

c. Service/unit/compose file:

Above

d. My complete Caddy config:

# TVHeadend
tvh.birb.it:80 {
        reverse_proxy * localhost:9981 {
                header_up X-Real-IP {remote_host}
                header_up X-Forwarded-For {remote_host}
        }
}

3. The problem I’m having:

# curl -Lv tvh.birb.it
*   Trying 192.168.2.1:80...
* Connected to tvh.birb.it (192.168.2.1) port 80 (#0)
> GET / HTTP/1.1
> Host: tvh.birb.it
> User-Agent: curl/7.86.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 502 Bad Gateway
< Server: Caddy
< Date: Tue, 20 Dec 2022 03:17:11 GMT
< Content-Length: 0
<
* Connection #0 to host tvh.birb.it left intact

What I am trying to do: I would like to make TVHeadend available via Caddy (and my reverse-proxy outside) by using the name tvh.birb.it instead. Jellyfin, which I use to access it, has the Jellyfin Media Player, which allows one to get the raw TV stream via RTSP and/or HTTP. This means no transcoding work needs to be done on the TVH server and can instead happen on the much beefier client.

But - first things first. When I try to open the TVHeadend interface through the reverse proxy, I get the bad-gateway error. The logs are below, but these are logs from me attempting different IP address values to try and see if maybe TVH refused the connection…but, that does not seem to be the error.

Here is what it should look like:

# curl -Lv http://192.168.2.1:9981
*   Trying 192.168.2.1:9981...
* Connected to 192.168.2.1 (192.168.2.1) port 9981 (#0)
> GET / HTTP/1.1
> Host: 192.168.2.1:9981
> User-Agent: curl/7.83.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Server: HTS/tvheadend
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST, GET, OPTIONS
< Access-Control-Allow-Headers: x-requested-with,authorization,content-type
< Access-Control-Allow-Credentials: true
< Cache-Control: no-cache
< Connection: Keep-Alive
< Location: extjs.html
< Content-Type: text/html
< Content-Length: 173
<
* Ignoring the response-body
* Connection #0 to host 192.168.2.1 left intact
* Issue another request to this URL: 'http://192.168.2.1:9981/extjs.html'
* Found bundle for host: 0x254251aded0 [serially]
* Re-using existing connection #0 with host 192.168.2.1
* Connected to 192.168.2.1 (192.168.2.1) port 9981 (#0)
> GET /extjs.html HTTP/1.1
> Host: 192.168.2.1:9981
> User-Agent: curl/7.83.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: HTS/tvheadend
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST, GET, OPTIONS
< Access-Control-Allow-Headers: x-requested-with,authorization,content-type
< Access-Control-Allow-Credentials: true
< Cache-Control: no-cache
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Content-Length: 817
<
<!DOCTYPE html>
<html>
... snip ...

4. Error messages and/or full log output:

2022/12/20 03:26:55.207 debug   http.handlers.reverse_proxy     selected upstream       {"dial": "127.0.0.1:9981", "total_upstreams": 1}
2022/12/20 03:26:55.210 debug   http.handlers.reverse_proxy     upstream roundtrip      {"upstream": "127.0.0.1:9981", "duration": 0.001769593, "request": {"remote_ip": "192.168.2.212", "remote_port": "23888", "proto": "HTTP/1.1", "method": "GET", "host": "tvh.birb.it", "uri": "/", "headers": {"User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 OPR/93.0.0.0"], "X-Forwarded-Host": ["tvh.birb.it"], "Cache-Control": ["max-age=0"], "Dnt": ["1"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Accept-Language": ["de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7"], "Accept-Encoding": ["gzip, deflate"], "X-Real-Ip": ["192.168.2.212"], "X-Forwarded-For": ["192.168.2.212"], "Upgrade-Insecure-Requests": ["1"], "X-Forwarded-Proto": ["http"]}}, "error": "dial tcp 127.0.0.1:9981: connect: connection refused"}
2022/12/20 03:26:55.210 error   http.log.error  dial tcp 127.0.0.1:9981: connect: connection refused    {"request": {"remote_ip": "192.168.2.212", "remote_port": "23888", "proto": "HTTP/1.1", "method": "GET", "host": "tvh.birb.it", "uri": "/", "headers": {"Upgrade-Insecure-Requests": ["1"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 OPR/93.0.0.0"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Accept-Language": ["de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7"], "Cache-Control": ["max-age=0"], "Dnt": ["1"], "Accept-Encoding": ["gzip, deflate"], "Connection": ["keep-alive"]}}, "duration": 0.00299142, "status": 502, "err_id": "p5pwxiyvv", "err_trace": "reverseproxy.statusError (reverseproxy.go:1272)"}

5. What I already tried:

I used the same values to reverse_proxy that I usually use when connecting via my browser (and in Jellyfin too). The idea is that once I can map HTTP and RTSP to a hostname, the underlying IP can re resolved depending on where I am (within my vpn, home, in a cafe, …). But if I can’t even get into the TVH interface, that’s going to be a problem… ^^’

I suspect that I am not passing the right headers. TVH is configured to allow reverse proxying:

6. Links to relevant resources:

None I could think of.

Have you tried using reverse_proxy 192.168.2.1:9981 instead of reverse_proxy * localhost:9981?

Note: That * is optional and can be omitted :innocent:

1 Like

I tried that - as well as prefixing with http:// as well in the hopes that this would solve it. Unfortunately, no dice…

Is there something about authorization headers in HTTP/1.x and HTTP/2 or /3 even?

No, the connection fails at the TCP layer (or even before).

This isn’t a problem with Caddy, it’s a networking problem between Caddy and your upstream app.

1 Like

is the server where Caddy is running the same server where TVHeadend running? Here you are proxying to localhost:9981

in your curl log, you are curl-ing to 192.168.2.1:9981.

If they are not, you can replace localhost with 192.168.2.1, but only if you’re sure the IP address will not change or you have another approach to your network topology.

Another way to investigate this is to check if TVHeadend is listening on port 9981 on all interfaces and not just on 192.168.2.1.

This topic was automatically closed after 30 days. New replies are no longer allowed.