V2: cors problems when reverse proxying to ssh tunnel

1. My Caddy version (caddy version):

FROM caddy/caddy:alpine

2. How I run Caddy:

docker-compose up

a. System environment:

FROM caddy/caddy:alpine

b. Command:

paste command here

c. Service/unit/compose file:

paste full file contents here

d. My complete Caddyfile or JSON config:

{	
    email   mail@gmail.com
    # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

translatum.xyz {
    respond "let the neurons flow - translatum.xyz!"
}

# perception studies
perception.translatum.xyz {
    reverse_proxy {
        to perceptionist:8888
    }
}


glio.translatum.xyz {
    reverse_proxy {
        to bratsstarz:80
    }
}


pneumonia.translatum.xyz {
    reverse_proxy {
        to pneustarz:80
    }
}


# kraken
corona.translatum.xyz {
    reverse_proxy {
        to coronakraken:80
    }
}

kraken.translatum.xyz {
    respond "high 8 - long live the kraken on translatum.xyz!"
}

corona.kraken.translatum.xyz {
    reverse_proxy {
        to http://dockerhost:8080
    }
}

redis.kraken.translatum.xyz {
    reverse_proxy {
        to http://dockerhost:6379
    }
}

python.kraken.translatum.xyz {
    reverse_proxy {
        to http://dockerhost:8889
    }
}

upload.kraken.translatum.xyz {
    reverse_proxy {
        to http://dockerhost:3020
    }
}

3. The problem I’m having:

I am trying to setup an upload via an ssh-tunnel aka. dockerhost in my caddy file. the ssh-tunnel works but I am running into CORS issues (see error msgs).

4. Error messages and/or full log output:

browser console

Access to XMLHttpRequest at 'http://upload.kraken.translatum.xyz/corona-upload/96f4148e73058a9367cc2fb518482834' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

caddy

percy            | {"level":"error","ts":1585937612.8092902,"logger":"http.log.error","msg":"read tcp 172.25.0.2:48266->172.25.0.1:3020: read: connection reset by peer","request":{"method":"HEAD","uri":"/admin/files/admin/css/custom.css","proto":"HTTP/1.1","remote_addr":"23.254.229.202:41280","host":"upload.kraken.translatum.xyz","headers":{"Accept-Encoding":["gzip, deflate"],"Accept":["*/*"],"Connection":["keep-alive"],"User-Agent":["python-requests/2.18.4"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"","proto_mutual":true,"server_name":"upload.kraken.translatum.xyz"}},"status":502,"err_id":"vh29rf74u","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:363)"}
percy            | {"level":"error","ts":1585937612.906564,"logger":"http.log.error","msg":"read tcp 172.25.0.2:48272->172.25.0.1:3020: read: connection reset by peer","request":{"method":"HEAD","uri":"/app/lib/pics/glaesses_not.svg","proto":"HTTP/1.1","remote_addr":"23.254.229.202:41282","host":"upload.kraken.translatum.xyz","headers":{"User-Agent":["python-requests/2.18.4"],"Accept-Encoding":["gzip, deflate"],"Accept":["*/*"],"Connection":["keep-alive"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"","proto_mutual":true,"server_name":"upload.kraken.translatum.xyz"}},"status":502,"err_id":"f3pc17n0i","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:363)"}
percy            | {"level":"error","ts":1585937613.0103903,"logger":"http.log.error","msg":"read tcp 172.25.0.2:48278->172.25.0.1:3020: read: connection reset by peer","request":{"method":"HEAD","uri":"/office365/logs.txt","proto":"HTTP/1.1","remote_addr":"23.254.229.202:41284","host":"upload.kraken.translatum.xyz","headers":{"Accept-Encoding":["gzip, deflate"],"Accept":["*/*"],"Connection":["keep-alive"],"User-Agent":["python-requests/2.18.4"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"","proto_mutual":true,"server_name":"upload.kraken.translatum.xyz"}},"status":502,"err_id":"s7y65ejbu","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:363)"}
percy            | {"level":"error","ts":1585937613.1078727,"logger":"http.log.error","msg":"read tcp 172.25.0.2:48296->172.25.0.1:3020: read: connection reset by peer","request":{"method":"HEAD","uri":"/bocah/","proto":"HTTP/1.1","remote_addr":"23.254.229.202:41286","host":"upload.kraken.translatum.xyz","headers":{"User-Agent":["python-requests/2.18.4"],"Accept-Encoding":["gzip, deflate"],"Accept":["*/*"],"Connection":["keep-alive"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"","proto_mutual":true,"server_name":"upload.kraken.translatum.xyz"}},"status":502,"err_id":"k0r8zdp22","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:363)"}
percy            | {"level":"error","ts":1585937613.213589,"logger":"http.log.error","msg":"read tcp 172.25.0.2:48306->172.25.0.1:3020: read: connection reset by peer","request":{"method":"HEAD","uri":"/admin/","proto":"HTTP/1.1","remote_addr":"23.254.229.202:41288","host":"upload.kraken.translatum.xyz","headers":{"User-Agent":["python-requests/2.18.4"],"Accept-Encoding":["gzip, deflate"],"Accept":["*/*"],"Connection":["keep-alive"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"","proto_mutual":true,"server_name":"upload.kraken.translatum.xyz"}},"status":502,"err_id":"h4jsysbh1","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:363)"}

5. What I already tried:

At perception.translatum.xyz I run another upload server which works fine. If I copy the same server to the tunnel machine it does not work anymore because of CORS.

the front-end located at corona.translatum.xyz which runs on the front-end server is not able to upload to upload.kraken.translatum.xyz. I switched from an node-express xhr upload server to tusd for TUS uploads but it still does not work. Also when I use the identical front-end located on corona.kraken.translatum.xyz which runs on the backend server for testing purposes it won’t connect to the upload server.

6. Links to relevant resources:

Unfortunately outdated.

The browser is trying to see if it’s allowed to connect to http://upload.kraken.translatum.xyz from http://127.0.0.1:8080. Caddy is replying with a redirect to HTTPS, which isn’t accepted by clients for CORS. The client should be changed to connect to the https:// URL instead. (And then your server should probably still set some CORS headers to allow it.)

Interesting this is the content of my .env files:
VUE_APP_UPLOAD_URL=https://upload.kraken.translatum.xyz/corona-upload/

how can set I the correct headers in v2?

The change to access HTTPS needs to be made client-side.

You can set headers on the server using the header directive: header (Caddyfile directive) — Caddy Documentation

hmm now I am getting this error after rebuilding the docker…without changing the upload url client side:
Access to XMLHttpRequest at 'https://upload.kraken.translatum.xyz/corona-upload' from origin 'https://corona.translatum.xyz' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Thanks for the links to header directive, I also had a look before, but I am too puzzled and to clueless about cors…how should I actually implement this in my caddy file? Do you have a more practical example?

It depends on what your requirements are. I would suggest learning about CORS, it’s a great security feature of the modern Web! Cross-Origin Resource Sharing (CORS) - HTTP | MDN (Unfortunate that it is needed, but great anyways. Mostly.)

I read through it already two days ago. Hmm I am quite confident that the main missing setting is something along the lines of…

cors / {
  origin            https://corona.translatum.xyz https://corona.kraken.translatum.xyz # both allowed origins in one line?
  origin            https://corona.translatum.xyz # / or each origin listed separately?
  origin            https://corona.kraken.translatum.xyz # second allowed origin?
  methods           POST,PUT # which method is the right one for.a tusd upload server?
  allow_credentials false # should I set this to TRUE or false for tusd upload servers?
}

…in caddy v1 syntax. Due to lack of examples I struggle to convert this in caddy v2 syntax.

upload.kraken.translatum.xyz {
    reverse_proxy {
        to http://dockerhost:3020
        header * {
            origin            https://corona.translatum.xyz https://corona.kraken.translatum.xyz # both allowed origins in one line?
            methods           POST,PUT # which method is the right one for.a tusd upload server?
            allow_credentials false # should I set this to TRUE or false for tusd upload servers?
        } 
    }
}

I think a very verbose example of a caddyfile with various common settings enabled is something I and many other users could profit from.

1 Like

My caddyfile looks now like this:


upload.kraken.translatum.xyz {
    header {
            origin            https://corona.translatum.xyz https://corona.kraken.translatum.xyz # both allowed origins in one line?
            methods           GET, POST, PUT, OPTIONS # which method is the right one for.a tusd upload server?
            allow_credentials true # should I set this to TRUE or false for tusd upload servers?
    } 
    reverse_proxy {
        to http://dockerhost:3020
  
    }
}

the uploads are sent to https://upload.translatum.xyz - I double checked.

now I get the following error message:

Mixed Content: The page at '<URL>' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint '<URL>'. This request has been blocked; the content must be served over HTTPS.
upload.js:636 Mixed Content: The page at 'https://corona.translatum.xyz/#/upload' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://upload.kraken.translatum.xyz/corona-upload/607d5f570800056defda7c8bc3b6f7f9'. This request has been blocked; the content must be served over HTTPS.
(anonymous) @ upload.js:636
value @ source.js:54
value @ upload.js:620
value @ upload.js:584
t.onload @ upload.js:420
load (async)
value @ upload.js:387
(anonymous) @ upload.js:254
value @ storage.js:49
(anonymous) @ upload.js:244
(anonymous) @ getFingerprint.js:26
value @ upload.js:237
(anonymous) @ upload.js:137
t.getSource @ source.js:192
value @ upload.js:129
(anonymous) @ index.js:279
t._call @ RateLimitedQueue.js:25
t.run @ RateLimitedQueue.js:107
(anonymous) @ index.js:277
n.upload @ index.js:205
(anonymous) @ index.js:691
n.uploadFiles @ index.js:682
n.handleUpload @ index.js:717
(anonymous) @ index.js:1625
Promise.then (async)
(anonymous) @ index.js:1603
t._runUpload @ index.js:1597
(anonymous) @ index.js:1743
Promise.then (async)
t.upload @ index.js:1723
startUpload @ index.js:38
w @ preact.esm.js:308
upload.js:528 Mixed Content: The page at 'https://corona.translatum.xyz/#/upload' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://upload.kraken.translatum.xyz/corona-upload/607d5f570800056defda7c8bc3b6f7f9'. This request has been blocked; the content must be served over HTTPS.

So now, the preflight check goes through successfully, then tusd sends an upload links which is unfortunately http. If we intercept this request with burpsuite and send back an https link instead everything seems to work.

At this stage we are not sure whether is is a caddy or a tusd problem. Is there a way to tell caddy that these answer packages should contain https targets?

we made some progress with, now requests seem to go through

upload.kraken.translatum.xyz {
    header {
            origin            https://corona.translatum.xyz https://corona.kraken.translatum.xyz # both allowed origins in one line?
            methods           HEAD, GET, POST, PUT, OPTIONS, PATCH # which method is the right one for.a tusd upload server?
            allow_credentials true # should I set this to TRUE or false for tusd upload servers?
            # header_up         X-Forwarded-Proto https
            # header_down       X-Forwarded-Proto https 
            # request_header    +X-Forwarded-Proto https
    } 
    reverse_proxy {
        header_up         X-Forwarded-Proto https
        header_down       X-Forwarded-Proto https 
        to http://dockerhost:3020
    }
}
1 Like

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