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.
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()

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