diff --git a/cmd/serverNameExample_grpcGwPbExample/initial/createService.go b/cmd/serverNameExample_grpcGwPbExample/initial/createService.go index 43698d8..f5cf82d 100644 --- a/cmd/serverNameExample_grpcGwPbExample/initial/createService.go +++ b/cmd/serverNameExample_grpcGwPbExample/initial/createService.go @@ -18,6 +18,7 @@ func CreateServices() []app.IServer { // case 1, create a http service without registry httpServer := server.NewHTTPServer_pbExample(httpAddr, server.WithHTTPIsProd(cfg.App.Env == "prod"), + server.WithHTTPTLS(cfg.HTTP.TLS), ) // case 2, Create a http service and register it with consul or etcd or nacos @@ -25,6 +26,7 @@ func CreateServices() []app.IServer { //httpServer := server.NewHTTPServer_pbExample(httpAddr, // server.WithHTTPRegistry(httpRegistry, httpInstance), // server.WithHTTPIsProd(cfg.App.Env == "prod"), + // server.WithHTTPTLS(cfg.HTTP.TLS), //) servers = append(servers, httpServer) diff --git a/cmd/serverNameExample_grpcHttpPbExample/initial/createService.go b/cmd/serverNameExample_grpcHttpPbExample/initial/createService.go index c6ae82e..9c52ce6 100644 --- a/cmd/serverNameExample_grpcHttpPbExample/initial/createService.go +++ b/cmd/serverNameExample_grpcHttpPbExample/initial/createService.go @@ -19,6 +19,7 @@ func CreateServices() []app.IServer { // case 1, create http and grpc services without registry httpServer := server.NewHTTPServer(httpAddr, server.WithHTTPIsProd(cfg.App.Env == "prod"), + server.WithHTTPTLS(cfg.HTTP.TLS), ) grpcServer := server.NewGRPCServer(grpcAddr) @@ -27,6 +28,7 @@ func CreateServices() []app.IServer { //httpServer := server.NewHTTPServer(httpAddr, // server.WithHTTPRegistry(httpRegistry, httpInstance), // server.WithHTTPIsProd(cfg.App.Env == "prod"), + // server.WithHTTPTLS(cfg.HTTP.TLS), //) //grpcRegistry, grpcInstance := registerService("grpc", cfg.App.Host, cfg.Grpc.Port) //grpcServer := server.NewGRPCServer(grpcAddr, diff --git a/cmd/serverNameExample_httpExample/initial/createService.go b/cmd/serverNameExample_httpExample/initial/createService.go index 36b554c..c670578 100644 --- a/cmd/serverNameExample_httpExample/initial/createService.go +++ b/cmd/serverNameExample_httpExample/initial/createService.go @@ -18,6 +18,7 @@ func CreateServices() []app.IServer { httpAddr := ":" + strconv.Itoa(cfg.HTTP.Port) httpServer := server.NewHTTPServer(httpAddr, server.WithHTTPIsProd(cfg.App.Env == "prod"), + server.WithHTTPTLS(cfg.HTTP.TLS), ) servers = append(servers, httpServer) diff --git a/cmd/serverNameExample_httpPbExample/initial/createService.go b/cmd/serverNameExample_httpPbExample/initial/createService.go index 7074514..56bfc91 100644 --- a/cmd/serverNameExample_httpPbExample/initial/createService.go +++ b/cmd/serverNameExample_httpPbExample/initial/createService.go @@ -18,6 +18,7 @@ func CreateServices() []app.IServer { httpAddr := ":" + strconv.Itoa(cfg.HTTP.Port) httpServer := server.NewHTTPServer_pbExample(httpAddr, server.WithHTTPIsProd(cfg.App.Env == "prod"), + server.WithHTTPTLS(cfg.HTTP.TLS), ) servers = append(servers, httpServer) diff --git a/cmd/serverNameExample_mixExample/initial/createService.go b/cmd/serverNameExample_mixExample/initial/createService.go index 6679229..af93a8d 100644 --- a/cmd/serverNameExample_mixExample/initial/createService.go +++ b/cmd/serverNameExample_mixExample/initial/createService.go @@ -26,6 +26,7 @@ func CreateServices() []app.IServer { httpServer := server.NewHTTPServer(httpAddr, server.WithHTTPRegistry(httpRegistry, httpInstance), server.WithHTTPIsProd(cfg.App.Env == "prod"), + server.WithHTTPTLS(cfg.HTTP.TLS), ) servers = append(servers, httpServer) diff --git a/cmd/sponge/commands/generate/rpc-gw-pb.go b/cmd/sponge/commands/generate/rpc-gw-pb.go index 1914fad..42298bb 100644 --- a/cmd/sponge/commands/generate/rpc-gw-pb.go +++ b/cmd/sponge/commands/generate/rpc-gw-pb.go @@ -212,10 +212,6 @@ func (g *rpcGwPbGenerator) addFields(r replacer.Replacer) []replacer.Field { Old: appConfigFileMark2, New: getDBConfigCode(""), // no db config }, - { // replace the configuration of the *.yml file - Old: appConfigFileMark, - New: "", - }, //{ // replace the contents of the model/init.go file // Old: modelInitDBFileMark, // New: getInitDBCode(DBDriverMysql), // default is mysql diff --git a/cmd/sponge/commands/generate/template.go b/cmd/sponge/commands/generate/template.go index dd29bdd..c53fdde 100644 --- a/cmd/sponge/commands/generate/template.go +++ b/cmd/sponge/commands/generate/template.go @@ -370,7 +370,17 @@ func NewCenter(configFile string) (*Center, error) { httpServerConfigCode = `# http server settings http: port: 8080 # listen port - timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s` + timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s + tls: + # TLS mode options: + # self-signed - Use localhost self-signed certificate + # encrypt - Use Let's Encrypt (requires domain & email) + # external - Use external certificates (requires certFile & keyFile) + enableMode: "" + domain: "" # Required if enableMode = encrypt + email: "" # Required if enableMode = encrypt + certFile: "" # Required if enableMode = external, absolute path of cert file + keyFile: "" # Required if enableMode = external, absolute path of key file` rpcServerConfigCode = `# grpc server settings grpc: @@ -414,6 +424,16 @@ grpcClient: http: port: 8080 # listen port timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s + tls: + # TLS mode options: + # self-signed - Use localhost self-signed certificate + # encrypt - Use Let's Encrypt (requires domain & email) + # external - Use external certificates (requires certFile & keyFile) + enableMode: "" + domain: "" # Required if enableMode = encrypt + email: "" # Required if enableMode = encrypt + certFile: "" # Required if enableMode = external, absolute path of cert file + keyFile: "" # Required if enableMode = external, absolute path of key file # grpc client-side settings, support for setting up multiple grpc clients. @@ -441,7 +461,17 @@ grpcClient: grpcAndHTTPServerConfigCode = `# http server settings http: port: 8080 # listen port - timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s + timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s + tls: + # TLS mode options: + # self-signed - Use localhost self-signed certificate + # encrypt - Use Let's Encrypt (requires domain & email) + # external - Use external certificates (requires certFile & keyFile) + enableMode: "" + domain: "" # Required if enableMode = encrypt + email: "" # Required if enableMode = encrypt + certFile: "" # Required if enableMode = external, absolute path of cert file + keyFile: "" # Required if enableMode = external, absolute path of key file # grpc server settings diff --git a/configs/serverNameExample.yml b/configs/serverNameExample.yml index 23b4295..562a85f 100644 --- a/configs/serverNameExample.yml +++ b/configs/serverNameExample.yml @@ -23,7 +23,16 @@ app: http: port: 8080 # listen port timeout: 0 # request timeout, unit(second), if 0 means not set, if greater than 0 means set timeout, if enableHTTPProfile is true, it needs to set 0 or greater than 60s - + tls: + # TLS mode options: + # self-signed - Use localhost self-signed certificate + # encrypt - Use Let's Encrypt (requires domain & email) + # external - Use external certificates (requires certFile & keyFile) + enableMode: "" + domain: "" # Required if enableMode = encrypt + email: "" # Required if enableMode = encrypt + certFile: "" # Required if enableMode = external, absolute path of cert file + keyFile: "" # Required if enableMode = external, absolute path of key file # grpc server settings grpc: diff --git a/internal/config/serverNameExample.go b/internal/config/serverNameExample.go index 2b20e18..50e0f39 100644 --- a/internal/config/serverNameExample.go +++ b/internal/config/serverNameExample.go @@ -76,6 +76,14 @@ type ServerSecure struct { Type string `yaml:"type" json:"type"` } +type TLS struct { + CertFile string `yaml:"certFile" json:"certFile"` + Domain string `yaml:"domain" json:"domain"` + Email string `yaml:"email" json:"email"` + EnableMode string `yaml:"enableMode" json:"enableMode"` + KeyFile string `yaml:"keyFile" json:"keyFile"` +} + type App struct { CacheType string `yaml:"cacheType" json:"cacheType"` EnableCircuitBreaker bool `yaml:"enableCircuitBreaker" json:"enableCircuitBreaker"` @@ -169,4 +177,5 @@ type NacosRd struct { type HTTP struct { Port int `yaml:"port" json:"port"` Timeout int `yaml:"timeout" json:"timeout"` + TLS TLS `yaml:"tls" json:"tls"` } diff --git a/internal/server/http.go b/internal/server/http.go index 7ba67e4..cad2e62 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -9,8 +9,10 @@ import ( "github.com/gin-gonic/gin" "github.com/go-dev-frame/sponge/pkg/app" + "github.com/go-dev-frame/sponge/pkg/httpsrv" "github.com/go-dev-frame/sponge/pkg/servicerd/registry" + "github.com/go-dev-frame/sponge/internal/config" "github.com/go-dev-frame/sponge/internal/routers" ) @@ -18,7 +20,7 @@ var _ app.IServer = (*httpServer)(nil) type httpServer struct { addr string - server *http.Server + server *httpsrv.Server instance *registry.ServiceInstance iRegistry registry.Registry @@ -33,8 +35,8 @@ func (s *httpServer) Start() error { } } - if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - return fmt.Errorf("listen server error: %v", err) + if err := s.server.Run(); err != nil { + return fmt.Errorf("run %s service error: %v", s.server.Scheme(), err) } return nil } @@ -56,7 +58,29 @@ func (s *httpServer) Stop() error { // String comment func (s *httpServer) String() string { - return "http service address " + s.addr + return s.server.Scheme() + " service address is " + s.addr +} + +func newServer(server *http.Server, tls config.TLS) *httpsrv.Server { + var c *httpsrv.Server + switch httpsrv.Mode(tls.EnableMode) { + case httpsrv.ModeTLSSelfSigned: + c = httpsrv.New(server, httpsrv.NewTLSSelfSignedConfig()) + case httpsrv.ModeTLSEncrypt: + c = httpsrv.New(server, + httpsrv.NewTLSEAutoEncryptConfig( + tls.Domain, + tls.Email, + // enable http redirect to https, port 80 to 443, default is false + //httpsrv.WithTLSEncryptEnableRedirect(), + ), + ) + case httpsrv.ModeTLSExternal: + c = httpsrv.New(server, httpsrv.NewTLSExternalConfig(tls.CertFile, tls.KeyFile)) + default: + c = httpsrv.New(server) // default is http, no tls + } + return c } // NewHTTPServer creates a new http server @@ -82,7 +106,7 @@ func NewHTTPServer(addr string, opts ...HTTPOption) app.IServer { return &httpServer{ addr: addr, - server: server, + server: newServer(server, o.tls), iRegistry: o.iRegistry, instance: o.instance, } @@ -113,7 +137,7 @@ func NewHTTPServer_pbExample(addr string, opts ...HTTPOption) app.IServer { //no return &httpServer{ addr: addr, - server: server, + server: newServer(server, o.tls), iRegistry: o.iRegistry, instance: o.instance, } diff --git a/internal/server/http.go.noregistry b/internal/server/http.go.noregistry index 6c94b9f..be3d90c 100644 --- a/internal/server/http.go.noregistry +++ b/internal/server/http.go.noregistry @@ -9,7 +9,9 @@ import ( "github.com/gin-gonic/gin" "github.com/go-dev-frame/sponge/pkg/app" + "github.com/go-dev-frame/sponge/pkg/httpsrv" + "github.com/go-dev-frame/sponge/internal/config" "github.com/go-dev-frame/sponge/internal/routers" ) @@ -17,13 +19,13 @@ var _ app.IServer = (*httpServer)(nil) type httpServer struct { addr string - server *http.Server + server *httpsrv.Server } // Start http service func (s *httpServer) Start() error { - if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { - return fmt.Errorf("listen server error: %v", err) + if err := s.server.Run(); err != nil { + return fmt.Errorf("run %s service error: %v", s.server.Scheme(), err) } return nil } @@ -36,7 +38,29 @@ func (s *httpServer) Stop() error { // String comment func (s *httpServer) String() string { - return "http service address " + s.addr + return s.server.Scheme() + " service address is " + s.addr +} + +func newServer(server *http.Server, tls config.TLS) *httpsrv.Server { + var c *httpsrv.Server + switch httpsrv.Mode(tls.EnableMode) { + case httpsrv.ModeTLSSelfSigned: + c = httpsrv.New(server, httpsrv.NewTLSSelfSignedConfig()) + case httpsrv.ModeTLSEncrypt: + c = httpsrv.New(server, + httpsrv.NewTLSEAutoEncryptConfig( + tls.Domain, + tls.Email, + // enable http redirect to https, port 80 to 443, default is false + //httpsrv.WithTLSEncryptEnableRedirect(), + ), + ) + case httpsrv.ModeTLSExternal: + c = httpsrv.New(server, httpsrv.NewTLSExternalConfig(tls.CertFile, tls.KeyFile)) + default: + c = httpsrv.New(server) + } + return c } // NewHTTPServer creates a new http server @@ -54,39 +78,14 @@ func NewHTTPServer(addr string, opts ...HTTPOption) app.IServer { server := &http.Server{ Addr: addr, Handler: router, + //ReadTimeout: time.Second*30, + //WriteTimeout: time.Second*60, + IdleTimeout: time.Second * 60, MaxHeaderBytes: 1 << 20, } return &httpServer{ addr: addr, - server: server, + server: newServer(server, o.tls), } } - -// delete the templates code start - -// NewHTTPServer_pbExample creates a new web server -func NewHTTPServer_pbExample(addr string, opts ...HTTPOption) app.IServer { //nolint - o := defaultHTTPOptions() - o.apply(opts...) - - if o.isProd { - gin.SetMode(gin.ReleaseMode) - } else { - gin.SetMode(gin.DebugMode) - } - - router := routers.NewRouter_pbExample() - server := &http.Server{ - Addr: addr, - Handler: router, - MaxHeaderBytes: 1 << 20, - } - - return &httpServer{ - addr: addr, - server: server, - } -} - -// delete the templates code end diff --git a/internal/server/http_option.go b/internal/server/http_option.go index 9450541..4533b67 100644 --- a/internal/server/http_option.go +++ b/internal/server/http_option.go @@ -2,6 +2,8 @@ package server import ( "github.com/go-dev-frame/sponge/pkg/servicerd/registry" + + "github.com/go-dev-frame/sponge/internal/config" ) // HTTPOption setting up http @@ -11,6 +13,7 @@ type httpOptions struct { isProd bool instance *registry.ServiceInstance iRegistry registry.Registry + tls config.TLS } func defaultHTTPOptions() *httpOptions { @@ -41,3 +44,10 @@ func WithHTTPRegistry(iRegistry registry.Registry, instance *registry.ServiceIns o.instance = instance } } + +// WithHTTPTLS setting up tls +func WithHTTPTLS(tls config.TLS) HTTPOption { + return func(o *httpOptions) { + o.tls = tls + } +} diff --git a/internal/server/http_option.go.noregistry b/internal/server/http_option.go.noregistry index faa2b05..911d55a 100644 --- a/internal/server/http_option.go.noregistry +++ b/internal/server/http_option.go.noregistry @@ -1,10 +1,15 @@ package server +import ( + "github.com/go-dev-frame/sponge/internal/config" +) + // HTTPOption setting up http type HTTPOption func(*httpOptions) type httpOptions struct { isProd bool + tls config.TLS } func defaultHTTPOptions() *httpOptions { @@ -25,3 +30,10 @@ func WithHTTPIsProd(isProd bool) HTTPOption { o.isProd = isProd } } + +// WithHTTPTLS setting up tls +func WithHTTPTLS(tls config.TLS) HTTPOption { + return func(o *httpOptions) { + o.tls = tls + } +} diff --git a/internal/server/http_test.go b/internal/server/http_test.go index 3bbe586..a4b985d 100644 --- a/internal/server/http_test.go +++ b/internal/server/http_test.go @@ -85,11 +85,12 @@ func TestHTTPServerMock(t *testing.T) { instance: ®istry.ServiceInstance{}, iRegistry: &iRegistry{}, } - s.server = &http.Server{ + server := &http.Server{ Addr: addr, Handler: http.NewServeMux(), MaxHeaderBytes: 1 << 20, } + s.server = newServer(server, config.Get().HTTP.TLS) go func() { time.Sleep(time.Second * 3) @@ -113,3 +114,48 @@ func (i *iRegistry) Register(ctx context.Context, service *registry.ServiceInsta func (i *iRegistry) Deregister(ctx context.Context, service *registry.ServiceInstance) error { return nil } + +func Test_newServer(t *testing.T) { + tests := []struct { + name string + tls config.TLS + scheme string + }{ + { + name: "no_tls", + tls: config.TLS{}, + scheme: "http", + }, + { + name: "tls_self_signed", + tls: config.TLS{ + EnableMode: "self-signed", + }, + scheme: "https", + }, + { + name: "tls_encrypt", + tls: config.TLS{ + EnableMode: "encrypt", + Domain: "example.com", + Email: "admin@example.com", + }, + scheme: "https", + }, + { + name: "tls_external", + tls: config.TLS{ + EnableMode: "external", + CertFile: "cert.pem", + KeyFile: "key.pem", + }, + scheme: "https", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := newServer(&http.Server{}, tt.tls) + assert.Equal(t, tt.scheme, server.Scheme()) + }) + } +}