I couldn’t find a single article explaining the different ways of connecting two Go applications using gRPC. After many tries, I came to the final 3 most useful ways to go:
Basic connection, no security
First, and easiest, is to not use TLS at all and not require any certificate. This mode is most useful if you have no certificate or if you don’t care about security, as transport is just HTTP, everything is in clear :-)
On the server side:
func (s *GroundServer) Serve(addr string) {
lis, err := net.Listen("tcp", addr)
if err != nil {
return fmt.Errorf("could not list on %s: %s", addr, err)
}
srv := grpc.NewServer()
pb.RegisterFooServer(srv, s)
if err := srv.Serve(lis); err != nil {
return fmt.Errorf("grpc serve error: %s", err)
}
}
Here, we didn’t specify any argument to grpc.NewServer()
, so no TLS!
On the client side:
func Run(addr string) error {
creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
// conn, err := grpc.Dial(addr, grpc.WithInsecure())
// Create a connection with the TLS credentials
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
if err != nil {
return fmt.Errorf("could not dial %s: %s", addr, err)
}
defer conn.Close()
// Initialize the client and make the request
client := pb.NewFooClient(conn)
pong, err := client.Feature(context.Background(), &pb.UniqID{Uniqid: "aaabc23232aaa", Timestamp: 1234})
if err != nil {
return fmt.Errorf("could not ping %s: %s", addr, err)
}
log.Printf("%s\n", pong.String())
return nil
}
Secure connection, using TLS
Now, we establish a connection using TLS, which requires a certificate on the server side. To generate a self-signed certificate, you can use openssl
like so:
openssl req -x509 -newkey rsa:4096 -keyout server.key \
-out server.crt -nodes -days 365 \
-subj '/CN=mynicedomainname.com'
Server side would be:
func (s *GroundServer) Serve(addr string) {
lis, err := net.Listen("tcp", addr)
if err != nil {
return fmt.Errorf("could not list on %s: %s", addr, err)
}
creds, err := credentials.NewServerTLSFromFile(crt, key)
if err != nil {
panic(fmt.Errorf("could not load TLS keys: %s", err))
}
srv := grpc.NewServer(grpc.Creds(creds))
pb.RegisterFooServer(srv, s)
if err := srv.Serve(lis); err != nil {
return fmt.Errorf("grpc serve error: %s", err)
}
}
Client side would be :
func Run(addr string) {
creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
if err != nil {
return fmt.Errorf("could not dial %s: %s", addr, err)
}
defer conn.Close()
// Initialize the client and make the request
client := pb.NewFooClient(conn)
pong, err := client.Feature(context.Background(), &pb.UniqID{Uniqid: "aaabc23232aaa", Timestamp: 1234})
if err != nil {
return fmt.Errorf("could not ping %s: %s", addr, err)
}
log.Printf("%s\n", pong.String())
}
Even more secure connection, using TLS and server cert
We establish a connection using TLS, which requires a certificate on the server side.
Server side would be:
func (s *GroundServer) Serve(addr string) {
lis, err := net.Listen("tcp", addr)
if err != nil {
return fmt.Errorf("could not list on %s: %s", addr, err)
}
creds, err := credentials.NewServerTLSFromFile(crt, key)
if err != nil {
panic(fmt.Errorf("could not load TLS keys: %s", err))
}
srv := grpc.NewServer(grpc.Creds(creds))
pb.RegisterFooServer(srv, s)
if err := srv.Serve(lis); err != nil {
return fmt.Errorf("grpc serve error: %s", err)
}
}
And on the client side:
func Run(addr string) error {
creds, err := credentials.NewClientTLSFromFile(cert, "")
if err != nil {
return fmt.Errorf("could not load tls cert: %s", err)
}
conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
if err != nil {
return fmt.Errorf("could not dial %s: %s", addr, err)
}
defer conn.Close()
client := pb.NewDistributerClient(conn)
pong, err := client.Feature(context.Background(), &pb.UniqID{Uniqid: "aaabc23232aaa", Timestamp: 1234})
if err != nil {
return fmt.Errorf("could not ping %s: %s", addr, err)
}
log.Printf("%s\n", pong.String())
return nil
}

Gophers images provided by René French, Brian Ketelsen and Steve Francia, https://github.com/ashleymcnamara/gophers