Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document alternative methods of accessing Chorus (Reverse proxy, port forwarding, via addons path, etc) #133

Open
lozbrown opened this issue Nov 11, 2016 · 33 comments
Assignees

Comments

@lozbrown
Copy link

Whilst there are configuration to "Enable Reverse Proxy Support" because of the use of web sockets standard configurations do not appear to work for this.

Would it be possible to update the readme or wiki for this project to include suggested configurations for common server such as nginx and apache.

I seem to remember some versions of apache do not support websocket proxy.

This site becomes much more useful when available outside the home, particularly if it can be access securely over SSL which could be achieved with the proxy

@lozbrown lozbrown changed the title Suggestions on how to use proxy for this site... Suggestions on how to use proxy for Chorus2 Nov 11, 2016
@lozbrown
Copy link
Author

For example I found the following is close but does not get the streaming working, Something needs to be corrected with the vfs path. Furthermore image paths could probably be redirected properly by someone who knows how to write rewrite rules.

         location /kodi {
                rewrite           ^/kodi$      https://home.example.com/kodi/ permanent;
                rewrite           ^/kodi/(.*)  /$1  break;
                proxy_redirect  http://localhost:5555   /kodi/;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Scheme $scheme;
                proxy_pass http://localhost:5555;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
       }

        location /image
            {
                proxy_pass          http://localhost:5555;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
            }

         location /vfs
            {
                proxy_pass          http://localhost:5555;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
            }

        location /jsonrpc
            {
                proxy_pass          http://localhost:5555;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
            }

@tommyknows
Copy link

I'd be interested in that too!
Trying the same with Nginx - so that it is possibly to use my HTTPS-Webserver from outside the LAN.

@jez500 jez500 changed the title Suggestions on how to use proxy for Chorus2 Document how to use proxy for Chorus2 Nov 19, 2016
@jez500
Copy link
Collaborator

jez500 commented Nov 19, 2016

If anyone wants to submit some nice documentation on how to do this I will gladly add it to the help section in Chorus. Ideally configuration settings for Nginx, Apache & IIS

@Rouzax
Copy link

Rouzax commented Nov 19, 2016

Hi @jez500,
I also created a ticket with Kodi and they say that it is something you need to add to the web service.

We actually store the HTTP (or any other paths) we got the image from in case we want to refresh it at some point. To make it accessible we add the "image://" VFS protocol in front of it to know that it's a cached image. Webinterfaces and other remotes that want to access these images over the webserver need to URL-encode the whole image:// path which already encodes all the remaining slashes etc. So Chorus2 needs to add that URL encoding step to be fully compatible with how it should be.

@lozbrown
Copy link
Author

I'm pretty close for nginx but don't really understand the rewrite rules so have asked the question in a couple of places that will hopefully yield answers and I'll get back to you if i get it working properly.

http://stackoverflow.com/questions/40704417/nginx-reverse-proxy-config-for-kodi-rewrite-rule

https://forum.nginx.org/read.php?11,271074

@lozbrown
Copy link
Author

lozbrown commented Nov 24, 2016

I've eventually worked out that requests passed to nginx as
home.example.com/kodi/vfs/%2fmedia%2fVirtual%2fVideos%2fMovies%2f10_Items_or_Less.%5b2006%5d.avi
get passed to the server as
/vfs/media/Virtual/Videos/Movies/10_Items_or_Less.[2006].avi
which fails

but somehow requests passed to nginx as
https://home.example.com/vfs/%2fmedia%2fVirtual%2fVideos%2fMovies%2f10_Items_or_Less.%5b2006%5d.avi
gets passed to the kodi webserver as
/vfs/%2fmedia%2fVirtual%2fVideos%2fMovies%2f10_Items_or_Less.%5b2006%5d.avi

which works....
so somehow its unencodeing the vfs path, but the rewrite rule is passing it to the correct place

@lozbrown
Copy link
Author

lozbrown commented Nov 25, 2016

I have it for nginx, I must have tried hundreds of configurations and manuals etc.
But finally I have it working.

    location /kodi{
            rewrite           ^ $request_uri;
            rewrite           ^/kodi/(.*)  /$1  break;
            proxy_redirect  http://localhost:5555   /kodi/;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_pass http://localhost:5555$uri;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
   }
    location /image
        {
            proxy_pass          http://localhost:5555;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    location /jsonrpc
        {
            proxy_pass          http://localhost:5555;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

I may raise a request to make the references to jsonrpc and image/ relative so that the second two blocks are not required

@jez500 jez500 changed the title Document how to use proxy for Chorus2 Document alternative methods of accessing Chorus (Reverse proxy, port forwarding, via addons path, etc) Dec 2, 2016
@war59312
Copy link

war59312 commented Dec 4, 2016

Nicely done.

I'm sure I'm not the only one who would like SSL support (HTTP/2 would be ideal). ;)

@Drsela
Copy link

Drsela commented Jan 13, 2017

Hey @lozbrown

When I try to use your configuration from November 25th, it just gives me an error 500 when I go to www.mydomain.com/kodi

My setup in nginx for /kodi /image /jsonrpc is exactly as yours, except I use port 8585 instead so I just replaced 5555 with 8585. Do you know if I've done anything wrong?

@Zelaf
Copy link

Zelaf commented Feb 11, 2017

Hello, I'm trying to do this as well and I can't find a way to do it. Anyone know a way?
@lozbrown your config gave me the same error as @Drsela.

Thanks for any help.

@druchoo
Copy link

druchoo commented Feb 17, 2017

@lozbrown,
This probably wasn't available when you posted your config but there is reverse proxy support now.

Settings -> Web interface -> Reverse proxy support

If enabled, /jsonrpc and /image locations aren't needed (doesn't seem to work?). Alternatively the 2 locations can be combined to save some typing.

location ~ ^/(image|jsonrpc) {
    proxy_pass          http://localhost:5555;
    proxy_http_version  1.1;
    proxy_set_header    Upgrade $http_upgrade;
    proxy_set_header    Connection "upgrade";
}

@Drsela, @Zelaf, your 500 errors are likely due to no trailing slash in your URL.

Instead of:

www.mydomain.com/kodi

try:

www.mydomain.com/kodi/

Alternatively, you can add another rewrite rule to add trailing slash.

...
    rewrite  ^ $request_uri;
    rewrite  ^([^.]*[^/])$ $1/ permanent;
    rewrite  ^/kodi/(.*)  /$1  break;
...

@war59312, you should be able to use standard method to enabled SSL in nginx. As for WebSocket over HTTP/2.0, my understanding is it is not yet supported (pending RFC?).

To wrap everything up, here is a mostly complete example with trailing slash rewrite and SSL support.

upstream kodi {
  server    my-kodi-server:8080;
  keepalive 512;
}

# Redirect http -> https
server {
  listen 80;
  return 301 https://$host$request_uri;
}

server {
  listen              443 ssl;
  server_name         192.168.1.100 kodi kodi.tld.org;

  # Do SSL stuff...
  ssl_certificate     /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;
  ssl_session_timeout 5m;
  ssl_ciphers         "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";

  # Optionally add basic auth
  auth_basic "Authorization Restricted";
  auth_basic_user_file /etc/nginx/.htpasswd;

  locaton /kodi {
    rewrite            ^ $request_uri;
    rewrite            ^([^.]*[^/])$ $1/ permanent;
    rewrite            ^/kodi/(.*)  /$1  break;
    proxy_redirect     http://kodi   /kodi/;
    proxy_set_header   Host $http_host;
    proxy_redirect     off;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Scheme $scheme;
    proxy_pass         http://kodi$uri;
    proxy_http_version 1.1;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection "upgrade";
  }

  # _Shouldn't_ need this if you turned on proxy headers? (Settings -> Web interface -> Reverse proxy support)
  location ~ ^/(image|jsonrpc) {
    proxy_pass         http://kodi;
    proxy_http_version 1.1;
    proxy_set_header   Upgrade $http_upgrade;
    proxy_set_header   Connection "upgrade";
  }
}

Thanks again @lozbrown!

EDIT: commas should be spaces in server_name

@Zelaf
Copy link

Zelaf commented Feb 18, 2017

HUGE thanks for this @druchoo but can you edit everything that needs to be edited with something like "edit-this" as a place holder because when setting it up I only got to the nginx on debian page.

Thanks again.

EDIT: found out why, was being stupid, do you know how to make it on root and not on /kodi ?

@druchoo
Copy link

druchoo commented Feb 18, 2017

@Zelaf, Unless you want SSL and/or want to change the port (<=1024) then you really don't need nginx.

Nevertheless, here's a solution (most likely can be done better) which should work:

...
location / {
    proxy_set_header    Host $http_host;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Scheme $scheme;
    proxy_pass          http://kodi$uri;
    proxy_http_version  1.1;
    proxy_set_header    Upgrade $http_upgrade;
    proxy_set_header    Connection "upgrade";
}
location ~ ^/(image|jsonrpc) {
    proxy_pass          http://kodi;
    proxy_http_version  1.1;
    proxy_set_header    Upgrade $http_upgrade;
    proxy_set_header    Connection "upgrade";
}
..

@Zelaf
Copy link

Zelaf commented Feb 18, 2017

Thanks for the config @druchoo but I can't connect to the websocket for some reason, know why?

Thanks.

@lozbrown
Copy link
Author

@druchoo I tested adding that setting this morning and removing my location settings for image and jsonrpc and it simply didn't work, I didn't get much time to investigate so added in your neater combined config, thanks for that.

One question, are you sure server_name needs the commas between names? I've found space separated examples.

@druchoo
Copy link

druchoo commented Feb 19, 2017

@Zelaf, Hmm not sure. Seemed to work before but not now.

@lozbrown, my mistake. commas should be spaces (previous comment edited). And yea, 'Reverse proxy support' seemed to work before but not now.

Either something was cached or I just totally screwed up my testing for those 2 cases.

@lozbrown
Copy link
Author

@druchoo I'm, pretty sure it worked in the original chorus but not chorus 2, hence why i raised #140 which is all that's really required to make this work

@Drsela
Copy link

Drsela commented Feb 20, 2017

@druchoo

Thanks, that did the trick! I also enabled reverse proxy support within the web interface and still used the image and jsonrpc paths just to be sure. Everything is working flawlessy :)

@Zelaf
Copy link

Zelaf commented Feb 20, 2017

@druchoo Now I'm not getting web socket on the /kodi config and the / config... Am I missing something?

Also the first config has a typo

locaton /kodi {

instead of

location /kodi {

@Kl0use
Copy link

Kl0use commented Jun 16, 2017

Hi,
thanks for the configs, but i can't get the websocket to work.

config:

upstream kodi {
	server 192.168.1.155:8080;
}
server {
  listen 80;

 location / {
    proxy_set_header    Host $http_host;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Scheme $scheme;
    proxy_pass          http://kodi$uri;
    proxy_http_version  1.1;
    proxy_set_header    Upgrade $http_upgrade;
    proxy_set_header    Connection "upgrade";
}

location ~ ^/(image|jsonrpc) {
    proxy_pass          http://kodi;
    proxy_http_version  1.1;
    proxy_set_header    Upgrade $http_upgrade;
    proxy_set_header    Connection "upgrade";
}

Error - Console output:
WebSocket connection to 'ws://home:9090/jsonrpc?kodi' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

After adding following lines, it takes longer to take a timeout error, see:
1. pending 2. TimeOut

server {
listen 9090;
location / {
   access_log off;
   proxy_pass http://192.168.1.155:9090;
   proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # WebSocket support (nginx 1.4)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
}
}
	

Thank you.

Regards,

Klaus

saponace added a commit to saponace/alis-server that referenced this issue Sep 10, 2017
@gurabli
Copy link

gurabli commented Jul 23, 2019

Bumping this up, as I would need a reverse proxy for Kodi but using LE certs in nginx. Actually I only need it to enable remote https access to my Kodi boxes to be able to connect Sonarr/Radarr notifications (to trigger a library update). I guess I don't need websocket port for that. Any help would be appreciates. Running LE 9.0.2 on Rpi.

@pcross616
Copy link

I feel this issue can be solved pretty easily, kodi needs a configuration value for the internal port (which it has) and an external port (which is needs). The host value is there already the rest is a configuration in haproxy / nginx / apache

Here is a setup (mine but you can extrapolate to something else)

  • I run HAProxy on port 443 and 80
  • I evaluate a set of SNI host entries for backend route for 443 and a few hostname entries on 80 for backends
  • I want to add my custom acl in HAproxy to look for the upgrade header for websockets and add it to a new route for my kodi instance based on the SNI name and the websocket custom acl to point to a different backend (the kodi_websocket port 9090) and not kodi (the webserver 8080)

If the UI would honor the websocket connections based on the configured external hostname and port (not the internal one) this solution would just work with any configuration or reverse proxy.

@ileodo
Copy link

ileodo commented Dec 31, 2020

Here is my nginx config which works fine so far. hope this helps.

#
# Kodi Web
#
location /kodi {
    rewrite           ^ $request_uri;
    rewrite           ^/kodi/(.*)  /$1  break;
    proxy_redirect  http://KODI_IP:8080   /kodi/;
    proxy_set_header Host $http_host;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_pass http://KODI_IP:8080$uri;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    location /kodi/jsonrpc
    {
    	rewrite        ^/kodi/(.*)  /$1  break;
        proxy_pass     http://KODI_IP:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /kodi/image
    {
	rewrite           ^ $request_uri;
        rewrite        ^/kodi/(.*)  /$1  break;
        proxy_pass     http://KODI_IP:8080$uri;
        proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
    }

}

@jtbgroup
Copy link

jtbgroup commented Feb 6, 2021

Hi,

Trying to configure nginx for the same purpose. Copied ileodo's config in my file, but still getting the 404 for jsonrpc and images. Is it normal to have the /kodi/jsonrpc under /kodi and not at the same level?

Or does kodi needs to be configured in a special way?

@ileodo
Copy link

ileodo commented Feb 6, 2021

@jmbreuer can you paste the entire config file ?

@jtbgroup
Copy link

jtbgroup commented Feb 6, 2021

I assume you asked it to me ;-)

this is what my file looks like

      server {
        listen 80;

       location /kodi {
          rewrite           ^ $request_uri;
          rewrite           ^/kodi/(.*)  /$1  break;
          proxy_redirect  http://192.168.1.12:8080   /kodi/;
          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Scheme $scheme;
          proxy_pass http://192.168.1.12:8080$uri;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";

             location /kodi/jsonrpc
             {
	         rewrite        ^/kodi/(.*)  /$1  break;
                 proxy_pass     http://192.168.1.12:8080;
                 proxy_http_version 1.1;
                 proxy_set_header Upgrade $http_upgrade;
                 proxy_set_header Connection "upgrade";
             }

             location /kodi/image
             {   
	         rewrite           ^ $request_uri;
                 rewrite        ^/kodi/(.*)  /$1  break;
                 proxy_pass     http://192.168.1.12:8080$uri;
                 proxy_http_version 1.1;
	         proxy_set_header Upgrade $http_upgrade;
	         proxy_set_header Connection "upgrade";
              }
          }
      }

@ileodo
Copy link

ileodo commented Feb 8, 2021

have you enable the "reverse proxy" in the web ui settings?

@jtbgroup
Copy link

Hi,
Sorry for my late reply. Didn't see your last comment.

Yes, option is active in Web ui.

After several attemps, I tried your config again, which gives this :

upstream KODI_IP {
    server  192.168.1.2:8080;
}

# Redirect http -> https
server {
    if ($host = mydomain.abc.org){
        return 301 https://$host$request_uri;
    }
    listen          8080;
    server_name     mydomain.abc.org;
    return 404;
}

server {
    listen                  443 ssl;
    server_name             mydomain.abc.org;

    # Do SSL stuff...
    ssl_certificate         /etc/letsencrypt/live/mydomain.abc.org/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/mydomain.abc.org/privkey.pem; 
    include                 /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_dhparam             /etc/letsencrypt/ssl-dhparams.pem; 

    location /kodi {
        rewrite             ^ $request_uri;
        rewrite             ^/kodi/(.*)  /$1  break;
        proxy_redirect      http://KODI_IP   /kodi/;
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://KODI_IP$uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        location /kodi/jsonrpc {
            rewrite             ^/kodi/(.*)  /$1  break;
            proxy_pass          http://KODI_IP;
            proxy_http_version  1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location /kodi/image {
            rewrite             ^ $request_uri;
            rewrite             ^/kodi/(.*)  /$1  break;
            proxy_pass          http://KODI_IP$uri;
            proxy_http_version  1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

But browsers keep giving the following messages:

Firefox can’t establish a connection to the server at wss://mydomain.abc.org:9090/jsonrpc?kodi.

@somini
Copy link

somini commented Oct 16, 2021

The following setup works well, except for the WebSocket situation:

server { # Kodi Chorus2
    server_name <SERVER_NAME>;
    listen 443 ssl;
    listen [::]:443 ssl;

    location ~ ^/(image|vfs)/ {
        proxy_pass http://<UPSTREAM>;
    }

    location / {
        proxy_pass http://<UPSTREAM>/;
    }

    # Proxy Settings
    proxy_http_version 1.1;
    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_set_header X-Script-Name /; # Same from root "location" above
    proxy_redirect off;

    # WebSockets
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    # Basic Authentication
    auth_basic "<UPSTREAM-NAME>";
    auth_basic_user_file <SERVER_NAME>.auth;

    # Logging
    # - Write per-host logs, on the usual location
    # - gzip the logs
    # - Flush every 1h, losing logs is fine by me
    access_log /var/log/nginx/<SERVER_NAME>.log.gz combined gzip flush=1h;

    # TLS
    ssl_certificate /etc/letsencrypt/live/<SERVER_NAME>/fullchain.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/<SERVER_NAME>/chain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<SERVER_NAME>/privkey.pem;
}
  • <UPSTREAM>: Kodi server @ LAN (includes port)
  • <SERVER_NAME>: External Hostname
  • UPSTREAM-NAME>: Basic Auth to protect the juicy Kodi API. Don't just expose Chorus2 to the web publicly.

@onknows
Copy link

onknows commented Aug 31, 2022

I noticed that the advanced options for the web interface for example "Reverse proxy support" is stored using browser local storage. That is a very strange way to store these type of settings.

I think the conclusion should be that reverse proxy is just not supported / working currently.

There are a great number of issues with the current setup. That aside, the fact that reverse proxy settings are stored locally is a showstopper I think.

@somini
Copy link

somini commented Aug 31, 2022

I think the biggest papercut with the web interface is not being possible disallowing access to the remote control functionality, that is, only remote viewing AKA pink Chorus.

@jtru
Copy link

jtru commented Mar 10, 2023

The problem

So I have been banging my head against this particular wall for a while, and I think the solution that needs to be achieved to make reverse proxying-associated problems go away involves not only Chorus2, but also either Kodi's built-in HTTP daemon itself (using available libmicrohttpd functionality), or a third-party, external reverse proxy that covers both Kodi's JSONRPC-over-TCP-Port as well as Kodi's HTTP-for-Chorus2-Port.

The core defect/problem is that Chorus seems to expect to make a second, websockets-dedicated TCP connection to an endpoint that is available to the User Agent just like the HTTP port is. In many scenarios that is impossible, or at the very least unwise. It is also unnecessary, since HTTP in general (and afaict, also libmicrohttpd in particular) allows for the well-estyablished Upgrade-Request-Header based mechanism to negotiate a websocket connection for any HTTP URL/request, if the HTTP server so grants it.

The proper solution

Imho, the "most proper" way for Kodi to handle and implement this on its own is to

  1. Use libmicrohttpd to set up an URL namespace/prefix on its Chorus-serving webserver that will serve as the websocket request handler for any clients that want to initiate a websocket connection (i.e., a GET request that will match /jsonrpc?kodi would trigger the behavior described below)
  2. Use that URL namespace/prefix to negotiate a properly reverse-proxied websockets connection to localhost:9090 (or whereever the "remote control"-JSONRPC-TCP-Socket is listening on from the Kodi processes' perspective)
  3. Hard-code the assumption that websockets-server == http-server and websockets-port == http-port into Chorus2, along with the URL namespace/prefix for getting to the websocket handler in Kodi's modified HTTP daemon.

Unfortunately, I don't have enough experience with either Kodi's codebase (and C++ in general) nor libmicrohttpd's API to pull this out of my hat.

I did arrive at an alternative solution, however.

Alternative, hackier solution

If the above is too much of a change to be coordinated in too many places, one could achieve a similarly clean setup when involving an external HTTP proxy server, but would need to teach Chorus2 an additional trick to make it work smoothly and transparently in all cases.

Right now, the Websockets host setting accepts a magic value of auto, that will make Chorus2 assume the UA's current HTTP origin hostname as the hostname for the websocket connection, too. If the Websocket port setting would accept a similar magic value to make it assume the same TCP port as the current HTTP(S) port, a reverse proxy configuration like the below for caddy would always lead to the expected result of working websockets, as long as Chorus2 is configured to use the same websockets port as the current HTTP(S) port is used to serve it via the proxy instance:

{
        debug
        on_demand_tls {
                interval 60s
                burst 2
        }
}

:80 :443 {
        tls internal {
                on_demand
        }
        @websockets {
                header Connection *Upgrade*
                header Upgrade    websocket
        }
        reverse_proxy @websockets 127.0.0.1:9090
        reverse_proxy * 127.0.0.1:8090
}

Of course, Chorus2 would also have to inherit whether or not the connection is supposed to negotiate TLS from the protocol/scheme of the HTTP(S) origin it is being served from.

For this example to work, the caddy instance (configured with the snippet above saved as its Caddyfile) will have to run on the same host as Kodi does, with Kodi's webserver having been reconfigured to listen on TCP port 8090 instead of TCP Port 80.

Demo / PoC

To conveniently try this yourself on a LibreELEC box (tested on 11.0 on a Raspberry Pi 4 only, but I think it should work on any aarch64 or amd64 host running LE 10 or later), you may want to configure Kodi as described above (Webserver binding to Port 8090) and use this script to bootstrap caddy with a suitable config:

#!/bin/sh
LC_ALL=C
TZ=UTC
set -x
set -u
umask 0077
dir="${CADDYDIR:-/tmp/caddy-proxy-test}"
ver="${CADDYVER:-2.6.4}"

mkdir -p "${dir}"
cd "${dir}" || exit 1

case "$(uname -m)" in
  amd64)
    arch=amd64
  ;;
  aarch64)
    arch=arm64
  ;;
  *)
    echo "FATAL - Unexpected CPU arch - sorry." >&2
    exit 1
  ;;
esac

if ! netstat -ntlp | awk '/.*/{if($4 ~ /:(443|80)$/){exit 1}}'
then
  echo "FATAL - You already have listeners on TCP Port 80 and/or 443. Please stop/reconfigure these." >&2
  exit 1
fi

if netstat -ntlp | awk -v s=1 '/kodi.bin$/{if($4 ~ /:8090$/){s=0}} END{exit s}' >/dev/null
then
  : OK, Kodi on Port 8090
else
  echo "FATAL - Please configure Kodi's internal webserver (for Chorus2) to listen on TCP Port 8090." >&2
  exit 1
fi

: Downloading Caddy release
curl --fail -o ./caddy.tar.gz -L 'https://github.com/caddyserver/caddy/releases/download/v'"${ver}"'/caddy_'"${ver}"'_linux_'"${arch}"'.tar.gz'

: Extracting caddy executable
tar xzf caddy.tar.gz || exit 1

cat >Caddyfile <<EOF
{
        debug
        on_demand_tls {
                interval 60s
                burst 2
        }
}

:80 :443 {
        tls internal {
                on_demand
        }
        @websockets {
                header Connection *Upgrade*
                header Upgrade    websocket
        }
        reverse_proxy @websockets 127.0.0.1:9090
        reverse_proxy * 127.0.0.1:8090
}
EOF

chmod +x caddy || exit 1

: Executing caddy, serving HTTP and HTTPS, with Caddyfile from ${PWD} ...
: Hit Ctrl+C to stop.
exec ./caddy run

After that, make sure to set Chorus2's Websocket host to "auto", and to match the "Websocket port" to the HTTP(S) port you use (that is, either 80 or 443) to access the caddy reverse proxy.

(Please note that the Caddyfile used enables production-unsafe use of dynamic TLS certificate minting. Do not use this verbatim if the resulting caddy instance is available on a non-private network!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests