Reload/rewrite to root on browser refresh, v2

My original post is locked but now that I’ve got v2 working I’m back to this issue

@francislavoie so my new v2 stanza is working except for this issue.

https://lights.kebler.net {
    import r53
    root * /opt/lights/web
    reverse_proxy /socket.io http://lights.net:3030
    rewrite not /socket.io/* /
    file_server
    }

there you mentioned rewrite I’ve tried a few things for V2 but keep getting

run: adapting config using caddyfile: parsing caddyfile tokens for 'rewrite': /opt/caddy/conf/lights.conf:22 - Error during parsing: Wrong argument count or unexpected line ending after '/socket.io/*'

It seems like rewrite is considering not as the matcher?? I’m not getting the syntax for not correct obvioiusly

Once I get that working I am thinking this might not solve my problem.
My SPA does use some (uri) routes so I can’t just rewrite everything to root always. I just need it to do that if user refreshes the browser or does initial visit to other than root (e.g. they bookmarked a subpath). So only on the first request. Not sure caddy can distinguish a first request (i.e. browser refresh) from user visiting other routes at the site. Maybe I don’t understand a SPA well but maybe it doesn’t make another request when changing routes in which case your suggestion should work.

Otherwise it’s something ugly in my code to trap the user clicking browser refresh and then route in my SPA back to root. https://stegosource.com/prevent-browser-refresh-url-changes-route-navigation-vue/

as I said when I run my dev server for this spa “refresh” is handled correctly. I mean it redirects to root reloading the entire spa and then the default route is loaded. But when I build for production and have caddy serve the build this issue comes up.

Hey David,

From the top of that page:

The matcher token can be one of these forms:

  1. * to match all requests (wildcard; default).
  2. /path start with a forward slash to match a request path.
  3. @name to specify a named matcher .

So, Caddy is probably not interpreting the not token as a matcher (and rightly so) – so it thinks you have 3 arguments, which is too many for rewrite.

You’ll need to use a named matcher to use not. The vast majority of matchers (among the various ones that are available) need to be named matchers. (But the vast majority of matchers used in practice are simply path or wildcard matchers, which is why they can also be inlined.)

Sorry that I misled you over a month ago, that was my bad :slight_smile:

this apparently worked although it broke serving the site so not 100% sure.

  @notsocket {
	   not path /socket.io/*
	 }
    rewrite @notsocket /

just so folks like me know not is not a “module” it is a modifier so

  @notsocket {
	   not /socket.io/*
	 }
    rewrite @notsocket /

does “not” work it needs a “module” according to error. Maybe the docs should put it not with the modules in this regard.

also the examples on this page seem missing

Not sure why you’re looking at the JSON docs if you’re using the Caddyfile. The matcher docs for Caddyfile are here:

This means "for any path that doesn’t match /socket.io/*, rewrite it to /. I’m not exactly sure what result you’re expecting, so you’ll need to elaborate. What paths should route to where? Can you give multiple examples to cover the usecases?

That’s what you/I intended (rewrite all to root) but this just isn’t going to work on a spa that has more than a single root route which mine does.

Caddy has no way of knowing if the user entered the site via other than the root or if they clicked refresh so no way to redirect to root under those circumstances (otherwise it should serve all routes normally). The site works fine except for those two situations.

I mean, there might be a way with try_files, but I still don’t have a clear idea of what paths should do what. I need some examples to be able to suggest anything! :stuck_out_tongue:

thx for continuing to try. I just don’t see the web server as the fix to this. All routes/paths should work as is except in the case of browser refresh or initial request. I don’t think caddy can distinguish those cases. I’ve asked in the quasar framework forum (the code that built the spa).

Well, no one helping me there. @francislavoie seems as though the quasar spa has special requirements of the web server that maybe Caddy is not meeting.

"Interaction with the single page application often involves dynamic communication with the web server behind the scenes."

Unfortunately they don’t explain what that is.

they do support two other web builds SSR

and PWA

maybe one of those two types can be served by Caddy?

There has got to be more than me coming up against this issue. Anyway I’ll try those but is there any other Caddy “way” of serving a site than with the file_server mode?

SPAs are usually pretty easy with Caddy (I’ve done it before, but every SPA has its own requirements, and as you noted, they don’t spell them out unfortunately). It usually involves try_files.

Judging by this nginx config the key is, again, try_files:

    location / {
        try_files $uri $uri/ /index.html;
    }

So in Caddy:

try_files {path} {path}/ /index.html

That’s probably minimally required; their nginx example has a few other things that might be good.

Notably, you’ll need to wrap that in a handle directive though, because you’re also using a reverse_proxy.

@matt actually just wrote a post that explains why that would be needed!

So I think your Caddyfile would look like this:

https://lights.kebler.net {
    import r53
    root * /opt/lights/web
    handle /socket.io/* {
        reverse_proxy http://lights.net:3030
    }
    handle {
        try_files {path} {path}/ /index.html
        file_server
    }
}
2 Likes

Could also be a route:

route {
    reverse_proxy /socket.io/* http://lights.net:3030
    try_files {path} {path}/ /index.html
    file_server
}

whatever floats your boat.

I usually like handle since it makes it clear that it’s one or the other.

2 Likes

That worked!! and the site serves SOO fast compared to dev server.
If we weren’t in a pandemic I’d kiss you guys!

Even if I had seen that nginx configuration there is no way I’d figured that out.

Thx again you both!
Now just nextcloud to figure out and I have a working v1 version.

3 Likes