diff --git a/docker-compose.yml b/docker-compose.yml index af28b1f..adcb84c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,18 +4,18 @@ services: gateway: image: hyperioxx/frontman:latest ports: - - 8080:8080 - - 8000:8000 + - 8082:8080 + - 8002:8000 volumes: - ./certs:/certs environment: - FRONTMAN_SERVICE_TYPE=yaml - FRONTMAN_MONGO_URL=mongodb://mongo:27017 - - FRONTMAN_API_ADDR=0.0.0.0:8080 - - FRONTMAN_GATEWAY_ADDR=0.0.0.0:8000 - - FRONTMAN_API_SSL_ENABLED=false - - FRONTMAN_GATEWAY_SSL_ENABLED=false - mongo: - image: mongo:latest - ports: - - 27017:27017 \ No newline at end of file + - FRONTMAN_API_ADDR=0.0.0.0:8082 + - FRONTMAN_GATEWAY_ADDR=0.0.0.0:8002 + - FRONTMAN_API_SSL_ENABLED=true + - FRONTMAN_GATEWAY_SSL_ENABLED=true + - FRONTMAN_API_SSL_CERT=/certs/server.crt + - FRONTMAN_API_SSL_KEY=/certs/server.key + - FRONTMAN_GATEWAY_SSL_CERT=/certs/server.crt + - FRONTMAN_GATEWAY_SSL_KEY=/certs/server.key \ No newline at end of file diff --git a/gateway.go b/gateway.go index 82871d6..06bc136 100644 --- a/gateway.go +++ b/gateway.go @@ -82,53 +82,73 @@ func NewGateway(conf *config.Config) (*Gateway, error) { } func (gw *Gateway) Start() error { - apiAddr := gw.conf.APIConfig.Addr - if apiAddr == "" { - apiAddr = "0.0.0.0:8080" - } - gatewayAddr := gw.conf.GatewayConfig.Addr - if gatewayAddr == "" { - gatewayAddr = "0.0.0.0:8000" - } - - var apiHandler http.Handler - var gatewayHandler http.Handler - - if gw.conf.APIConfig.SSL.Enabled { - apiHandler = gw.service - cert, err := loadCert(gw.conf.APIConfig.SSL.Cert, gw.conf.APIConfig.SSL.Key) - if err != nil { - return err - } - apiServer := createServer(apiAddr, apiHandler, &cert) - log.Println("Starting Frontman Gateway with SSL...") - go startServer(apiServer) - } else { - apiHandler = gw.service - api := createServer(apiAddr, apiHandler, nil) - log.Println("Starting Frontman Gateway...") - go startServer(api) - } - - if gw.conf.GatewayConfig.SSL.Enabled { - gatewayHandler = gw.router - cert, err := loadCert(gw.conf.GatewayConfig.SSL.Cert, gw.conf.GatewayConfig.SSL.Key) - if err != nil { - return err - } - gatewayServer := createServer(gatewayAddr, gatewayHandler, &cert) - log.Println("Starting Gateway with SSL...") - startServer(gatewayServer) - } else { - gatewayHandler = gw.router - gateway := createServer(gatewayAddr, gatewayHandler, nil) - log.Println("Starting Gateway...") - startServer(gateway) - } + apiAddr := gw.conf.APIConfig.Addr + if apiAddr == "" { + apiAddr = "0.0.0.0:8080" + } + gatewayAddr := gw.conf.GatewayConfig.Addr + if gatewayAddr == "" { + gatewayAddr = "0.0.0.0:8000" + } + + var apiHandler http.Handler + var gatewayHandler http.Handler + + if gw.conf.APIConfig.SSL.Enabled { + apiHandler = gw.service + cert, err := loadCert(gw.conf.APIConfig.SSL.Cert, gw.conf.APIConfig.SSL.Key) + if err != nil { + return err + } + apiServer := createServer(apiAddr, apiHandler, &cert) + log.Printf("Started Frontman API with SSL on %s\n", apiAddr) + go startServer(apiServer) + } else { + apiHandler = gw.service + api := createServer(apiAddr, apiHandler, nil) + log.Printf("Started Frontman API on %s\n", apiAddr) + go startServer(api) + } + + if gw.conf.GatewayConfig.SSL.Enabled { + gatewayHandler = gw.router + cert, err := loadCert(gw.conf.GatewayConfig.SSL.Cert, gw.conf.GatewayConfig.SSL.Key) + if err != nil { + return err + } + + // Redirect HTTP traffic to HTTPS + httpAddr := "0.0.0.0:80" + httpRedirect := createRedirectServer(httpAddr, gatewayAddr) + log.Printf("Started HTTP redirect server on %s\n", httpAddr) + go startServer(httpRedirect) + + + gatewayServer := createServer(gatewayAddr, gatewayHandler, &cert) + log.Printf("Started Frontman Gateway with SSL on %s\n", gatewayAddr) + startServer(gatewayServer) + } else { + gatewayHandler = gw.router + gateway := createServer(gatewayAddr, gatewayHandler, nil) + log.Printf("Started Frontman Gateway on %s", gatewayAddr) + startServer(gateway) + } + + return nil +} - return nil +func createRedirectServer(addr string, redirectAddr string) *http.Server { + redirect := func(w http.ResponseWriter, req *http.Request) { + httpsURL := "https://" + req.Host + req.URL.Path + http.Redirect(w, req, httpsURL, http.StatusMovedPermanently) + } + return &http.Server{ + Addr: addr, + Handler: http.HandlerFunc(redirect), + } } + func loadCert(certFile, keyFile string) (tls.Certificate, error) { cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { diff --git a/gateway_test.go b/gateway_test.go new file mode 100644 index 0000000..7ed0ef0 --- /dev/null +++ b/gateway_test.go @@ -0,0 +1,36 @@ +package frontman + +import ( + "net/http" + "net/http/httptest" + "testing" +) + + +func TestCreateRedirectServer(t *testing.T) { + redirectAddr := "0.0.0.0:8000" + redirectServer := createRedirectServer("0.0.0.0:80", redirectAddr) + + // Create a test request to the redirect server + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if err != nil { + t.Fatal(err) + } + + // Create a test response recorder + rr := httptest.NewRecorder() + + // Call the redirect server's handler function + redirectServer.Handler.ServeHTTP(rr, req) + + // Check that the response has a 301 status code + if status := rr.Code; status != http.StatusMovedPermanently { + t.Errorf("Unexpected status code: got %v, expected %v", status, http.StatusMovedPermanently) + } + + // Check that the response includes a "Location" header with the expected value + expectedURL := "https://example.com/foo" + if location := rr.Header().Get("Location"); location != expectedURL { + t.Errorf("Unexpected Location header value: got %v, expected %v", location, expectedURL) + } +} \ No newline at end of file