diff --git a/README.md b/README.md index 0e97feefc..168577975 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,10 @@ This command would need customizing for your environment. [This link](https://s Once you have a certificate and key file name them `stash.crt` and `stash.key` and place them in the same directory as the `config.yml` file, or the `~/.stash` directory. Stash detects these and starts up using HTTPS rather than HTTP. +## Basepath rewriting + +The basepath defaults to `/`. When running stash via a reverse proxy in a subpath, the basepath can be changed by having the reverse proxy pass `X-Forwarded-Prefix` (and optionally `X-Forwarded-Port`) headers. When detects these headers, it alters the basepath URL of the UI. + # Customization ## Themes and CSS Customization diff --git a/pkg/api/server.go b/pkg/api/server.go index cb969562c..6bb9e47b5 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -258,7 +258,15 @@ func Start() { if ext == ".html" || ext == "" { data, _ := uiBox.Find("index.html") - _, _ = w.Write(data) + + prefix := "" + if r.Header.Get("X-Forwarded-Prefix") != "" { + prefix = strings.TrimRight(r.Header.Get("X-Forwarded-Prefix"), "/") + } + + baseURLIndex := strings.Replace(string(data), "%BASE_URL%", prefix+"/", 2) + baseURLIndex = strings.Replace(baseURLIndex, "base href=\"/\"", fmt.Sprintf("base href=\"%s\"", prefix+"/"), 2) + _, _ = w.Write([]byte(baseURLIndex)) } else { isStatic, _ := path.Match("/static/*/*", r.URL.Path) if isStatic { @@ -372,11 +380,22 @@ func BaseURLMiddleware(next http.Handler) http.Handler { } else { scheme = "http" } - baseURL := scheme + "://" + r.Host + prefix := "" + if r.Header.Get("X-Forwarded-Prefix") != "" { + prefix = strings.TrimRight(r.Header.Get("X-Forwarded-Prefix"), "/") + } + + port := "" + forwardedPort := r.Header.Get("X-Forwarded-Port") + if forwardedPort != "" && forwardedPort != "80" && forwardedPort != "8080" { + port = ":" + forwardedPort + } + + baseURL := scheme + "://" + r.Host + port + prefix externalHost := config.GetInstance().GetExternalHost() if externalHost != "" { - baseURL = externalHost + baseURL = externalHost + prefix } r = r.WithContext(context.WithValue(ctx, BaseURLCtxKey, baseURL)) diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json index c36fd1989..f3e7f7e39 100644 --- a/ui/v2.5/package.json +++ b/ui/v2.5/package.json @@ -2,6 +2,7 @@ "name": "stash", "version": "0.1.0", "private": true, + "homepage": "./", "sideEffects": false, "scripts": { "start": "react-scripts start", diff --git a/ui/v2.5/public/index.html b/ui/v2.5/public/index.html index 322bc1d11..62c7d3940 100755 --- a/ui/v2.5/public/index.html +++ b/ui/v2.5/public/index.html @@ -1,6 +1,7 @@ + Stash + diff --git a/ui/v2.5/src/components/Changelog/versions/v0100.md b/ui/v2.5/src/components/Changelog/versions/v0100.md index a332998d3..1d5125020 100644 --- a/ui/v2.5/src/components/Changelog/versions/v0100.md +++ b/ui/v2.5/src/components/Changelog/versions/v0100.md @@ -1,6 +1,7 @@ #### 💥 Note: Please check your logs after migrating to this release. A log warning will be generated on startup if duplicate image checksums exist in your system. Search for the images using the logged checksums, and remove the unwanted ones. ### ✨ New Features +* Support subpaths when serving stash via reverse proxy. ([#1719](https://github.com/stashapp/stash/pull/1719)) * Added options to generate webp and static preview files for markers. ([#1604](https://github.com/stashapp/stash/pull/1604)) * Added sort by option for gallery rating. ([#1720](https://github.com/stashapp/stash/pull/1720)) * Added support for querying scene scrapers using keywords. ([#1712](https://github.com/stashapp/stash/pull/1712)) diff --git a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx index 3a9ee024e..c2ed3d11c 100644 --- a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx +++ b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx @@ -343,7 +343,7 @@ export class ScenePlayerImpl extends React.Component<
{ + const baseURL = window.STASH_BASE_URL; + if (baseURL === "%BASE_URL%") return "/"; + return baseURL; +}; + export const getPlatformURL = (ws?: boolean) => { - const platformUrl = new URL(window.location.origin); + const platformUrl = new URL(window.location.origin + getBaseURL()); if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") { platformUrl.port = process.env.REACT_APP_PLATFORM_PORT ?? "9999"; @@ -107,8 +113,8 @@ export const createClient = () => { wsPlatformUrl.protocol = "wss:"; } - const url = `${platformUrl.toString().slice(0, -1)}/graphql`; - const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`; + const url = `${platformUrl.toString()}graphql`; + const wsUrl = `${wsPlatformUrl.toString()}graphql`; const httpLink = createUploadLink({ uri: url, diff --git a/ui/v2.5/src/globals.d.ts b/ui/v2.5/src/globals.d.ts index 08dbb94ad..20db3882a 100644 --- a/ui/v2.5/src/globals.d.ts +++ b/ui/v2.5/src/globals.d.ts @@ -1,3 +1,5 @@ +// eslint-disable-next-line no-var +declare var STASH_BASE_URL: string; declare module "*.md"; declare module "string.prototype.replaceall"; declare module "mousetrap-pause"; diff --git a/ui/v2.5/src/index.tsx b/ui/v2.5/src/index.tsx index 9ebba95f9..bae8e45a0 100755 --- a/ui/v2.5/src/index.tsx +++ b/ui/v2.5/src/index.tsx @@ -4,14 +4,14 @@ import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; import { App } from "./App"; import { getClient } from "./core/StashService"; -import { getPlatformURL } from "./core/createClient"; +import { getPlatformURL, getBaseURL } from "./core/createClient"; import "./index.scss"; import * as serviceWorker from "./serviceWorker"; ReactDOM.render( <> - +