Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
APP_NAME=Fuse

PORT=9090
# Path prefix when hosted behind a reverse proxy (e.g. api.example.com/fuse) so the Swagger UI at
# /docs works under the prefix. The proxy's X-Forwarded-Prefix header takes precedence if set.
# SERVER_BASE_PATH=/fuse

# Database: memory | postgres
DB_DRIVER=memory
Expand Down
19 changes: 17 additions & 2 deletions internal/actors/mux_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package actors
import (
"net/http"
"strconv"
"strings"

"ergo.services/ergo/act"
"ergo.services/ergo/gen"
Expand Down Expand Up @@ -84,10 +85,24 @@ func (m *muxServer) Init(_ ...any) error {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(spec.ReadDoc()))
})
// When FUSE is hosted under a reverse-proxy path prefix (e.g. /fuse), the /docs redirect and
// the Swagger UI spec URL must carry that prefix or the browser drops it. The prefix comes from
// the proxy's X-Forwarded-Prefix header when set, else SERVER_BASE_PATH.
configuredBasePath := strings.TrimRight(m.config.Server.BasePath, "/")
muxRouter.HandleFunc("/docs", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/docs/index.html", http.StatusMovedPermanently)
prefix := strings.TrimRight(r.Header.Get("X-Forwarded-Prefix"), "/")
if prefix == "" {
prefix = configuredBasePath
}
http.Redirect(w, r, prefix+"/docs/index.html", http.StatusMovedPermanently)
})
muxRouter.PathPrefix("/docs/").Handler(httpSwagger.WrapHandler)
// The UI loads its spec relatively ("doc.json" resolves under <prefix>/docs/) so it works
// behind any prefix; a configured base path makes it explicit/absolute.
specURL := "doc.json"
if configuredBasePath != "" {
specURL = configuredBasePath + "/docs/doc.json"
}
muxRouter.PathPrefix("/docs/").Handler(httpSwagger.Handler(httpSwagger.URL(specURL)))
m.Log().Info("swagger documentation available at /docs or /docs/index.html")

// create and spawn a web server meta-process
Expand Down
5 changes: 5 additions & 0 deletions internal/app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ type (
ServerConfig struct {
Host string `env:"HOST" envDefault:"0.0.0.0"`
Port string `env:"PORT" envDefault:"9090"`
// BasePath is the URL path prefix the engine is reachable under when behind a
// reverse proxy (e.g. "/fuse" for https://api.example.com/fuse). It is used to build
// the Swagger UI redirect/spec URL so /docs works under the prefix. The proxy's
// X-Forwarded-Prefix header takes precedence when present. Empty = served at root.
BasePath string `env:"SERVER_BASE_PATH"`
}

// ClusterConfig configuration for ergo distributed clustering
Expand Down
Loading