Serve ports through URL using lighttpd

Settings and goal

On a raspberry pi, I'm running a Lighttpd server (version: lighttpd/1.4.53 (ssl)). This server was initially installed by pi-hole, a DNS I'm starting to use to manage my network. I already managed to associate http://raspi.home to my raspberry pi IP.

This device already runs several services, for instance an R-shiny server on port 3838 and a homeassistant installation on port 8123, that I can thus access through http://raspi.home:3838/ and http://raspi.home:8123 respectively.

My goal is now to be able to access my services through user-friendly addresses, such as http://raspi.home/shiny (port 3838) and http://raspi.home/homeassistant (port 8123).

Since the lighttpd server was configured for pi-hole, /var/www/html/ contains only two folders: "pihole" and "admin". I can access pi-hole admin panel through http://raspi.home/admin and http://raspi.home/pihole is accessible but not of much use.

My goal is to make that browsing http://raspi.home/shiny/... serves http://raspi.home:3838/... (and same for homeassistant).

Advance so far

I'm modifying /etc/lighttpd/external.conf, which adds on /etc/lighttpd/lighttpd.conf (code here). I tried various things but lighttpd conf files are quite confusing to me, and I'm never sure what should I put at the root level or in a $HTTP["url"].

What worked the most so far was adding an URL mapping with the server definition:

$HTTP["url"] =~ "^/shiny" {
    proxy.header = (
        "map-urlpath" => ( "/shiny" => "/" ),
        "upgrade" => "enable"
    )
    proxy.server = ( "" => ( ( "host" =>  "localhost", "port" => 3838) ) )
}

Unfortunately, this changed all the relative URLs as well so that any image in http://raspi.home/shiny/index.html is searched in http://raspi.home/images/image.png instead of http://raspi.home/shiny/images/image.png. Therefore, no resource could be found.

If I remove the condition, the mapping is global so the app is usable, but since everything is mapped all other sites are now unusable. This is described in this bug but I couldn't make the solution provided work.

I tried with "map-urlpath" => ( "/shiny(.*)$" => "/$1" ) but inexpectedly this throws a 404 error (with or without the condition).

resources

Here are more resources that might be related/useful:

  • Proxy URL to different port via Lighttpd
  • Lighttpd proxy redirect by port
  • https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModProxy
  • https://redmine.lighttpd.net/boards/2/topics/1946 (redirection worked though)
  • Rewrite URL before passing to proxy Lighttpd
  • https://redmine.lighttpd.net/boards/2/topics/8322

They didn't work for me, either because I didn't put the code on the right place or not adapted to my case, who knows...


$HTTP["url"] =~ "^/shiny" {
    proxy.server = ( "" => ( ( "host" =>  "192.168.1.138", "port" => 3838 ) ) )
}

Delete proxy.header until you better understand what it does and does not do.

https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModProxy

proxy.header "map-urlpath" will modify the request-line of the HTTP headers, but lighttpd does not rewrite the response body, so your R-shiny server will have to understand it is rooted under /shiny/. I have not looked at R-shiny to see if that is possible.

A different alternative is to create DNS names shiny.raspi.home and homeassistant.raspi.home, which you can then configure lighttpd to reverse proxy

$HTTP["host"] =~ "shiny.raspi.home" {
    proxy.server = ( "" => ( ( "host" =>  "192.168.1.138", "port" => 3838 ) ) )
}

Please note that I changed the target "port" in my examples above, as I am guessing that is the reverse-proxy target host and port to which you would like lighttpd to reverse-proxy the request to http://shiny.raspi.home/