-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Solution (Note to Les Googlers)
My question was, as I misinterpreted the documentation.
GetCertificate == SNICallback
- You cannot cast
net.Conn
tohttp.Conn
, you can only castnet.Listener
tohttp.Listener
- i.e.
server := &http.Serve{}; server.Server(tlsListener)
- i.e.
See examples at
- https://github.com/coolaj86/golang-https-example/tree/https-server
- https://github.com/coolaj86/golang-https-example
The crux of the issue In 68 lines:
package main
import (
"crypto/tls"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
)
type myHandler struct{}
func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Host)
fmt.Println(r.Method)
fmt.Println(r.RequestURI)
fmt.Println(r.URL) // also has many keys, such as Query
for k, v := range r.Header {
fmt.Println(k, v)
}
fmt.Println(r.Body)
// End the request
fmt.Fprintf(w, "Hi there, %s %q? Wow!\n\nWith Love,\n\t%s", r.Method, r.URL.Path[1:], r.Host)
}
func main() {
port := uint(8443)
certsPath := "/etc/letsencrypt/live"
defaultHost := "localhost.daplie.com"
fmt.Printf("Loading Certificates %s/%s/{privkey.pem,fullchain.pem}\n", certsPath, defaultHost)
privkeyPath := filepath.Join(certsPath, defaultHost, "privkey.pem")
certPath := filepath.Join(certsPath, defaultHost, "fullchain.pem")
cert, err := tls.LoadX509KeyPair(certPath, privkeyPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Couldn't load default certificates: %s\n", err)
os.Exit(1)
}
addr := ":" + strconv.Itoa(int(port))
conn, err := net.Listen("tcp", addr)
if nil != err {
fmt.Fprintf(os.Stderr, "Couldn't bind to TCP socket %q: %s\n", addr, err)
os.Exit(1)
}
tlsConfig := new(tls.Config)
tlsConfig.Certificates = []tls.Certificate{cert}
tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &cert, nil
}
tlsListener := tls.NewListener(conn, tlsConfig)
server := &http.Server{
Addr: addr,
Handler: &myHandler{},
}
host := strings.ToLower(defaultHost)
fmt.Printf("Listening on https://%s:%d\n", host, port)
server.Serve(tlsListener)
}
Original Question
https://LetsEncrypt.org's release is just around the corner, but it's currently not possible to dynamically retrieve and renew certificates in go with an active http server.
To do so requires fixing a tiny regression introduced sometime between the move from httputils and now. See https://golang.org/pkg/net/http/httputil/#ServerConn.
We need to re-expose http.NewConn and http.conn.Serve.
See the diff: coolaj86@1a30898
I've got a working demo of dynamically loading certificates with this change here:
https://gist.github.com/coolaj86/16ed8fd810e19dec71be
I've already signed the CLA and with a little coaching I'm sure I could turn my example into an appropriate test case, but I'm way out of my league with the 37-page explanation of how to make a pull request...
See also #11649