On the grpc client code, I just change the addr from: localhost:50051 to localhost:443. Then I start caddy and the grpc service/server. Then I run the client again but I get the following error:
➜ make client
go run greeter_client/main.go --name=Drio
2023/03/16 09:50:26 could not greet: rpc error: code = Unavailable desc = connection error: desc = "error reading server preface: EOF"
exit status 1
make: *** [client] Error 1
Does anyone know what may be happening?
I must admit I have zero expertise in grpc. I am just trying to stream cisco telemetry to a telegraf instance to store the data but I wanted to move in small steps.
I see there is another grpc mode (streaming) which requires a different caddy configuration (h2c). What is exactly the difference between traditional grpc vs grpc streaming?
I still get the same error when proxying via Caddy:
➜ go run greeter_client/main.go --addr localhost:443;
2023/03/16 12:45:48 could not greet: rpc error: code = Unavailable desc = connection error: desc = "error reading server preface: EOF"
exit status 1
But the client works correctly if I connect directly to the server.
➜ go run greeter_client/main.go --addr localhost:50051;
2023/03/16 12:45:42 Greeting: Hello world
{
debug off
}
https://localhost {
reverse_proxy h2c://localhost:50051
}
I get this on the client side:
➜ go run greeter_client/main.go --addr localhost:443;
2023/03/16 14:17:23 could not greet: rpc error: code = Unavailable desc = connection error: desc = "error reading server preface: EOF"
exit status 1
And the Caddy log gives the same error:
023/03/16 18:19:59.866 DEBUG http.stdlib http: TLS handshake error from [::1]:54512: tls: first record does not look like a TLS handshake
I think I know what is going on.
The server code looks like this:
...
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
So, the server is talking plain http2.
If I connect to port 80 (served by caddy), the client gives me this error:
➜ go run greeter_client/main.go --addr localhost:80;
2023/03/16 14:34:16 could not greet: rpc error: code = Unavailable desc = connection error: desc = "error reading server preface: http2: frame too large"
exit status 1
{
debug off
}
https://localhost {
reverse_proxy h2c://localhost:50051
}
➜ go run greeter_client/main.go --addr localhost:443
Is the only one that actually connects to Caddy (but Caddy does not proxy the request).
And in the caddy logs I see:
http.stdlib http: TLS handshake error from [::1]:51567: tls: first record does not look like a TLS handshake
With https://localhost I get:
➜ go run greeter_client/main.go --addr https://localhost
2023/03/17 06:55:27 could not greet: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp: lookup tcp///localhost: nodename nor servname provided, or not known"
exit status 1
And if I connect directly to the server/service:
➜ go run greeter_client/main.go --addr localhost:50051
2023/03/17 06:57:53 Greeting: Hello world
Like I said, this is because your client is connecting using HTTP, and not HTTPS.
You need to make sure your client uses HTTPS.
Okay, your client program doesn’t understand schemes. That’s strange.
Ultimately this problem is with your client program, not with Caddy. Your Caddy config is correct. Your program is only able to connect using HTTP and not HTTPS.