Hi Curtis,
While I appreciate your reply, like most similar examples that I have seen, Example, it does not deal with http -> https redirection for multiple hosts.
For those that may be following his thread here are some code extracts & structure comments of what I have so far:
Each host’s root/public_html directory sits within a sites directory: sites -> siteA, sites -> siteB etc. This is where the static content for each host is served from.
I create my router/mux: package router
package router
type dmux struct {
StaticRoutes map[string]http.Handler
APIRoutes map[string]http.HandlerFunc
}
var Router = dmux{
StaticRoutes: make(map[string]http.Handler),
APIRoutes: make(map[string]http.HandlerFunc),
}
LoadStaticSites method on the dmux struct:
func (mx dmux) LoadStaticSites() error {
fileServer := http.FileServer(http.Dir(path.Join("/var/www/sites", "siteA")))
mx.StaticRoutes["siteA"] = fileServer
fileServer = http.FileServer(http.Dir(path.Join("/var/www/sites", "siteB")))
mx.StaticRoutes["siteB"] = fileServer
return nil
}
The ServeHTTP method of the route/mux is:
func (mx dmux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if staticHandler := mx.StaticRoutes[r.Host]; staticHandler != nil {
// This check is done here so that every hosted site will have access to the API handlers
if APIHandler := mx.APIRoutes[r.URL.Path]; APIHandler != nil {
// Check for an API Route
APIHandler.ServeHTTP(w, r)
} else {
staticHandler.ServeHTTP(w, r)
}
} else {
// Handle host names for which no handler is registered
http.Error(w, "Forbidden", 403) // Or Redirect?
}
}`
From main.go : package main
func init() {
err := router.Router.LoadStaticSites()
if err != nil {
fmt.Println("Failed to load sites.")
panic(err)
}
// Load API routes
router.Router.APIRoutes[`/email`] = apiHandlers.Email
router.Router.APIRoutes[`/samples`] = apiHandlers.Samples
}
func main() {
var m *autocert.Manager
var httpsSrv *http.Server
prod := true
log.Printf("PROD: %v",prod )
if prod {
m = &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("site1.dab", "www.site1.dab", "site2.dab", "www.site2.dab"),
Cache: autocert.DirCache("./certs-cache"),
// Use Letsencrypts staging server for testing
Client: &acme.Client{
DirectoryURL: "https://acme-staging-v02.api.letsencrypt.org/directory",
},
}
httpsSrv = makeHTTPServer()
httpsSrv.Addr = ":443"
httpsSrv.Handler = router.Router
httpsSrv.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate}
go func() {
fmt.Printf("Starting HTTPS server on %s\n", httpsSrv.Addr)
err := httpsSrv.ListenAndServeTLS("", "")
if err != nil {
log.Fatalf("HTTP TLS Server failed with %s", err)
}
}()
}
var httpSrv *http.Server
if prod {
httpSrv = makeHTTPToHTTPSRedirectServer()
} else {
log.Println("Running HTTP")
httpSrv = makeHTTPServer()
httpSrv.Handler = router.Router
}
//allow autocert handle Let's Encrypt callbacks over http
if m != nil {
httpSrv.Handler = m.HTTPHandler(httpSrv.Handler)
}
httpSrv.Addr = ":80"
log.Fatal(httpSrv.ListenAndServe())
} // End of main
func makeHTTPServer() *http.Server {
return &http.Server{
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 120 * time.Second,
}
}
This function is where I get all types of issues E.G. circular redirects … when I attempt to run HTTPS. HTTP works OK
func makeHTTPToHTTPSRedirectServer() *http.Server {
handleRedirect := func(w http.ResponseWriter, r *http.Request) {
newURI := "https://" + r.Host + r.URL.String()
http.Redirect(w, r, newURI, http.StatusMovedPermanently)
}
router.Router.APIRoutes[`/`] = handleRedirect
router.Router.StaticRoutes[`/`] = http.HandlerFunc(handleRedirect)
return makeHTTPServer()
}
As I wrote in the original post, I am relatively new to GO with about a years experience, but this is my first encounter with a ‘public facing’ HTTP/HTTPS server.