CSS not loading with rewrite

1. Caddy version (caddy version):

v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

2. How I run Caddy:

a. System environment:

Fedora 34, Docker version 20.10.6, build 370c289, Portainer 2.1.1, slothcroissant/caddy-cloudflaredns container.

b. Command:

Managing containers with Portainer.

c. Service/unit/compose file:

   docker run -it --name caddy \
     -p 80:80 \
     -p 443:443 \
     -v caddy_data:/data \
     -v caddy_config:/config \
     -v $PWD/Caddyfile:/etc/caddy/Caddyfile \
     -e CLOUDFLARE_EMAIL=my email \
     -e CLOUDFLARE_API_TOKEN=my token \
     -e ACME_AGREE=true \
     slothcroissant/caddy-cloudflaredns 

Moved Caddyfile to /srv afterwards.

d. My complete Caddyfile or JSON config:

www.domain.com domain.com {
        tls email {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        }

        reverse_proxy HOSTIP:PORT {
        }
}

mobile.domain.com {
        tls email {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        }

        rewrite * /mobile{uri}
        reverse_proxy HOSTIP:PORT {
        }
}

3. The problem I’m having:

I have a site with two pages running in Docker. The first page is available at HOSTIP:PORT, and the other HOSTIP:PORT/mobile.

With Caddy they’re also available at domain.com and domain.com/mobile.

What I want to do is make the mobile page available at the mobile sub domain.

The problem is that the CSS does not work at mobile.domain.com, and seems to be trying to get the .css from mobile.domain.com/mobile.css instead of domain.com/mobile.css.

4. Error messages and/or full log output:

“Refused to apply style from ‘https://mobile.domain.com/mobile.css’ because its MIME type (‘text/html’) is not a supported stylesheet MIME type, and strict MIME checking is enabled.”

5. What I already tried:

I tried the rewrite which gets me to the right site, but with the CSS issue. I tried hardcoding using “domain.com/mobile.css” as the CSS, but it only worked temporarily.

6. Links to relevant resources:

Howdy @Howdy!

At a glance the only difference between the two sites I can see, with respect to communication between Caddy and the upstream, is likely the Host header itself (which is passed through from the client).

Is the upstream server configured to accept and respond for any value of Host? i.e. for the two examples:

Client’s request to Caddy → Caddy’s request to upstream
domain.com/mobile/mobile.cssdomain.com/mobile/mobile.css
mobile.domain.com/mobile.cssmobile.domain.com/mobile/mobile.css

Does the upstream treat both of the final results as the same?

One way to help debug this would be to use the debug global option and investigate the log output. Caddy will output the details of the request it received from your client as well as the request it made to the upstream server, and the upstream server’s response. You can also try replicate those requests with curl to inspect how the upstream server is responding.

If you can’t fix the upstream to permit the other Host, you can configure Caddy to alter the Host header before it sends it upstream with the header_up subdirective for reverse_proxy.

reverse_proxy (Caddyfile directive) — Caddy Documentation

1 Like

Hey @Whitestrake, thanks for the tips!

I’m not sure, the CSS is at domain.com/mobile.css, but both mobile.domain.com/mobile.css and domain.com/mobile/mobile.css give Cannot GET /mobile/mobile.css.

I’m running with debug, but I can’t say that anything jumps out at me. The requests return status 200, and I can’t see any sort of errors.

2021/05/17 10:12:06.530	DEBUG	http.handlers.reverse_proxy	upstream roundtrip	{"upstream": "LOCALSERVERIP:PORT", "request": {"remote_addr": "162.158.134.47:44792", "proto": "HTTP/1.1", "method": "GET", "host": "www.domain.com", "uri": "/", "headers": {"Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Sec-Fetch-Mode": ["navigate"], "Sec-Fetch-User": ["?1"], "Sec-Gpc": ["1"], "Cf-Request-Id": ["0a1b68d0d6000010b9d3164000000001"], "Cf-Visitor": ["{\"scheme\":\"https\"}"], "Sec-Ch-Ua-Mobile": ["?0"], "Cf-Connecting-Ip": ["MYIP"], "Accept-Encoding": ["gzip"], "X-Forwarded-For": ["MYIP, 162.158.134.47"], "Cf-Ray": ["650c10c7bb1c10b9-CPH"], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Site": ["none"], "Sec-Fetch-Dest": ["document"], "Dnt": ["1"], "Cdn-Loop": ["cloudflare"], "Cf-Ipcountry": ["SE"], "X-Forwarded-Proto": ["https"], "Sec-Ch-Ua": ["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\""], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"], "Accept-Language": ["en-US,en;q=0.9,sv;q=0.8,an;q=0.7"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "proto_mutual": true, "server_name": "www.domain.com"}}, "duration": 0.017973188, "headers": {"Connection": ["keep-alive"], "Keep-Alive": ["timeout=5"], "X-Powered-By": ["Express"], "Content-Type": ["text/html; charset=utf-8"], "Content-Length": ["78335"], "Etag": ["W/\"131ff-7jULV5BSLFRDea5Z887IcJpuGj4\""], "Date": ["Mon, 17 May 2021 10:12:06 GMT"]}, "status": 200}

2021/05/17 10:12:06.663	DEBUG	http.handlers.reverse_proxy	upstream roundtrip	{"upstream": "LOCALSERVERIP:PORT", "request": {"remote_addr": "162.158.134.105:48828", "proto": "HTTP/1.1", "method": "GET", "host": "www.domain.com", "uri": "/favicon.ico", "headers": {"Sec-Fetch-Site": ["same-origin"], "Sec-Fetch-Mode": ["no-cors"], "Cf-Request-Id": ["0a1b68d16e000010b9c8058000000001"], "Cf-Ray": ["650c10c8ad9d10b9-CPH"], "Accept-Language": ["en-US,en;q=0.9,sv;q=0.8,an;q=0.7"], "Accept-Encoding": ["gzip"], "X-Forwarded-For": ["MYIP, 162.158.134.105"], "X-Forwarded-Proto": ["https"], "Cf-Visitor": ["{\"scheme\":\"https\"}"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"], "Sec-Fetch-Dest": ["image"], "Referer": ["https://www.domain.com/"], "Sec-Gpc": ["1"], "Cf-Connecting-Ip": ["MYIP"], "Cdn-Loop": ["cloudflare"], "Cf-Ipcountry": ["SE"], "Sec-Ch-Ua": ["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\""], "Sec-Ch-Ua-Mobile": ["?0"], "Accept": ["image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"], "Dnt": ["1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "proto_mutual": true, "server_name": "www.domain.com"}}, "duration": 0.005289849, "headers": {"Accept-Ranges": ["bytes"], "Cache-Control": ["public, max-age=0"], "Last-Modified": ["Wed, 12 May 2021 07:43:27 GMT"], "Content-Length": ["15406"], "Connection": ["keep-alive"], "X-Powered-By": ["Express"], "Etag": ["W/\"3c2e-1795f87d136\""], "Content-Type": ["image/x-icon"], "Date": ["Mon, 17 May 2021 10:12:06 GMT"], "Keep-Alive": ["timeout=5"]}, "status": 200}

2021/05/17 10:12:11.953	DEBUG	http.handlers.rewrite	rewrote request	{"request": {"remote_addr": "162.158.134.73:44712", "proto": "HTTP/1.1", "method": "GET", "host": "mobile.domain.com", "uri": "/", "headers": {"Cf-Ipcountry": ["SE"], "Sec-Fetch-User": ["?1"], "Sec-Fetch-Dest": ["document"], "Connection": ["Keep-Alive"], "Accept-Encoding": ["gzip"], "Cf-Visitor": ["{\"scheme\":\"https\"}"], "Sec-Fetch-Site": ["none"], "Sec-Ch-Ua": ["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\""], "Sec-Ch-Ua-Mobile": ["?0"], "Sec-Gpc": ["1"], "X-Forwarded-For": ["MYIP"], "Cf-Ray": ["650c10e9c96310b9-CPH"], "X-Forwarded-Proto": ["https"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"], "Cf-Connecting-Ip": ["MYIP"], "Cdn-Loop": ["cloudflare"], "Cf-Request-Id": ["0a1b68e61e000010b9ef98f000000001"], "Upgrade-Insecure-Requests": ["1"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Sec-Fetch-Mode": ["navigate"], "Accept-Language": ["en-US,en;q=0.9,sv;q=0.8,an;q=0.7"], "Dnt": ["1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "proto_mutual": true, "server_name": "mobile.domain.com"}}, "method": "GET", "uri": "/mobile/"}

2021/05/17 10:12:11.968	DEBUG	http.handlers.reverse_proxy	upstream roundtrip	{"upstream": "LOCALSERVERIP:PORT", "request": {"remote_addr": "162.158.134.73:44712", "proto": "HTTP/1.1", "method": "GET", "host": "mobile.domain.com", "uri": "/mobile/", "headers": {"X-Forwarded-For": ["MYIP, 162.158.134.73"], "Cf-Ray": ["650c10e9c96310b9-CPH"], "X-Forwarded-Proto": ["https"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"], "Sec-Ch-Ua-Mobile": ["?0"], "Sec-Gpc": ["1"], "Upgrade-Insecure-Requests": ["1"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"], "Sec-Fetch-Mode": ["navigate"], "Accept-Language": ["en-US,en;q=0.9,sv;q=0.8,an;q=0.7"], "Dnt": ["1"], "Cf-Connecting-Ip": ["MYIP"], "Cdn-Loop": ["cloudflare"], "Cf-Request-Id": ["0a1b68e61e000010b9ef98f000000001"], "Cf-Ipcountry": ["SE"], "Sec-Fetch-User": ["?1"], "Sec-Fetch-Dest": ["document"], "Accept-Encoding": ["gzip"], "Cf-Visitor": ["{\"scheme\":\"https\"}"], "Sec-Fetch-Site": ["none"], "Sec-Ch-Ua": ["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\""]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "proto_mutual": true, "server_name": "mobile.domain.com"}}, "duration": 0.012159386, "headers": {"Content-Length": ["19997"], "Etag": ["W/\"4e1d-mUMe56W9CDwdGWDE/ewXVuUHfiY\""], "Date": ["Mon, 17 May 2021 10:12:11 GMT"], "Connection": ["keep-alive"], "Keep-Alive": ["timeout=5"], "X-Powered-By": ["Express"], "Content-Type": ["text/html; charset=utf-8"]}, "status": 200}

Tried disabling the Cloudflare proxy, but that showed the same lack of CSS.

Is changing the headers the way to go?

What I gather from this is that, actually, we just need to not rewrite to prepend this base path for requests specifically to /mobile.css.

We can do this quite easily with named matchers, e.g.

@notMobileCSS not path /mobile.css
rewrite @notMobileCSS /mobile{uri}

See: Request matchers (Caddyfile) — Caddy Documentation

More modification might be required if there’s more than one static asset that needs to be excluded from the rewrite.

2 Likes

Thanks a lot, that sorted it! :smiley:

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