I'm trying to translate this simple nginx configuration (taken from the app documentation, see here) into a Caddyfile:
NGINX version:
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
location /rstudio/ {
rewrite ^/rstudio/(.*)$ /$1 break;
proxy_pass http://localhost:8787;
proxy_redirect http://localhost:8787/ $scheme://$host/rstudio/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 20d;
}
My Caddyfile:
myserver.com
redir localhost:8787 {scheme}://{host}/rstudio 302
proxy /rstudio localhost:8787 {
without /rstudio
}
But this Caddyfile, rather than proxy-ing in to the application running on localhost of port 8787, literally redirects my browser to point to it's own localhost. Not sure where I've gone wrong; the nginx is a bit opaque to me (though it works just fine). Any suggestions?
Are you getting redirected to http://localhoslt/rstudio ?
I'm getting redirected to http://localhost:8787
If it helps to debug, the app is dockerized, so this behavior should be relatively straight-forward to reproduce if you have docker installed. e.g. just run: docker run -d -p 127.0.0.1:8787:8787 rocker/rstudio to get the app running on localhost, and then run the above Caddyfile (with appropriate hostname) and I think you should see what I see...
Alright. Got my hands tied right now but hopefully before end of the day (if someone else hasn't come around).
This line is what is causing your redirect:
redir localhost:8787 {scheme}://{host}/rstudio 302
But this line in nginx conf causes a rewrite:
rewrite ^/rstudio/(.*)$ /$1 break;
So, you want a rewrite, which changes the URL internally but doesn't issue a response. Basically this rewrite just strips rstudio from the URL.
Actually j/k, just get rid of the redir entirely in your Caddyfile, see if that works. (because you have the without line in your proxy directive)
@mholt thanks, I really appreciate your help in debugging this.
I tried dropping the redir but no luck, that still forwards me to the http://localhost:8787
Right, like you say, my reading was that the without was doing the same thing as rewrite. Interestingly, if I drop the without and the redir command, so I just have proxy /rstudio localhost:8787, then I get an "Input/output error" (which I do think comes from the app, as expected).
I also tried using the Caddy rewrite instead of without:
proxy /rstudio localhost:8787
rewrite {
regexp ^/rstudio/(.*)
to /
}
That doesn't go to http://localhost:8787, but throws the same error as it does with the proxy line alone.
I tried testing without the need for any rewrite to see if I could run it on root, using only the line:
proxy / localhost:8787
in the Caddyfile. And that sends me to http://localhost:8787....
So I'm stuck. In the nginx, I see the rewrite and redir clauses are placed within the location clause, but in caddy they are outside the proxy clause; guess that's not an issue since they declare the location explicitly. Were you able to give it a whirl with docker and a test server?
I'm not convinced Caddy is redirecting without that redir line. Check your app or your browser cache or at least the Network tab in the inspector tools to see what's really going on.
@mholt hmm, tried all that, still persists.
I've cleared the browser cache & all associated history, and have also tried switching to another domain name to avoid any caching that might exist between my computer and the server. I've reset the app. No luck.
It seems like the app itself is responsible for returning its localhost:8787 call instead of the server address, and I suppose the nginx code's "redirect" line is introduced to address that? For instance, if I curl -L https://example.com/rstudio, I get the expected error message from the app saying "your browser is not supported". Only in a real browser does the app end up directing to localhost...
@cboettig maybe you need add proxy_header Host {host} in proxy section.
^ That's possible.
Strange that the app insists on forwarding like that. You can confirm this by looking at the Network tab of your browser's inspector tools - even a screenshot or two of the requests and the response headers might be useful. But try @novaeye's suggestion and see what happens.
@novaeye Thanks, that pretty much does it! With one problem. When hosting from root, all I need is this:
example.com
proxy / localhost:8787 {
proxy_header Host {host}
}
Hosting from the /app sub-directory, I add without /app and append /app to Host:
proxy /app localhost:8787 {
without /app
proxy_header Host {host}/app
}
and it almost works, except that I need to go to https://example.com/app/ with the explicit trailing slash; https://example.com/app doesn't work.
This appears to be because the app loads a page looking for javascript at src="rstudio/rstudio.nochache.js". If the browser URL has the trailing slash, https://example.com/app/, then that relative URL corresponds to: https://example.com/app/rstudio/rstudio.nocache.js and all is well. But if the browser URL does not have the trailing slash, then the full URL of the javascript is missing the "app" part https://example.com/rstudio/rstudio.nocache.js and thus cannot be loaded. Not quite sure how to get around this. I tried proxy_header Host {host}/app/ but that doesn't make a difference.
This hack could work
redir /app /app/
@abiosoft Thanks, that works for me.
Incidentally, Caddy won't let me write a redir command without also giving a code (running v0.8), so I needed: redir /app /app/ 307 or I get the error Parse error: Invalid redirect code '/app/'
Thanks everyone for all the help, much appreciated and happy to have this all working nicely now!
Its my mistake. :)
Glad it worked in the end.
I was having this same issue. novaeye's solutions didn't help, but using transparent did the trick.
Just in case someone else google's their way over here.
transparent doesn鈥檛 work for me in Caddy 0.10.11, has there been a regression?
My Caddyfile is:
https://forum.ac.upt.ro:443 {
tls self_signed
proxy / http://www.ac.upt.ro/forum/ {
transparent
}
filter rule {
content_type text/html.*
search_pattern http://www.ac.upt.ro/forum
replacement "https://forum.ac.upt.ro"
}
filter rule {
content_type text/css.*
search_pattern http://www.ac.upt.ro/forum
replacement "https://forum.ac.upt.ro"
}
log ./access.log {
rotate_size 100
rotate_age 14
rotate_keep 10
}
errors ./error.log
}
It should reverse-proxy an upstream http://www.ac.upt.ro/forum/ to a new Caddy-served downstream https://forum.ac.upt.ro/
I鈥檝e setup a minimal index.php in http://www.ac.upt.ro/forum/:
<?php
if (isset($_GET['getnews']))
{
header("HTTP/1.1 302 Moved Temporarily");
header("Location: http://www.ac.upt.ro/forum/index.php?showtopic=2711&pid=149620&st=0&#entry149620");
exit;
}
if (isset($_GET['showtopic']))
{
exit("here's what's new..");
}
exit("try <a href='./?getnews'>?getnews</a> or <a href='./?showtopic'>?showtopic</a>");
?>
https://forum.ac.upt.ro/?showtopic works as expected.
But https://forum.ac.upt.ro/?getnews just serves directly the upstream reply from http://www.ac.upt.ro/forum/?getnews which has a hostnamed 302-redirect to http://www.ac.upt.ro/forum/index.php?showtopic=2711&pid=149620&st=0&#entry149620
I鈥檇 have expected the reply to be a transparent https://forum.ac.upt.ro/index.php?showtopic=2711&pid=149620&st=0&#entry149620
I can鈥檛 even find a workaround, something like a non-existing header_downstream Location {<Location{query}}{<Location{fragment}}.
@uptad0112 Caddy doesn't rewrite Location headers, if that's what you're asking for -- the application needs to redirect properly, i.e. it has to know it's behind a reverse proxy (this is true of most applications).
For further discussion, try asking on our forum, rather than 3-year-old closed issue: https://caddy.community
Apologies, I misunderstood from last year鈥檚 entry that the problem had been fixed by transparent.
Since my application is not proxy-aware, I鈥檝e subscribed to the #1639 rewrite, and await for proxy_redirect #606
Most helpful comment
I was having this same issue. novaeye's solutions didn't help, but using
transparentdid the trick.Just in case someone else google's their way over here.