Strip trailing slash in reverse proxy

I’m having some trouble setting up a fairly simple reverse proxy. The background is that I have my site hosted in GitHub pages (here) and I’d like to reverse proxy to that from my main domain. The docs used to be hosted somewhere else which allowed trailing slashes (e.g. https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started/ should show the same contents as https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started.html). I’m struggling to set this up.

1. Output of caddy version:

v2.5.2 h1:eCJdLyEyAGzuQTa5Mh3gETnYWDClo1LjtQm2q9RNZrs=

2. How I run Caddy:

Caddy is installed as a service in Ubuntu, with a Caddyfile config.

a. System environment:

OS: Ubuntu 20.04.5 LTS

d. My complete Caddy config:

My config comes in several parts, the actual Caddyfile is:

{
	email "admin@placeholder-software.co.uk"
}

import sites-enabled/*

There are several enabled sites, but only one is relevant:

placeholder-software.co.uk {

	# This block is not related to the issue (afaik)
	redir /discord https://discord.gg/8dKpP5W
	redir /dissonance/community https://www.reddit.com/r/dissonance_voip/
	redir /wetstuff/community https://www.reddit.com/r/WetStuff/
	handle_path /assetstore/package* {
		redir https://assetstore.unity.com/packages/slug/{uri}?aid=1100lJDF
	}
	handle_path /wetstuff/docs* {
		redir https://wetsurfacedecals.readthedocs.io/en/latest{uri}
	}
	handle_path /overcrowded/docs* {
		redir https://placeholder-software.github.io/Crowds{uri}
	}

	# This is the one that I'm having a problem with!
	handle_path /dissonance/docs* {
		rewrite * /Dissonance{uri}
		uri strip_suffix /
		reverse_proxy https://placeholder-software.github.io {
			header_up Host {upstream_hostport}
		}
	}

	root * /var/www/placeholder-software.co.uk
	file_server
	
	handle_errors {
		respond "{err.status_code} ({err.status_text})"
	}
}

3. The problem I’m having:

I would like this URL:

https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started/

To fetch the same content as this URL:

https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started

i.e. strip trailing slashes.

I would prefer it to be handled transparently in the reverse proxy, but I’d be ok with a redirect if that’s easier to setup!

Thanks in advance :slight_smile:

What exactly is the problem? Did you try that? What doesn’t work, specifically? What do you see in your logs? What does it look like when you make a request with curl -v?

Please don’t remove parts of the help topic template. All the parts are necessary for us to properly understand the problem and to have an idea how to help you.

Thanks for the fast response! Sorry I wasn’t clear about the problem.

What exactly is the problem?
What doesn’t work, specifically?

Fetching the site with a trailing slash delivers a broken version of the content, i’m not sure why. I suspect I’m simply not understanding something fundamental about how caddy does reverse_proxy.

Did you try that?

I did, in fact the Caddyfile I showed above is currently live. So you can see for yourself the site working at this URL (no trailing slash): https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started, but failing at this URL (trailing slash): https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started/

If you scroll past the hilariously large icons the correct content is there.

What does it look like when you make a request with curl -v?

Here is the complete response from curl -v https://placeholder-software.co.uk/dissonance/docs/Basics/Getting-Started/

What do you see in your logs?

The journalctl log for caddy has some log spam about https issuance errors (note this is for a different domain, not the one we’re talking about). e.g.

Sep 05 02:24:21 placeholder-software caddy[865]: {“level”:“error”,“ts”:1662341061.0472126,“logger”:“tls.issuance.acme”,“msg”:“looking up info for HTTP challenge”,“host”:“placeholder.software”,“error”:“no information found to solve challenge for identifier: placeholder.software”}
Sep 05 02:24:21 placeholder-software caddy[865]: {“level”:“error”,“ts”:1662341061.0484319,“logger”:“tls.issuance.acme”,“msg”:“looking up info for HTTP challenge”,“host”:“placeholder.software”,“error”:“no information found to solve challenge for identifier: placeholder.software”}

i.e. nothing relevant as far as I can tell.

1 Like

On closer inspection I think the issue is to do with the relative paths for css files and the reverse proxy is working fine. I was fixating on looking for the problem in the wrong place!

For example the html includes this: <link rel="stylesheet" href="../assets/stylesheets/main.69437709.min.css"> which explains why the content is there, but the styling is missing.

Given that, I think the easiest way to fix this will be to redirect if it has a trailing slash.

Something like:

handle_path /dissonance/docs* {
    if <has_trailing_slash> {
        redirect
    }
    else
    {
        rewrite * /Dissonance{uri}
        uri strip_suffix /
        reverse_proxy https://placeholder-software.github.io {
            header_up Host {upstream_hostport}
        }
    }
}

Obviously I just made that syntax up! What’s the correct way to do it?

Ah okay, so it seems like the problem is with loading CSS/JS assets for your site from that URL, the relative paths for those end up broken.

I think you probably want to do a redirect instead a rewrite to fix this, because the problem is with the browser not knowing the correct relative path for the assets because it uses ../ to go up a path segment, but the trailing / means there’s one too many path segments to get to the right place.

Instead of uri strip_suffix /, try this:

@trailing path_regexp trailing ^(.*)/$
redir @trailing /dissonance/docs{re.trailing.1} permanent

This’ll match the path with a regexp, capturing the whole URI except the slash, then redirect if it matches to a URL with the captured part. (Need to re-add /dissonance/docs because handle_path will have stripped it away).

2 Likes

That fixed it! Thankyou very much for your help :smiley:

2 Likes

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