diff --git a/beszel/Makefile b/beszel/Makefile index 19379a2..529db3d 100644 --- a/beszel/Makefile +++ b/beszel/Makefile @@ -7,7 +7,7 @@ SKIP_WEB ?= false # Set executable extension based on target OS EXE_EXT := $(if $(filter windows,$(OS)),.exe,) -.PHONY: tidy build-agent build-hub build clean lint dev-server dev-agent dev-hub dev generate-locales +.PHONY: tidy build-agent build-hub build-hub-dev build clean lint dev-server dev-agent dev-hub dev generate-locales .DEFAULT_GOAL := build clean: @@ -53,6 +53,10 @@ build-agent: tidy build-dotnet-conditional build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui) GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" beszel/cmd/hub +build-hub-dev: tidy + mkdir -p ./site/dist && touch ./site/dist/index.html + GOOS=$(OS) GOARCH=$(ARCH) go build -tags development -o ./build/beszel-dev_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" beszel/cmd/hub + build: build-agent build-hub generate-locales: @@ -73,9 +77,9 @@ dev-hub: export ENV=dev dev-hub: mkdir -p ./site/dist && touch ./site/dist/index.html @if command -v entr >/dev/null 2>&1; then \ - find ./cmd/hub/*.go ./internal/{alerts,hub,records,users}/*.go | entr -r -s "cd ./cmd/hub && go run . serve --http 0.0.0.0:8090"; \ + find ./cmd/hub/*.go ./internal/{alerts,hub,records,users}/*.go | entr -r -s "cd ./cmd/hub && go run -tags development . serve --http 0.0.0.0:8090"; \ else \ - cd ./cmd/hub && go run . serve --http 0.0.0.0:8090; \ + cd ./cmd/hub && go run -tags development . serve --http 0.0.0.0:8090; \ fi dev-agent: diff --git a/beszel/internal/hub/hub.go b/beszel/internal/hub/hub.go index d8eec7a..3f56ca5 100644 --- a/beszel/internal/hub/hub.go +++ b/beszel/internal/hub/hub.go @@ -8,13 +8,10 @@ import ( "beszel/internal/hub/systems" "beszel/internal/records" "beszel/internal/users" - "beszel/site" "crypto/ed25519" "encoding/pem" "fmt" - "io/fs" "net/http" - "net/http/httputil" "net/url" "os" "path" @@ -164,55 +161,6 @@ func (h *Hub) initialize(e *core.ServeEvent) error { return nil } -// startServer sets up the server for Beszel -func (h *Hub) startServer(se *core.ServeEvent) error { - // TODO: exclude dev server from production binary - switch h.IsDev() { - case true: - proxy := httputil.NewSingleHostReverseProxy(&url.URL{ - Scheme: "http", - Host: "localhost:5173", - }) - se.Router.GET("/{path...}", func(e *core.RequestEvent) error { - proxy.ServeHTTP(e.Response, e.Request) - return nil - }) - default: - // parse app url - parsedURL, err := url.Parse(h.appURL) - if err != nil { - return err - } - // fix base paths in html if using subpath - basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/" - indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html") - indexContent := strings.ReplaceAll(string(indexFile), "./", basePath) - indexContent = strings.Replace(indexContent, "{{V}}", beszel.Version, 1) - indexContent = strings.Replace(indexContent, "{{HUB_URL}}", h.appURL, 1) - // set up static asset serving - staticPaths := [2]string{"/static/", "/assets/"} - serveStatic := apis.Static(site.DistDirFS, false) - // get CSP configuration - csp, cspExists := GetEnv("CSP") - // add route - se.Router.GET("/{path...}", func(e *core.RequestEvent) error { - // serve static assets if path is in staticPaths - for i := range staticPaths { - if strings.Contains(e.Request.URL.Path, staticPaths[i]) { - e.Response.Header().Set("Cache-Control", "public, max-age=2592000") - return serveStatic(e) - } - } - if cspExists { - e.Response.Header().Del("X-Frame-Options") - e.Response.Header().Set("Content-Security-Policy", csp) - } - return e.HTML(http.StatusOK, indexContent) - }) - } - return nil -} - // registerCronJobs sets up scheduled tasks func (h *Hub) registerCronJobs(_ *core.ServeEvent) error { // delete old system_stats and alerts_history records once every hour diff --git a/beszel/internal/hub/server_development.go b/beszel/internal/hub/server_development.go new file mode 100644 index 0000000..e7a34d5 --- /dev/null +++ b/beszel/internal/hub/server_development.go @@ -0,0 +1,23 @@ +//go:build development + +package hub + +import ( + "net/http/httputil" + "net/url" + + "github.com/pocketbase/pocketbase/core" +) + +// startServer sets up the development server for Beszel +func (h *Hub) startServer(se *core.ServeEvent) error { + proxy := httputil.NewSingleHostReverseProxy(&url.URL{ + Scheme: "http", + Host: "localhost:5173", + }) + se.Router.GET("/{path...}", func(e *core.RequestEvent) error { + proxy.ServeHTTP(e.Response, e.Request) + return nil + }) + return nil +} diff --git a/beszel/internal/hub/server_production.go b/beszel/internal/hub/server_production.go new file mode 100644 index 0000000..831d0b5 --- /dev/null +++ b/beszel/internal/hub/server_production.go @@ -0,0 +1,51 @@ +//go:build !development + +package hub + +import ( + "beszel" + "beszel/site" + "io/fs" + "net/http" + "net/url" + "strings" + + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" +) + +// startServer sets up the production server for Beszel +func (h *Hub) startServer(se *core.ServeEvent) error { + // parse app url + parsedURL, err := url.Parse(h.appURL) + if err != nil { + return err + } + // fix base paths in html if using subpath + basePath := strings.TrimSuffix(parsedURL.Path, "/") + "/" + indexFile, _ := fs.ReadFile(site.DistDirFS, "index.html") + indexContent := strings.ReplaceAll(string(indexFile), "./", basePath) + indexContent = strings.Replace(indexContent, "{{V}}", beszel.Version, 1) + indexContent = strings.Replace(indexContent, "{{HUB_URL}}", h.appURL, 1) + // set up static asset serving + staticPaths := [2]string{"/static/", "/assets/"} + serveStatic := apis.Static(site.DistDirFS, false) + // get CSP configuration + csp, cspExists := GetEnv("CSP") + // add route + se.Router.GET("/{path...}", func(e *core.RequestEvent) error { + // serve static assets if path is in staticPaths + for i := range staticPaths { + if strings.Contains(e.Request.URL.Path, staticPaths[i]) { + e.Response.Header().Set("Cache-Control", "public, max-age=2592000") + return serveStatic(e) + } + } + if cspExists { + e.Response.Header().Del("X-Frame-Options") + e.Response.Header().Set("Content-Security-Policy", csp) + } + return e.HTML(http.StatusOK, indexContent) + }) + return nil +}