Cloudflared HTTP2Origin Issue

Hey guys, just wondering if there's a solution to this issue I'm having accessing a grpc endpoint behind cloudflared: https://github.com/cloudflare/cloudflared/issues/682
GitHub
๐Ÿ› http2Origin option and --http2-origin ยท Issue #682 ยท cloudflare/c...
Describe the bug @nikr-canva I added the flag mentioned here to my docker container (version 2022.6.3). In the log Settings: map[http2-origin:true loglevel:debug no-autoupdate:true token:*] whi...
88 Replies
Chaika
Chaikaโ€ข10mo ago
I don't think so. It's also marked here: https://developers.cloudflare.com/network/grpc-connections/
Cloudflare Tunnel currently does not support gRPC.
Cloudflare Docs
gRPC connections ยท Cloudflare Network settings docs
Cloudflare offers support for gRPC to protect your APIs on any proxied gRPC endpoints. The gRPC protocol helps build efficient APIs with smaller โ€ฆ
Geospace
GeospaceOPโ€ข10mo ago
So I guess itโ€™s safe to assume this will never get fixed
Chaika
Chaikaโ€ข10mo ago
hmm, actually I was looking at another github issue and it looks like it might work over http2 not but quic https://github.com/cloudflare/cloudflared/issues/491#issuecomment-1643233485 try that if you need it
GitHub
grpc support ยท Issue #491 ยท cloudflare/cloudflared
Are there any plans/eta on supporting GRPC through cloudflared/argo tunnel?
Geospace
GeospaceOPโ€ข10mo ago
Oh, I did notice that quic is enabled in my cf dashboard, would disabling that fix it?
Chaika
Chaikaโ€ข10mo ago
no, you have to configure your tunnel to not use quic quic in your dashboard is unrelated
Geospace
GeospaceOPโ€ข10mo ago
Oh ok, so in my cloudflared config.yaml file?
Chaika
Chaikaโ€ข10mo ago
if you're using local tunnels could do that, or could modify the way you run the tunnel, ex: cloudflared tunnel --protocol http2 run <UUID or NAME>
Geospace
GeospaceOPโ€ข10mo ago
Ok great, Iโ€™ll give that a shot, thanks mate hmm ok i ran that command, but I'm seeing
ERR error="Incoming request ended abruptly: context canceled" cfRay=8520eefa2bdfaac1 event=1 ingressRule=2 originService=http://localhost:8080
ERR failed to serve incoming request error="Failed to proxy HTTP: Incoming request ended abruptly: context canceled"
ERR error="Incoming request ended abruptly: context canceled" cfRay=8520eefa2bdfaac1 event=1 ingressRule=2 originService=http://localhost:8080
ERR failed to serve incoming request error="Failed to proxy HTTP: Incoming request ended abruptly: context canceled"
in my cloudflared logs $ cloudflared tunnel --protocol http2 run my-app
Chaika
Chaikaโ€ข10mo ago
What do see when you started it up? On the line "Registered tunnel connection" -> something oh, grpc also isn't going to work over http, need https even if self-signed like in his example:
ingress:
- hostname: <hostname>
service: https://localhost:50051
originRequest:
noTLSVerify: true
http2Origin: true
ingress:
- hostname: <hostname>
service: https://localhost:50051
originRequest:
noTLSVerify: true
http2Origin: true
https://github.com/cloudflare/cloudflared/issues/491#issuecomment-1643233485
Geospace
GeospaceOPโ€ข10mo ago
nothing obviously wrong, all services look like this:
Registered tunnel connection connIndex=0 connection=a5be094-0c27-436f-9470-95a17edc00dd event=0 ip=<IP> location=<LOC> protocol=http2
Registered tunnel connection connIndex=0 connection=a5be094-0c27-436f-9470-95a17edc00dd event=0 ip=<IP> location=<LOC> protocol=http2
hmm already had those config values for the grpc service, still got
ERR error="Incoming request ended abruptly: context canceled" cfRay=8520f4a8991ca83b-<LOC> event=1 ingressRule=2 originService=http://localhost:8080
ERR failed to serve incoming request error="Failed to proxy HTTP: Incoming request ended abruptly: context canceled"
ERR error="Incoming request ended abruptly: context canceled" cfRay=8520f4a8991ca83b-<LOC> event=1 ingressRule=2 originService=http://localhost:8080
ERR failed to serve incoming request error="Failed to proxy HTTP: Incoming request ended abruptly: context canceled"
Chaika
Chaikaโ€ข10mo ago
originService=http://localhost:8080
That's http though, not https
Geospace
GeospaceOPโ€ข10mo ago
ah good point
Chaika
Chaikaโ€ข10mo ago
may be worth mentioning you need to restart the tunnel after a config change
Geospace
GeospaceOPโ€ข10mo ago
yep always have done this just to be sure ok I think I need to change how I deploy my service to get https working, a self-signed "insecure" cert should work with this cloudflared config right?
Chaika
Chaikaโ€ข10mo ago
It should yea. I have not tried that setup myself, but a CF employee in that github thread did say that should work for gRPC, at the cost of not being able to do udp proxying in private networks (which I doubt matters to you) The Quic transport protocol with cloudflared in general has some weird issues/edge cases like that, not surprised it breaks this
Geospace
GeospaceOPโ€ข10mo ago
ah ok great, just for context this is how I'm deploying the https version: https://zitadel.com/docs/self-hosting/manage/reverseproxy/caddy (so using this 127.0.0.1.sslip.io domain) should that be fine? was able to visit the dashboard of this service, just with an "insecure" cert warning in the url bar but grpcurl --insecure 127.0.0.1.sslip.io:443 zitadel.admin.v1.AdminService/Healthz did return the expected {} result
Chaika
Chaikaโ€ข10mo ago
yea that looks sane to me, its reverse proxying the grpc down via h2c to the actual origin yea? Would need to make sure you set noTLSVerify
Geospace
GeospaceOPโ€ข10mo ago
" its reverse proxying the grpc down via h2c to the actual origin" i think so, but my networking knowledge is pretty basic so couldn't say for certain i guess the other question i have is, would grpc work with my hostname ( auth.example.com) once i set this up?
Chaika
Chaikaโ€ข10mo ago
that's the idea, only thing to check there would be if you have gRPC enabled on that website/zone in Cloudflare under Network tab
Geospace
GeospaceOPโ€ข10mo ago
ok cool, think that setting is already enabled in my cf dashboard. alright, i'll redeploy using this sslip.io domain and see if we have any luck! ok so this is what I have: config.yaml
- hostname: auth.example.com
#service: http://localhost:8080
service: https://127.0.0.1.sslip.io
originRequest:
noTLSVerify: true
http2Origin: true
- hostname: auth.example.com
#service: http://localhost:8080
service: https://127.0.0.1.sslip.io
originRequest:
noTLSVerify: true
http2Origin: true
then I run $ cloudflared tunnel --protocol http2 run my-app then i test the sslip.io domain: $ grpcurl --insecure 127.0.0.1.sslip.io:443 zitadel.admin.v1.AdminService/Healthz (which works, returns {}) and finally i test my own subdomain (auth.example.com) and get this output:
grpcurl --insecure auth.example.com:443 zitadel.admin.v1.AdminService/Healthz
Error invoking method "zitadel.admin.v1.AdminService/Healthz": rpc error: code = Unknown desc = failed to query for service descriptor "zitadel.admin.v1.AdminService": malformed header: missing HTTP content-type
grpcurl --insecure auth.example.com:443 zitadel.admin.v1.AdminService/Healthz
Error invoking method "zitadel.admin.v1.AdminService/Healthz": rpc error: code = Unknown desc = failed to query for service descriptor "zitadel.admin.v1.AdminService": malformed header: missing HTTP content-type
i would've thought grpcurl would include application/grpc for it's content type header by default (but maybe that's not the issue)
Chaika
Chaikaโ€ข10mo ago
in the post they stated
One final thing, if you get back an obscure error about a missing content-type header e.g. rpc error: code = Unknown desc = failed to query for service descriptor "some.service": unexpected HTTP status code received from server: 302 (Found); malformed header: missing HTTP content-type ... it might be because you have an Access Policy set on your tunnel and here CF is trying to redirect you to your auth page. There's no way to follow this redirect but if you can get your CF auth token then you can pass it as a header with your grpc request and it should work. E.g.
Do you have an Access policy on that? perhaps you could use service tokens as well
Geospace
GeospaceOPโ€ข10mo ago
ah, I don't think so but let me double check is that under `https://dash.cloudflare.com/:hash/example.com/access ?
Geospace
GeospaceOPโ€ข10mo ago
i'll post what my cf settings for my domain look like:
No description
Geospace
GeospaceOPโ€ข10mo ago
No description
Geospace
GeospaceOPโ€ข10mo ago
No description
Geospace
GeospaceOPโ€ข10mo ago
No description
Geospace
GeospaceOPโ€ข10mo ago
No description
Geospace
GeospaceOPโ€ข10mo ago
from what I can see I don't think so
Chaika
Chaikaโ€ข10mo ago
It'd be under launch zt => Access => Applications or https://one.dash.cloudflare.com/?to=/:account/access/apps
Cloudflare One
Cloudflare One replaces legacy security perimeters with our global edge, making the Internet faster and safer for teams around the world.
Chaika
Chaikaโ€ข10mo ago
not in the normal dash
Geospace
GeospaceOPโ€ข10mo ago
ah ok, let me check
Geospace
GeospaceOPโ€ข10mo ago
don't think so?
No description
Chaika
Chaikaโ€ข10mo ago
doesn't look like it try running grpcurl with -vv?
Geospace
GeospaceOPโ€ข10mo ago
no difference in output, still
Error invoking method "zitadel.admin.v1.AdminService/Healthz": rpc error: code = Unknown desc = failed to query for service descriptor "zitadel.admin.v1.AdminService": malformed header: missing HTTP content-type
Error invoking method "zitadel.admin.v1.AdminService/Healthz": rpc error: code = Unknown desc = failed to query for service descriptor "zitadel.admin.v1.AdminService": malformed header: missing HTTP content-type
i'll post the curl output, one sec
Chaika
Chaikaโ€ข10mo ago
yea the headers would be helpful
Geospace
GeospaceOPโ€ข10mo ago
$ curl --insecure https://auth.example.com:443/admin/v1/healthz -vv * Trying <IP>:443... * Connected to auth.example.com (<IP>) port 443 (#0) * ALPN: offers h2,http/1.1 * (304) (OUT), TLS handshake, Client hello (1): * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 * ALPN: server accepted h2 * Server certificate: * subject: CN=example.com * start date: Dec 16 04:35:40 2023 GMT * expire date: Mar 15 04:35:39 2024 GMT * issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1P5 * SSL certificate verify ok. * using HTTP/2 * h2 [:method: GET] * h2 [:scheme: https] * h2 [:authority: auth.example.com] * h2 [:path: /admin/v1/healthz] * h2 [user-agent: curl/8.1.2] * h2 [accept: /] * Using Stream ID: 1 (easy handle 0x13100da00)
GET /admin/v1/healthz HTTP/2 Host: auth.example.com User-Agent: curl/8.1.2 Accept: /
> < HTTP/2 200 < date: Thu, 08 Feb 2024 04:45:55 GMT < content-length: 0 < alt-svc: h3=":443"; ma=86400 < cf-cache-status: DYNAMIC < report-to: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=kWpK3unT4gyqxg%2FtIsS1P1CzpXCUtCLEp1E9FE00Wj5BZkVtnj%2Fu4o%2BMYPY8p7Tm8F4eunjimpGzY4mkWoYb5pWKVkDIqx1%2FuAHLJ%2BRv87Vq3ydugnPu6TocmVrqFvp%2B0lXcyx0%3D"}],"group":"cf-nel","max_age":604800} < nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800} < server: cloudflare < cf-ray: 852139d6ff29a81f-SYD < * Connection #0 to host auth.example.com left intact
Chaika
Chaikaโ€ข10mo ago
doesn't tell us too much, other then it went down the tunnel shouldn't need --insecure btw
Chaika
Chaikaโ€ข10mo ago
You can enable a higher logging level in your tunnel: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/monitor-tunnels/logs/ and try to see the actual request log/response
Cloudflare Docs
Tunnel logs ยท Cloudflare Zero Trust docs
Tunnel logs record all activity between a cloudflared instance and Cloudflareโ€™s global network, as well as all activity between cloudflared and your โ€ฆ
Chaika
Chaikaโ€ข10mo ago
If the origin service had logs that would be helpful as well to see exactly what it is getting
Geospace
GeospaceOPโ€ข10mo ago
ok this is what logs (from cloudflared cli output) after i run that curl command:
2024-02-08T04:53:08Z DBG GET http://localhost:8080/admin/v1/healthz HTTP/2.0 cfRay=852144690d11a871-SYD connIndex=0 content-length=-1 event=1 headers={"Accept":["*/*"],"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["852144690d11a871-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["5c3251ab-f798-4515-936d-7bb01ca82eba"],"User-Agent":["curl/8.1.2"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/admin/v1/healthz
2024-02-08T04:53:09Z DBG 200 OK cfRay=852144690d11a871-SYD connIndex=0 content-length=0 event=1
2024-02-08T04:53:08Z DBG GET http://localhost:8080/admin/v1/healthz HTTP/2.0 cfRay=852144690d11a871-SYD connIndex=0 content-length=-1 event=1 headers={"Accept":["*/*"],"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["852144690d11a871-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["5c3251ab-f798-4515-936d-7bb01ca82eba"],"User-Agent":["curl/8.1.2"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/admin/v1/healthz
2024-02-08T04:53:09Z DBG 200 OK cfRay=852144690d11a871-SYD connIndex=0 content-length=0 event=1
Chaika
Chaikaโ€ข10mo ago
what about the grpcurl?
Geospace
GeospaceOPโ€ข10mo ago
will check, one moment (also seeing this?
2024-02-08T04:53:33Z DBG Failed to parse ICMP reply, continue to parse as full packet error="expect ICMP echo, got neighbor advertisement" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:33Z DBG Failed to parse ICMP reply as full packet error="unknow ip version 8" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:34Z DBG Failed to parse ICMP reply, continue to parse as full packet error="expect ICMP echo, got neighbor solicitation" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:34Z DBG Failed to parse ICMP reply as full packet error="unknow ip version 8" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:33Z DBG Failed to parse ICMP reply, continue to parse as full packet error="expect ICMP echo, got neighbor advertisement" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:33Z DBG Failed to parse ICMP reply as full packet error="unknow ip version 8" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:34Z DBG Failed to parse ICMP reply, continue to parse as full packet error="expect ICMP echo, got neighbor solicitation" dst=[fe80::1012:aad3:a98:617a%en0]:0
2024-02-08T04:53:34Z DBG Failed to parse ICMP reply as full packet error="unknow ip version 8" dst=[fe80::1012:aad3:a98:617a%en0]:0
)
Chaika
Chaikaโ€ข10mo ago
think that's just silly stuff that can be ignored. cloudflared can do icmp proxying these days. Some stuff is only logged in debug mode for a reason
Geospace
GeospaceOPโ€ข10mo ago
ah ok no worries, guessed it wasn't important but just wanted to be sure ok here's the grpcurl log results:
2024-02-08T04:55:57Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488c1c77a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488c1c77a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:57Z DBG 200 OK cfRay=8521488c1c77a96d-SYD connIndex=3 content-length=0 event=1
2024-02-08T04:55:58Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488cacd1a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488cacd1a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:58Z DBG 200 OK cfRay=8521488cacd1a96d-SYD connIndex=3 content-length=0 event=1
2024-02-08T04:55:57Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488c1c77a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488c1c77a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:57Z DBG 200 OK cfRay=8521488c1c77a96d-SYD connIndex=3 content-length=0 event=1
2024-02-08T04:55:58Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488cacd1a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488cacd1a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:58Z DBG 200 OK cfRay=8521488cacd1a96d-SYD connIndex=3 content-length=0 event=1
2024-02-08T04:55:58Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488ced07a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488ced07a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:58Z DBG 200 OK cfRay=8521488ced07a96d-SYD connIndex=3 content-length=0 event=1
2024-02-08T04:55:58Z DBG POST http://localhost:8080/grpc.reflection.v1.ServerReflection/ServerReflectionInfo HTTP/2.0 cfRay=8521488ced07a96d-SYD connIndex=3 content-length=-1 event=1 headers={"Accept-Encoding":["gzip"],"Cdn-Loop":["cloudflare"],"Cf-Connecting-Ip":["<IP>"],"Cf-Ipcountry":["AU"],"Cf-Ray":["8521488ced07a96d-SYD"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Cf-Warp-Tag-Id":["fc4d4a5a-045e-4773-8561-2cce7f80cac1"],"Content-Type":["application/grpc"],"Grpc-Accept-Encoding":["gzip"],"Te":["trailers"],"User-Agent":["grpcurl/1.8.9 grpc-go/1.57.0"],"X-Forwarded-For":["<IP>"],"X-Forwarded-Proto":["https"]} host=auth.example.com ingressRule=2 path=/grpc.reflection.v1.ServerReflection/ServerReflectionInfo
2024-02-08T04:55:58Z DBG 200 OK cfRay=8521488ced07a96d-SYD connIndex=3 content-length=0 event=1
Chaika
Chaikaโ€ข10mo ago
you missed censoring your domain and ips on those those look like the origin is http://localhost:8080 directly though
Geospace
GeospaceOPโ€ข10mo ago
I noticed lol, not a huge issue
Chaika
Chaikaโ€ข10mo ago
if you run cloudflared tunnel ingress rule https://<your-real-website>, what does it say for 'Using rules from <location>', is it using them from the location you'd expect?
Geospace
GeospaceOPโ€ข10mo ago
I mean I think so, I don't really understand what sslip.io is doing, what it's resolving, etc but that's what the zitadel example documentation is using:
Using rules from /Users/me/.cloudflared/config.yml
Matched rule #2
hostname: auth.example.com
service: https://127.0.0.1.sslip.io
Using rules from /Users/me/.cloudflared/config.yml
Matched rule #2
hostname: auth.example.com
service: https://127.0.0.1.sslip.io
Chaika
Chaikaโ€ข10mo ago
sslip.io
All it does is return the ip you give it, ex 127.0.0.1. Because some of this tooling/etc needs a hostname and not an IP
Geospace
GeospaceOPโ€ข10mo ago
oh ok
Chaika
Chaikaโ€ข10mo ago
Still though that looks wrong to me, the origin service shouldn't be that..? You're running the tunnel under your user account, or as a service? if you run it as a service it would copy the config file from local and then use /etc/cloudflared/config.yml forever
Geospace
GeospaceOPโ€ข10mo ago
just under my user account (i.e. inside a terminal i run cloudflared tunnel --protocol http2 --loglevel debug run my-app) (inside my ~./cloudflared directory) $ cd ~./cloudflared && cloudflared tunnel --protocol http2 run my-app not sure if it's helpful but these commands are how I'm deploying zitadel locally:
# Download the configuration files.
export ZITADEL_CONFIG_FILES=https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy
wget ${ZITADEL_CONFIG_FILES}/docker-compose.yaml -O docker-compose-base.yaml
wget ${ZITADEL_CONFIG_FILES}/caddy/docker-compose.yaml -O docker-compose-caddy.yaml
wget ${ZITADEL_CONFIG_FILES}/caddy/enabled-tls.Caddyfile -O enabled-tls.Caddyfile

# Generate a self signed certificate and key.
openssl req -x509 -batch -subj "/CN=127.0.0.1.sslip.io/O=ZITADEL Demo" -nodes -newkey rsa:2048 -keyout ./selfsigned.key -out ./selfsigned.crt

# Run the database, ZITADEL and Caddy.
docker compose --file docker-compose-base.yaml --file docker-compose-caddy.yaml up --detach proxy-enabled-tls

# Test that gRPC and HTTP APIs work. Empty brackets like {} means success.
sleep 3
grpcurl --insecure 127.0.0.1.sslip.io:443 zitadel.admin.v1.AdminService/Healthz
curl --insecure https://127.0.0.1.sslip.io:443/admin/v1/healthz
# Download the configuration files.
export ZITADEL_CONFIG_FILES=https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy
wget ${ZITADEL_CONFIG_FILES}/docker-compose.yaml -O docker-compose-base.yaml
wget ${ZITADEL_CONFIG_FILES}/caddy/docker-compose.yaml -O docker-compose-caddy.yaml
wget ${ZITADEL_CONFIG_FILES}/caddy/enabled-tls.Caddyfile -O enabled-tls.Caddyfile

# Generate a self signed certificate and key.
openssl req -x509 -batch -subj "/CN=127.0.0.1.sslip.io/O=ZITADEL Demo" -nodes -newkey rsa:2048 -keyout ./selfsigned.key -out ./selfsigned.crt

# Run the database, ZITADEL and Caddy.
docker compose --file docker-compose-base.yaml --file docker-compose-caddy.yaml up --detach proxy-enabled-tls

# Test that gRPC and HTTP APIs work. Empty brackets like {} means success.
sleep 3
grpcurl --insecure 127.0.0.1.sslip.io:443 zitadel.admin.v1.AdminService/Healthz
curl --insecure https://127.0.0.1.sslip.io:443/admin/v1/healthz
https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy/docker-compose.yaml https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/manage/reverseproxy/caddy/docker-compose.yaml
Chaika
Chaikaโ€ข10mo ago
what's the first line when you launch the tunnel under debugmode? It should spit out the config location as well
Geospace
GeospaceOPโ€ข10mo ago
2024-02-08T05:12:13Z DBG Loading configuration from /Users/me/.cloudflared/config.yml
2024-02-08T05:12:13Z DBG Loading configuration from /Users/me/.cloudflared/config.yml
I do see this, relevant or no? 2024-02-08T05:12:13Z DBG Fetched protocol: quic and below it 2024-02-08T05:12:13Z INF Initial protocol http2
Chaika
Chaikaโ€ข10mo ago
as long as the actual connections say protocol=http2, shouldn't matter
Geospace
GeospaceOPโ€ข10mo ago
gotcha
Chaika
Chaikaโ€ข10mo ago
I'm assuming you saying /Users/me/.cloudflared/config.yml above is just you censoring it diferently?
Geospace
GeospaceOPโ€ข10mo ago
yeah correct, sorry about that always try to remove identifying information when possible, just incase someone else gets ahold of my pastes
Chaika
Chaikaโ€ข10mo ago
no worries. Yea this is a tunnel config issue of some sort, I'm 99% sure, just trying to understand where. The default for not specifying/unparsable is localhost:8080 iirc
Geospace
GeospaceOPโ€ข10mo ago
oh ok, so maybe it's that sslip.io domain causing issues? I was wondering where that locahost:8080 value was coming from
Chaika
Chaikaโ€ข10mo ago
I don't think so, I think this is yaml, one sec. Can you post your config.yml censoring anything needed?
Geospace
GeospaceOPโ€ข10mo ago
yeah of course
#url: http://localhost:8081
name: my-app
tunnel: b0eebf71-4cea-8150-0c240ecffe57
credentials-file: b0eebf72-4cea-8150-0c240ecffe57.json
http2Origin: true

ingress:
- hostname: foo.example.com
service: http://localhost:3000
- hostname: bar.example.com
service: http://localhost:8081
- hostname: auth.example.com
service: https://127.0.0.1.sslip.io
originRequest:
noTLSVerify: true
http2Origin: true
- hostname: baz.example.com
service: http://localhost:7700
- service: http_status:404
#url: http://localhost:8081
name: my-app
tunnel: b0eebf71-4cea-8150-0c240ecffe57
credentials-file: b0eebf72-4cea-8150-0c240ecffe57.json
http2Origin: true

ingress:
- hostname: foo.example.com
service: http://localhost:3000
- hostname: bar.example.com
service: http://localhost:8081
- hostname: auth.example.com
service: https://127.0.0.1.sslip.io
originRequest:
noTLSVerify: true
http2Origin: true
- hostname: baz.example.com
service: http://localhost:7700
- service: http_status:404
btw my caddyfiles contain this:
$ grep "8080" .
./external-tls.Caddyfile: reverse_proxy h2c://zitadel-external-tls:8080
./enabled-tls.Caddyfile: reverse_proxy https://zitadel-enabled-tls:8080 {
$ grep "8080" .
./external-tls.Caddyfile: reverse_proxy h2c://zitadel-external-tls:8080
./enabled-tls.Caddyfile: reverse_proxy https://zitadel-enabled-tls:8080 {
that might be where the localhost:8080 is coming from
--- external-tls.Caddyfile ---
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy h2c://zitadel-external-tls:8080
}

--- enabled-tls.Caddyfile ---
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy https://zitadel-enabled-tls:8080 {
transport http {
tls_insecure_skip_verify
}
}
}
--- external-tls.Caddyfile ---
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy h2c://zitadel-external-tls:8080
}

--- enabled-tls.Caddyfile ---
https://127.0.0.1.sslip.io {
tls /etc/certs/selfsigned.crt /etc/certs/selfsigned.key
reverse_proxy https://zitadel-enabled-tls:8080 {
transport http {
tls_insecure_skip_verify
}
}
}
Chaika
Chaikaโ€ข10mo ago
do you actually have anything running on http://localhost:8080/ that is even reachable from the tunnel host?
Geospace
GeospaceOPโ€ข10mo ago
well http://localhost:8080 doesn't resolve to the zitadel service if i enter that into the browser but I should say that localhost:8080 is the port zitadel usually runs on is caddy/cloudflared somehow redirecting requests from auth.example.com:443 to localhost:8080 possibly? this isn't relevant right? < alt-svc: h3=":443"; ma=86400 h3 meaning http3 , i'm guessing that's not an issue
Chaika
Chaikaโ€ข10mo ago
it's just a hint to tell your client "hey http3 is here, connect and use it sometime" I messed around with it a bit more and it looks like that host header thing may be something on CF's end. It looks like for QUIC it shows the right host header/url for the request, but for http2 it's localhost:8080 Not sure it actually matters though
Geospace
GeospaceOPโ€ข10mo ago
ah ok think I recall that from https://github.com/cloudflare/cloudflared/issues/682#issuecomment-1440736613 honestly so much of this networking stuff just goes over my head, have no idea how most of it works lol
Chaika
Chaikaโ€ข10mo ago
for you, it works from the same host as the tunnel both to the caddy proxy and to zitadel directly, right? that comment was about it showing /1.1, but for you and me its showing http/2.0, just with http://localhost:8080
Geospace
GeospaceOPโ€ข10mo ago
ah ok er not sure I fully understand, but https://127.0.0.1.sslip.io does resolve, but https://127.0.0.1 gives ERR_SSL_PROTOCOL_ERROR sorry if that doesn't answer the question, let me know if there's something i can check to help answer it
Chaika
Chaikaโ€ข10mo ago
I think you did answer that further up if you add
originRequest:
...
httpHostHeader: 'auth.example.com'
originRequest:
...
httpHostHeader: 'auth.example.com'
` does that change anything? just a last attempt I can think of, if it's failing to get the host header properly from logs, it's probably passing the wrong one too
Geospace
GeospaceOPโ€ข10mo ago
doesn't seem to unfortunately
Chaika
Chaikaโ€ข10mo ago
otherwise I gotta hop off, sorry for leading you on such a wild goose chase with no solution so far. That weirdness with it showing the wrong incoming url is well weird and complicated the already confusing grpc stuff. I'll see if I can't forward that up if I can reproduce it minimally, it may be related. As for debugging the actual issue, we can see from logs it is sending with the right headers, and the server is returning content-length 0 with that error. So tunnel -> proxy, something's not being forwarded right? Having caddy dump whatever its receiving including content, if you still had any more will to debug. It's weird though because it complains about the http content-type, but we know it got to cloudflared. so is it not forwarding to the proxy right? You could always do gRPC over Private Networking w/ WARP but that would require vpn
Geospace
GeospaceOPโ€ข10mo ago
nah all good mate, I really appreciate you taking the time to help try to resolve this, wouldn't know where to begin on my own just trying to get this service working locally so that I can develop with it, but keep hitting roadblocks no matter what I try ๐Ÿ˜‚
Chaika
Chaikaโ€ข10mo ago
Looks like that weirdness with http2 showing the wrong host header is just purely a weird logging thing and the origin gets the correct host header/doesn't matter. I spun up a quick python grpcio server and it properly works via tunnel forced to http2/with http2 to origin. When QUIC is used instead of http2 it properly doesn't work as expected "Message: "b'/MyService/Echo'" requires exactly one request message.". I tested using reflection as well as gRPC streams, and they all worked. So in theory at least it works with gRPC, but of course could be more specific then that if it's using a specific behavior that is unsupported
Geospace
GeospaceOPโ€ข10mo ago
ah interesting, so does that mean it's more likely an issue with zitadel itself rather than cloudflared?
Chaika
Chaikaโ€ข10mo ago
I mean you are trying to use a feature which is documented as not supported lol but yea, that or the proxy
Geospace
GeospaceOPโ€ข10mo ago
well to be fair they say it's an issue with cloudflared ๐Ÿ˜‚ but again i don't really understand the underlying technical details, was just trying to find a solution that's super helpful to know though, already discussed this topic with the founder so hopefully he has some insight into what could be going wrong from their end mate I can't thank you enough for all your help debugging this issue, it's been such a thorn in my side for the last week or so, wouldn't have known where to begin myself just for context, the founder said this yesterday:
To my last knowledge it was the problem that tunnels did not allow to force h2 (that is what we need for grpc, IMO they need no support for grpc explicitly)
To my last knowledge it was the problem that tunnels did not allow to force h2 (that is what we need for grpc, IMO they need no support for grpc explicitly)
So if that's no longer the problem, there's a good chance that some changes to zitadel itself might make it possible to access that grpc endpoint via cloudflared
Chaika
Chaikaโ€ข10mo ago
just in case it's worth mentioning, tunnels aren't forcing http2 to origin. They're just willing to accept it. If the origin doesn't say it supports it in tls connect/ alpn it'll just downgrade silently
Chaika
Chaikaโ€ข10mo ago
keyword in the docs is "attempts" lol
No description
Chaika
Chaikaโ€ข10mo ago
cloudflared is all open source btw, I'm no go programmer but it's not too hard to read: https://github.com/cloudflare/cloudflared/blob/a9aa48d7a1e5e0d06c30a243802af2b228e73995/ingress/origin_service.go#L355 They just pass it through to ForceAttemptHttp2
// ForceAttemptHTTP2 controls whether HTTP/2 is enabled when a non-zero // Dial, DialTLS, or DialContext func or TLSClientConfig is provided. // By default, use of any those fields conservatively disables HTTP/2. // To use a custom dialer or TLS config and still attempt HTTP/2 // upgrades, set this to true. ForceAttemptHTTP2 bool
Geospace
GeospaceOPโ€ข10mo ago
ah ok, so zitadel requires the ability to "force" http2 to origin, but cloudflared is only willing to accept it, and doesn't necessitate it?
Chaika
Chaikaโ€ข10mo ago
when you say "forcing" to me, it kinda sounds like they need h2c/http2 clear text I don't understand why it would require it otherwise, espec with the caddy proxy in the front. It's possible I'm missing something, or they are just saying they need h2c (which cloudflared doesn't support, but I thought that was the whole point of the caddy proxy?)
Geospace
GeospaceOPโ€ข10mo ago
ZITADEL Docs
You can either setup your environment for TLS mode external or TLS mode enabled.
Geospace
GeospaceOPโ€ข10mo ago
[TLS mode external] - Caddy terminates TLS and forwards the requests to ZITADEL via unencrypted h2c. This example uses an unsafe self-signed certificate for CaddyBy executing the commands below, you will download the files necessary to run ZITADEL behind Caddy with the following config: whereas [TLS mode enabled] - Caddy terminates TLS and forwards the requests to ZITADEL via encrypted HTTP/2. This example uses an unsafe self-signed certificate for Caddy and the same for ZITADEL.By executing the commands below, you will download the files necessary to run ZITADEL behind Caddy with the following config:
Chaika
Chaikaโ€ข10mo ago
Either should work. The end result is the client (cloudflared) can connect via http/2 encrypted
Geospace
GeospaceOPโ€ข10mo ago
ah right
Chaika
Chaikaโ€ข10mo ago
H2C is just special. It's not supported by browsers (also why you'll only see http/1.1 when connecting to an insecure site), and not the default golang net package Cloudflare uses. You kind of need prior knowledge too, because you don't have TLS/ALPN to pick the best protocol before connecting, have to rely on upgrade: headers like http3 does and upgrade later, but of course gRPC requires http/2. Shouldn't matter too much, the only bit worth noting is cloudflared can only do http/2 encrypted. Fun web things though, http/3 doesn't have an unencrypted version at all
Geospace
GeospaceOPโ€ข10mo ago
ah ok, i think that makes sense... i really need to read up on my networking lol. h2c is basically a way of using http/2 insecurely (without TLS) right?
Chaika
Chaikaโ€ข10mo ago
Yep, h2c just means http/2 Cleartext (which does mean no TLS/SSL)
Want results from more Discord servers?
Add your server