Anyone have any luck with mixed-content / forcing HTTPS on proxy requests?

Trying to tie together Caddy with an Apache/AJP backend to forward requests. That seems to work fine: but the backend application is putting out occasional “http” content requests; they’re not all getting converted to https.

# Make sure HTTP goes to HTTPS
redir 301 {
     if {>X-Forwarded-Proto} is http
     /  https://{host}{uri}
}

# INTERNAL Proxy: pass to local Apache/AJP router
rewrite /external /internal
proxy /internal http://localhost:8080 {
    except {dir}/robots.txt
    transparent
}

Hi @unquietwiki, welcome to the Caddy community.

I’m wondering who the client is, exactly? Another proxy server? The backend server itself making requests of Caddy? I’m not sure I understand what your environment is supposed to do and who that redir is meant for.

Does that work, out of curiosity? I assumed only header_upstream and header_downstream could make use of placeholders.

Client is an Apache HTTPD 2.4.x instance on localhost, acting as an AJP/mod_jk access point for another backend server. I doubt Caddy will ever support AJP directly; nginx and lighttpd gave up on it a while ago.

That robots.txt thing seems to work: at least it returns the one I created, and not the one on the backend server.

I’m going to see if I can work with my bosses on modifying the return pages to not be http-only, but need a workaround if that doesn’t work. In testing on Firefox and Google developer tool mode, most responses come back as HTTP/2 secure, but the initial HTTP redirect on the “bad” document causes the whole thing to go into mixed mode.

OK, but you mention testing in Firefox and Chrome. Whoever the client is, they won’t get redirected unless they send an X-Forwarded-Proto: http header in the request. 99% of clients will have no reason to send this header, it’s usually only used by reverse proxies, so most requests won’t meet the requirement for the redirect to take place. You’d need to download an extension to get Firefox and Chrome to send them, since neither have inbuilt tools to specify request headers.

If I understood your request, I went ahead and tried to set Caddy to issue “X-Forwarded-Proto: http” requests instead of the normal {scheme} default provided by “transparent”. No dice on that. At this point I think it’s a hard-coded thing on the application end I’ll need to fix with my bosses.

I think one of us is misunderstanding the situation. This part of your Caddyfile:

redir 301 {
     if {>X-Forwarded-Proto} is http
     /  https://{host}{uri}
}

Is configuring Caddy not to redirect the client to HTTPS unless Caddy receives X-Forwarded-Proto: http from that client. It has nothing to do with what Caddy issues to the upstream servers. Your browser, or whatever is trying to access Caddy, needs to include that header - if Caddy doesn’t see the header, it won’t do any redirecting at all.

It’s a really weird statement, because setting X-Forwarded-Proto to http manually will cause a redirect loop. There’s basically no way accessing your website in a browser is going to functionally redirect HTTP requests to HTTPS with that Caddyfile. It’d only work if there was another server at the edge, handling TLS, and reverse proxying to Caddy (which then reverse proxies to Apache) - but that doesn’t seem likely to me…

And you’re saying that Apache is the client, which implies that Apache is at the edge, reverse proxying to Caddy, which is reverse proxying. I’m quite confused.

I was copying that from the documentation, trying to force HTTPS redirection; it seems by default port 80 and 443 are active on a site. Sorry about the confusion on that.

Logistically, the path of request is as follows: user → (HTTPS) → Caddy → (HTTP) → localhost Apache instance → (AJP) → backend

The issue I wish to resolve for this, and similar situations; is that part of the backend reply is an HTTP url; probably a fixed one. I was hoping “rewrite” or something could work to convert HTTP requests to HTTPS. But that probably requires some kind of HTML parsing module. Otherwise, it still looks like my boss and I will need to directly modify the original source to our ability.

No worries! Where’s that documented, by the way? It’s a pretty unconventional way to go about it, I wonder if it could be changed/clarified?

It’s a pretty common issue to have - the backend giving out links to HTTP sub-resources on a site that you want to serve over HTTPS. Unfortunately there’s no way to upgrade a connection on-the-fly from HTTP->S, you have to tell the client to back away and come back on another port with a HTTPS protocol. That said, I believe browsers do respect 301s for inline resources, so redir should work for page elements and it will definitely work fine for actual pages.

All that said, Caddy handles HTTP->S redirection automatically under certain circumstances. Perhaps your label block makes it ineligible. What’s your label block look like?

Assuming you can’t take advantage of Caddy’s Automatic HTTPS, you probably want to try this redir block instead of the one you have:

redir 301 {
  if {scheme} is http
  / https://{host}{uri}
}

{scheme} will return the actual protocol the client used to connect to Caddy; you can rely on it being set correctly for any given client.

Thanks @Whitestrake . I implemented your change, and then messed around some more with my Apache setup. http://grokbase.com/t/tomcat/users/108269a8jv/rewrite-urls-inside-html-pages had a buried answer at the bottom for the JK connector: I might do a writeup on that aspect when the dust settles, but was able to combine that with mod_substitute to rewrite the https as http (seems crazy, I know), and it seems to work.