Search code examples
gohttpshttp2

Is it possible to host multiple domain TLS in golang with net/http?


I have multiple domain (let's say abc.com and xyz.org) with diffrent certificate. Is it possible to use key and certificate based on hostname without going deep low level and net.Listen, etc. Just using simple http.ListenAndServeTLS(...) or similar ? Basically like what nginx does.


Solution

  • BuildNameToCertificate() will sniff the hostname from the cert. If none match the SNI info it serves the [0]. https://golang.org/src/crypto/tls/common.go?s=18204:18245#L947

    Update for Go 1.14 - see https://github.com/golang/go/commit/eb93c684d40de4924fc0664d7d9e98a84d5a100b

    package main
    
    import (
        "crypto/tls"
        "net/http"
        "time"
    
        "log"
    )
    
    func myHandler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("tls"))
    }
    
    func main() {
        t := log.Logger{}
        var err error
        tlsConfig := &tls.Config{}
        tlsConfig.Certificates = make([]tls.Certificate, 3)
        // go http server treats the 0'th key as a default fallback key
        tlsConfig.Certificates[0], err = tls.LoadX509KeyPair("test0.pem", "key.pem")
        if err != nil {
            t.Fatal(err)
        }
        tlsConfig.Certificates[1], err = tls.LoadX509KeyPair("test1.pem", "key.pem")
        if err != nil {
            t.Fatal(err)
        }
        tlsConfig.Certificates[2], err = tls.LoadX509KeyPair("test2.pem", "key.pem")
        if err != nil {
            t.Fatal(err)
        }
    
        // as of go 1.14 this line is no longer needed
        // load the certs as above and skip BuildNameToCertificate()
        tlsConfig.BuildNameToCertificate()
    
        http.HandleFunc("/", myHandler)
        server := &http.Server{
            ReadTimeout:    10 * time.Second,
            WriteTimeout:   10 * time.Second,
            MaxHeaderBytes: 1 << 20,
            TLSConfig:      tlsConfig,
        }
    
        listener, err := tls.Listen("tcp", ":8443", tlsConfig)
        if err != nil {
            t.Fatal(err)
        }
        log.Fatal(server.Serve(listener))
    }