Golang http - Create HTTPS Server and Client


Written by - Tuan Nguyen
Reviewed by - Deepak Prasad

Introduction to Golang HTTP

In this tutorial, we will dive into the basics of writing HTTP servers. You will learn how handler functions work, discover more about processing requests, and study how to read and write streaming data.

The net/http package gives us the building blocks for writing an HTTP server. A server running on your computer, available at http://localhost:8080, would process a request as follows:

  • The server receives a client request at a certain path, say /api.
  • The server checks if it can handle this request.
  • If the answer is yes, the server calls a handler function to process the request and return the response. If not, it returns an HTTP error as a response to the client.

Golang http - Create HTTPS Server and Client

 

Create your first HTTP web server using golang

Let us create a basic HTTP server which will listen on a pre-defined port number.

package main

import (
	"log"
	"net/http"
	"os"
)

func main() {
	listenAddr := os.Getenv("LISTEN_ADDR")
	if len(listenAddr) == 0 {
		listenAddr = ":8080"
	}

	log.Fatal(http.ListenAndServe(listenAddr, nil))
}

Explanation: The ListenAndServe() function in the net/http package starts an HTTP server at a given network address. It is a good idea to make this address configurable. Thus, in the main() function, the following lines check if the LISTEN_ADDR environment variable has been specified, and if not, it defaults to ":8080"

Next, we call the ListenAndServe() function specifying the address to listen on ( listenAddr ) and the handler for the server. We will specify nil as the value for the handler and thus our function call to ListenAndServe is as follows:

log.Fatal(http.ListenAndServe(listenAddr, nil))

The ListenAndServe() returns immediately with an error value if there is an error when starting the server. If the server has started correctly, the function only returns when the server is terminated. In either case, the log.Fatal() function will log the error value if there is one.

Let's start our web server on one terminal

$ go run main.go

On another terminal you can see that port 8080 is in Listening state:

# ss -ntlp | grep 8080
LISTEN    0         4096                     *:8080                   *:*        users:(("main",pid=4073,fd=3))

But if we try to query our web server using curl command, we get 404:

$ curl -X GET localhost:8080/api
404 page not found

This means that the server receives the incoming request, looks at it, and returns an HTTP 404 response, meaning that it cannot find the resource, /api, which we are requesting.

 

Setting up Request Handlers

When you specified nil as the second argument to the ListenAndServe() function, you asked the function to use the default handler, DefaultServeMux. It serves as the default registry of how to handle a request path.

DefaultServeMux is an object of type ServeMux defined in the http package. It is a global object, which means that any other code you may be using in your application can also register handler functions with your server. There is absolutely nothing preventing a third-party rogue package from exposing an HTTP path without you even knowing it. Additionally, as with any other global object, this opens your code up to unforeseen concurrency bugs and non-robust behavior. Hence, we are not going to use it. Instead, we will create a new ServeMux object:

mux := http.NewServeMux()
Golang http - Create HTTPS Server and Client
Any package can register a handler function with the DefaultServeMux object

To solve the HTTP 404 issue that you encountered in the previous section, you will need to register a special function called a handler function for the path.

 

Handler Functions

A handler function must be of type func(http.ResponseWriter, *http.Request), where http.ResponseWriter and http.Request are two struct types defined in the net/http package. The object of type http.Request represents the incoming HTTP request and the http.ResponseWriter object is used to write back the response to the client making the request. The following is an example of a handler function:

func apiHandler(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello World")
}

Here we send the string "Hello World" using the fmt.Fprintf() function. Note how the Fprintf() function, which we used to write a string to the standard output, is equally applicable to send back a string as an HTTP response thanks to the power of the io.Writer interface. Of course, you could use any other library function here instead of fmt.Fprintf() – io.WriteString(), for example.

Once you have written your handler function, the next step is to register it with the ServeMux object that you created earlier:

mux.HandleFunc("/api", apiHandler)

This creates a mapping in the mux object so that any request for the /api path is now handled by the apiHandler() function. Finally, we will call the ListenAndServe() function specifying this ServeMux object:

err := http.ListenAndServe(listenAddr, mux)

The following code registers handler functions for two paths: /api and /healthz:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func apiHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "Hello, world!\n")
}

func healthCheckHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "ok\n")
}

func setupHandlers(mux *http.ServeMux) {
	mux.HandleFunc("/healthz", healthCheckHandler)
	mux.HandleFunc("/api", apiHandler)

}

func main() {

	listenAddr := os.Getenv("LISTEN_ADDR")
	if len(listenAddr) == 0 {
		listenAddr = ":8080"
	}

	mux := http.NewServeMux()
	setupHandlers(mux)

	log.Fatal(http.ListenAndServe(listenAddr, mux))

}

Explanation: We create a new ServeMux object, mux, via a call to the NewServeMux() function and then call the setupHandlers() function passing mux as a parameter. In the setupHandlers() function, we call the HandleFunc() functions to register the two paths and their corresponding handler functions. Then we call the ListenAndServe() function passing mux as the handler to use.

From a new terminal, use curl to make HTTP requests to the server. For the /api and /healthz paths, you will see the Hello, world! and ok responses respectively.

$ curl -X GET localhost:8080/api
Hello, world!


$ curl -X GET localhost:8080/healthz
ok

 

Secure Communication over HTTP with TLS and MTLS

Generate certificates

First of all we will generate our own CA certificate:

root@ubuntu:~/goexamples/code1/certs# openssl genrsa -out ca.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
...................................................++++
................................................................................++++
e is 65537 (0x010001)

root@ubuntu:~/goexamples/code1/certs# openssl req -new -x509 -days 365 -key ca.key -out cacert.pem -subj "/C=IN/ST=NSW/L=Bengaluru/O=GoLinuxCloud/OU=Org/CN=RootCA"

root@ubuntu:~/goexamples/code1/certs# ls -l
total 12
-rw-r--r-- 1 root root 2025 Oct  5 16:38 cacert.pem
-rw------- 1 root root 3243 Oct  5 16:37 ca.key

Next we will generate server certificate and key which will be signed using the above generated CA certificate. You can refer our OpenSSL tutorial to get more clarity on these individual commands I am executing here as I won't be able to explain them here.

My server hostname is ubuntu and it has IP of 172.20.10.2 so I have provided those in my SAN Extension file. These will be used for client authentication during MTLS communication.

root@ubuntu:~/goexamples/code1/certs# cat server_cert_ext.cnf 
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 172.20.10.2
DNS.1 = ubuntu
DNS.2 = localhost

root@ubuntu:~/goexamples/code1/certs# openssl genrsa -out server.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
............................................................++++
..................................................................................++++
e is 65537 (0x010001)

root@ubuntu:~/goexamples/code1/certs# openssl req -new -key server.key -out server.csr -subj "/C=IN/ST=NSW/L=Bengaluru/O=GoLinuxCloud/OU=Org/CN=ubuntu"

root@ubuntu:~/goexamples/code1/certs# openssl x509 -req -in server.csr  -CA cacert.pem -CAkey ca.key -out server.crt -CAcreateserial -days 365 -sha256 -extfile server_cert_ext.cnf
Signature ok
subject=C = IN, ST = NSW, L = Bengaluru, O = GoLinuxCloud, OU = Org, CN = ubuntu
Getting CA Private Key

root@ubuntu:~/goexamples/code1/certs# ls -l
total 36
drwxr-xr-x 2 root root 4096 Oct  5 16:38 ./
drwxr-xr-x 4 root root 4096 Oct  5 15:55 ../
-rw-r--r-- 1 root root 2025 Oct  5 16:38 cacert.pem
-rw-r--r-- 1 root root   41 Oct  5 16:38 cacert.srl
-rw------- 1 root root 3243 Oct  5 16:37 ca.key
-rw-r--r-- 1 root root  349 Oct  5 16:36 server_cert_ext.cnf
-rw-r--r-- 1 root root 2399 Oct  5 16:38 server.crt
-rw-r--r-- 1 root root 1695 Oct  5 16:38 server.csr
-rw------- 1 root root 3243 Oct  5 16:38 server.key

Now we have all the files we need to setup HTTPS webserver using golang program.

 

Using ListenAndServeTLS

We have written detailed tutorial covering Certificate Management so here we will try to be very brief here. TLS helps secure the communication between a server and a client using cryptographic protocols. More commonly, it allows you to implement secure web servers so that client-server communication happens over Hypertext Transfer Protocol Secure (HTTPS) rather than plain HTTP. To start an HTTPS server, you will use the http.ListenAndServeTLS() function or the srv.ListenAndServeTLS() method, where srv is a custom http.Server object. The signature of the ListenAndServeTLS() function is as follows:

func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler)

If you compare ListenAndServeTLS() to the ListenAndServe() function, it takes two additional arguments—the second and third argument are string values containing the path to the TLS certificate and key files

Since there is no additional argument supported by ListenAndServeTLS() to add CA Certificate so we will create a bundle with our server certificate and CA bundle and pass it as single argument. Here I have created a new file certbundle.pem and am appending cacert.pem content inside the certificate.

root@ubuntu:~/goexamples/code1/certs# cp server.crt certbundle.pem

root@ubuntu:~/goexamples/code1/certs# cat cacert.pem >> certbundle.pem 

root@ubuntu:~/goexamples/code1/certs# cat certbundle.pem 
-----BEGIN CERTIFICATE-----
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
Jvc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFqzCCA5OgAwIBAgIUdwkGHzFd4TwhiKCk1PQ5837Fs/IwDQYJKoZIhvcNAQEL
BQAwZTELMAkGA1UEBhMCSU4xDDAKBgNVBAgMA05TVzESMBAGA1UEBwwJQmVuZ2Fs
dXJ1MRUwEwYDVQQKDAxHb0xpbnV4Q2xvdWQxDDAKBgNVBAsMA09yZzEPMA0GA1UE
AwwGUm9vdENBMB4XDTIyMTAwNTExMDgwMVoXDTIzMTAwNTExMDgwMVowZTELMAkG
A1UEBhMCSU4xDDAKBgNVBAgMA05TVzESMBAGA1UEBwwJQmVuZ2FsdXJ1MRUwEwYD
VQQKDAxHb0xpbnV4Q2xvdWQxDDAKBgNVBAsMA09yZzEPMA0GA1UEAwwGUm9vdENB
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAztpAk6zgSBpq0IelMOjR
8dBG/5ovHf2Ab20iiPyvEqjzKAedPbAcYbouYuQwUjHmhLY8hrT8ndRBFFM+nmuJ
vYvyVj0T/o3i1e8iJS/yBIEmoeW8LtKohuPw8O+/3pGSRD8EPrfoG8/sUlwLp0YV
rZf8rKPXpJyXamfeJhU0726QRD4TiowvKbVK1GYNXByYFMjLY6VqvVG5liR1eAjt
Pk7Ju19jDqgfw20j1rP/mWJO8uSQlG27kjNEBBi2kHbK8vNgPol9vYZjaxRscFpi
UUHAGKzPazmw+GscWu+zKr9QSnOi4Pn673YFphSjexLsbtCw3ebJ649UWwbUDOMb
PMKEkSjOpaackwFIBDogFAX7lcXRG5aojYO2GU3uVDFQe6klnYxgqCpUl0EVdYAh
9XQuuy0u1JDdl2OlnN4efUJBeojAcEKzaWAel53o2t3rDh0Z7xvxQEarj4mYTTA+
T9Of4rYDIdwX3EnmQunRJgV0+CHwF0sLvDxVC6XvSyb0ddzzC0RTSewUG4WTu7wR
s/GJN7C+1DIr19DitI5PiBoFarxgdLDnN9byiAd65brhmEmDNUr2Y8Au6+SHWYTV
C5jDJJGzLDzNvoaDJmHIZcTjG2bbQy8J8WkPqDvYoUpTxLJuQTB8dKDmAyRXGuEZ
WJ2nOaJcdp2k6TKla3w1+AUCAwEAAaNTMFEwHQYDVR0OBBYEFNU4pEQJKWSlQ+uO
3urf3n+gAHVeMB8GA1UdIwQYMBaAFNU4pEQJKWSlQ+uO3urf3n+gAHVeMA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAKAYt/+TdJRs+5Z9KwzPj0g4
jcO0Q22nTGJ1pezK79OJpGfGr1iMnMG5CyLhPhlgTG0tY5uLPGPg0SQ6mS3//VYk
z09mwgBlWLXROHYGJBluNiKy6iICXZnfn4kiozaxlJC/Q0+kj6UcoF/KXao8MVTv
6ubpkpbcE8CtuESn9OiNGM1W9MLgb33mODCCI59ti51SuhYFPRDwAVlS4w3Mqb/H
CNshF43tm2hAb13hsMuoqqrUn00AzxAA2Rxk0314EYbRYNI8zTx2SFJUOzRm5Rhg
fwjWGj359GDF0+dAm7Hx2dZdYEs3lq+jO65oGD376rKzWdaKZ5CIrUSVbzAtiOCh
pPk8LCBRBEPnxFfVVFCaqZmqPe318eFlIn51EDoMmsp6lCI5oEb3w3QvvJETlL9x
wiN54NG4i2lGuVM9z9k7pCHhZ6pp4j+QEfWDQ2nLddA76gS6x3sxAfknsFA06nuX
YN764Kd2QhAFAmIo0T9zmwOf/ODUhJVs4Okl8lhGUcv+RfMPT8LH97UCMB28wHrI
aOBEQiqD8iTEL1Ymy6qF/BG85leliyGslzIeBGMyTkU7owUkdnplxDRrmkALMp8J
QEaBNccRzjhdPAMYhGzxdjd6TY7X3WZCs3DwHoIrOAW1n2fu7ROCXeg+6zywbG0I
ZFsjNKejskq6kmEdzkLW
-----END CERTIFICATE-----

 

Create HTTPS web server

Let us update our previous go code to use ListenAndServeTLS instead of ListenAndServe to server the traffic over TLS:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

var tlsCertFile = "/root/goexamples/code1/certs/certbundle.pem"
var tlsKeyFile = "/root/goexamples/code1/certs/server.key"

func welcomeHandler(res http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(res, "Hello GoLinuxCloud Members!\n")
}

func apiHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "Hello, world!\n")
}

func healthCheckHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "ok\n")
}

func setupHandlers(mux *http.ServeMux) {
	mux.HandleFunc("/healthz", healthCheckHandler)
	mux.HandleFunc("/api", apiHandler)
	mux.HandleFunc("/", welcomeHandler)

}

func main() {

	listenAddr := os.Getenv("LISTEN_ADDR")
	if len(listenAddr) == 0 {
		listenAddr = ":8443"
	}

	mux := http.NewServeMux()
	setupHandlers(mux)

	log.Fatal(http.ListenAndServeTLS(listenAddr, tlsCertFile, tlsKeyFile, mux))

}

Next we can try to query our handlers using curl command and additionally we will use -k to perform insecure connection. To avoid this we will have to place CA certificate into our HTTPS server and establish communication using the same CA certificate from the client. You can read more about such configuration at Setup & verify mutual TLS authentication (MTLS) with openssl

# curl -k -X GET https://localhost:8443/
Hello GoLinuxCloud Members!

# curl -k -X GET https://localhost:8443/api
Hello, world!

# curl -k -X GET https://localhost:8443/healthz
ok

 

Create Client to connect to HTTPS Server (InSecure, TLS, MTLS)

In this section we will create a client which will communicate with our HTTPS web server over following interfaces:

  • Insecure: Client and Server will not perform any kind of validation of the certificates and just establish the communication
  • TLS: Server will validate the CA certificate passed by client used to sign the server certificate. The CA certificate available with client must be the one which was used to sign server certificate.
  • MTLS: Both server and client will validate each other's certificate using the CA certificate.

 

Load Certificate and Key Pair

We will use tls.LoadX509KeyPair to load our certificate and private key which just takes these two as input argument.  The files must contain PEM encoded data.

// Load client cert
cert, err := tls.LoadX509KeyPair("/root/goexamples/code1/certs/server.crt", "/root/goexamples/code1/certs/server.key")
if err != nil {
	panic(err)
}

 

Load CA Certificate

We will use ioutil.ReadFile to read the CA certificate file and then create a certificate bundle using x509.NewCertPool. So we can pass as many number of CA certificates to this pool. In our case since we have single CA certificate so we will just add this one:

// Load CA cert
caCert, err := ioutil.ReadFile("/root/goexamples/code1/certs/cacert.pem")
if err != nil {
	panic(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

 

Create TLS Config

Next tlsConfig optionally provides a TLS configuration for use by ServeTLS and ListenAndServeTLS.

tlsConfig := &tls.Config{
	Certificates: []tls.Certificate{cert},
	RootCAs:      caCertPool,
	//InsecureSkipVerify: true,  //Enable this incase the certificate is invalid. example. certificate contains fqdn as CN but we are accessing using IP
}

 

Create TLS Transport

For control over proxies, TLS configuration, keep-alives, and other settings, create a Transport:

transport := &http.Transport{
	TLSClientConfig: tlsConfig,
	MaxIdleConns:    10,
	IdleConnTimeout: 30 * time.Second,
}
client := &http.Client{Transport: transport}

 

Create HTTPS client

Following code will communicate with our HTTPS web server using MTLS or TLS or Insecure based on the AUTH_TYPE environment variable. In this example I have not created a separate client certificate so I will use server certificate as my client certificate for performing MTLS based communication as I have added both serverAuth and clientAuth in my certificate's x509 extension.

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	var tlsConfig *tls.Config

	url := "https://localhost:8443/"
	method := "GET"

	switch os.Getenv("AUTH_TYPE") {
	case "mtls":
		fmt.Println("AUTH_TYPE set as mtls")
		// Load public/private key pair from a pair of files. The files must contain PEM encoded data.
		cert, err := tls.LoadX509KeyPair("/root/goexamples/code1/certs/server.crt", "/root/goexamples/code1/certs/server.key")
		if err != nil {
			panic(err)
		}
		// Load CA cert
		caCert, err := ioutil.ReadFile("/root/goexamples/code1/certs/cacert.pem")
		if err != nil {
			panic(err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		tlsConfig = &tls.Config{
			Certificates: []tls.Certificate{cert},
			RootCAs:      caCertPool,
		}

	case "tls":
		fmt.Println("AUTH_TYPE set as tls")
		// Load CA cert
		caCert, err := ioutil.ReadFile("/root/goexamples/code1/certs/cacert.pem")
		if err != nil {
			panic(err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)

		tlsConfig = &tls.Config{
			RootCAs: caCertPool,
		}

	default:
		fmt.Println("Insecure communication selected, skipping server verification")
		tlsConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
	}

	transport := &http.Transport{
		TLSClientConfig: tlsConfig,
		MaxIdleConns:    10,
		IdleConnTimeout: 30 * time.Second,
	}
	client := &http.Client{Transport: transport}

	for i := 1; i < 5; i++ {
		payloadStr := fmt.Sprintf("test the %v time", i)
		payload := strings.NewReader(payloadStr)
		req, err := http.NewRequest(method, url, payload)

		if err != nil {
			fmt.Println(err)
			return
		}
		req.Header.Add("Content-Type", "text/plain")

		res, err := client.Do(req)
		if err != nil {
			fmt.Println(err)
			return
		}
		defer res.Body.Close()

		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			fmt.Println(err)
			return
		}
		fmt.Print(string(body))
	}
}

When AUTH_TYPE is set to mtls:

# export AUTH_TYPE=mtls

# go run client.go 
AUTH_TYPE set as mtls
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!

 

When AUTH_TYPE is set to tls:

# export AUTH_TYPE=tls

# go run client.go 
AUTH_TYPE set as tls
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!

 

When AUTH_TYPE is set to insecure:

# unset AUTH_TYPE

# go run client.go 
Insecure communication selected, skipping server verification
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!
Hello GoLinuxCloud Members!

 

Summary

This article covered a lot of ground, including:

  • Basic knowledge of Golang HTTPS and certificates.
  • A brief overview of the various software tools available for working with certificates and keys.
  • How to write a basic and advanced HTTPS server in Go, with detailed instructions.
  • How to write an HTTPS client in Go, with detailed instructions.
  • How to have a secure and insecure communication using TLS, MTLS and insecure

 

References

https://www.ssl.com/
https://www.openssl.org/
https://pkg.go.dev/net/http
https://en.wikipedia.org/wiki/HTTPS

 

Views: 44

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on LinkedIn.

Categories GO

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment