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<