Golang HTTP and HTTPS servers with net/http and ListenAndServeTLS

Golang http and go http with net/http: golang http server example using ListenAndServe and ServeMux, golang https server and https golang with http.ListenAndServeTLS, golang http module meaning the standard library package, plus TLS client, mTLS pointers, and timeouts.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang HTTP and HTTPS servers with net/http and ListenAndServeTLS

People searching go http, golang http, golang http server, go http server, golang http server example, golang https, https golang, or golang https server are almost always working with the standard library net/http. Queries like http.ListenAndServeTLS map to http.ListenAndServeTLS (and http.Server.ListenAndServeTLS). Golang http module in search often means that package—not a third-party “HTTP module” from the module proxy. This guide gives a compact golang http server example, a TLS path with file-based ListenAndServeTLS, a no-cert-files HTTPS demo with httptest, and a shorter HTTPS client section (replace deprecated ioutil, fix common mistakes). For outbound timeouts, read HTTP client and server timeouts; for deep certificate operations, use OpenSSL and mutual TLS.

Competitive skim: official pkg.go.dev/net/http plus common tutorials stress owning an explicit http.ServeMux instead of http.DefaultServeMux, setting server timeouts, and never shipping InsecureSkipVerify: true outside local experiments.

Tested with Go 1.24 on Linux.


net/http: the go http stack

Go’s go http surface lives in net/http: http.Server, http.Client, http.Transport, http.ServeMux, and helpers like http.ListenAndServe. Import path:

go
import "net/http"

golang http server example: ListenAndServe and ServeMux

A minimal golang http server listens on an address and dispatches URLs to functions. Prefer an explicit mux instead of passing nil (which uses http.DefaultServeMux—any imported package can register on it).

go
package main

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

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

func healthz(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "ok\n")
}

func main() {
	addr := os.Getenv("LISTEN_ADDR")
	if addr == "" {
		addr = ":8080"
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/api", apiHandler)
	mux.HandleFunc("/healthz", healthz)

	log.Printf("listening on %s", addr)
	log.Fatal(http.ListenAndServe(addr, mux))
}

Run with go run ., then curl http://localhost:8080/api prints Hello, world! and /healthz prints ok.


golang https server and ListenAndServeTLS

http.ListenAndServeTLS (http.listenandservetls)

ListenAndServeTLS has the same shape as ListenAndServe but adds PEM paths:

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

The leaf certificate PEM is usually enough for the public cert chain; the private key must stay secret. Chaining the CA into the cert PEM is only needed when you want a single file bundle—many stacks pass fullchain.pem + privkey.pem separately instead.

The package-level helper http.ListenAndServeTLS(addr, certFile, keyFile, handler) is equivalent to starting an http.Server with only Addr, Handler, and default zero timeouts—fine for demos, but production services should set explicit deadlines (next subsection).

Generate real certificates with OpenSSL or your CA; follow certificate generation. On Ubuntu, ensure the CLI is present with install OpenSSL on Ubuntu. Test with curl -k https://localhost:8443/ only when you intentionally skip verification.

http.Server and ListenAndServeTLS

For timeouts and TLS on one struct, use http.Server:

go
package main

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

func main() {
	cert := os.Getenv("TLS_CERT_FILE")
	key := os.Getenv("TLS_KEY_FILE")
	if cert == "" || key == "" {
		log.Fatal("set TLS_CERT_FILE and TLS_KEY_FILE to PEM paths")
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("HTTPS ok\n"))
	})
	addr := ":8443"
	if a := os.Getenv("LISTEN_ADDR"); a != "" {
		addr = a
	}
	srv := &http.Server{
		Addr:              addr,
		Handler:           mux,
		ReadHeaderTimeout: 5 * time.Second,
		ReadTimeout:       10 * time.Second,
		WriteTimeout:      10 * time.Second,
		IdleTimeout:       60 * time.Second,
	}
	log.Fatal(srv.ListenAndServeTLS(cert, key))
}

Quick https golang without PEM files: httptest.NewTLSServer

For examples or tests, httptest.NewTLSServer starts an HTTPS server with an ephemeral cert. Use ts.Client() so the client trusts that cert.

go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
)

func main() {
	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "hello from https golang")
	}))
	defer ts.Close()

	resp, err := ts.Client().Get(ts.URL)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}

Running it prints hello from https golang. That answers “try https golang locally” before you wire ListenAndServeTLS to disk paths.


HTTPS client: TLS, mTLS, and local-only InsecureSkipVerify

Use crypto/tls with http.Transport{TLSClientConfig: …}. Read PEM material with os.ReadFile (not ioutil). For mTLS, load a client key pair and set Certificates; set RootCAs from your CA pool to verify the server. Production mutual authentication is spelled out in mutual TLS with OpenSSL.

Never leave InsecureSkipVerify: true in production—it disables server authentication.

Bug to avoid: calling defer resp.Body.Close() inside a for loop defers all closes until the function returns—read each body and close immediately, or use a small inner function per iteration. Inside a loop (with import "io" in the same file):

go
resp, err := client.Do(req)
if err != nil {
	return err
}
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
	return err
}
_ = body

Summary

Golang http and go http mean building servers and clients with net/http. A golang http server example is http.NewServeMux plus http.ListenAndServe. Golang https server work adds http.ListenAndServeTLS (the http.ListenAndServeTLS entry point people type) or http.Server.ListenAndServeTLS when you need timeouts. Golang http module in search is usually this standard library, not a go get dependency. For https golang experiments without files, httptest.NewTLSServer is the fastest loop; for real deployments, PEM on disk plus strict tls.Config and no insecure skips. Layer timeouts from the timeout article on both http.Server and http.Client.


References


Frequently Asked Questions

1. What do people mean by golang http module?

Usually the standard library package net/http (sometimes confused with a Go modules go.mod dependency); this article uses net/http only—no extra module beyond the toolchain.

2. How do I write a golang http server example or go http server?

Call http.ListenAndServe(addr, handler) with a http.Handler (often http.NewServeMux()); register paths with Handle or HandleFunc.

3. What is http.ListenAndServeTLS in Go?

http.ListenAndServeTLS(addr, certFile, keyFile, handler) starts an HTTPS listener using PEM certificate and key files on disk; http.Server.ListenAndServeTLS is the instance method variant.

4. How can I try golang https or a golang https server without OpenSSL first?

Use httptest.NewTLSServer in a test or small program: it mints a temporary certificate, exposes an https URL, and ts.Client() trusts it for local calls.

5. Where do HTTP timeouts fit in?

Configure http.Server read/write/header timeouts and sensible http.Client timeouts; see the dedicated timeout guide linked in the body.
Tuan Nguyen

Data Scientist

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 …