diff --git a/CHANGELOG b/CHANGELOG
index 3051043b97e292428dd290a41ffb945ad8e3ca26..fb05607204f972aef59c5e33870d7b0f1f3eef6d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,10 @@
 
 Formerly known as 'gitlab-git-http-server'.
 
+0.5.1
+
+Deprecate -relativeURLRoot option, use -authBackend instead.
+
 0.5.0
 
 Send ALL GitLab requests through gitlab-workhorse.
diff --git a/README.md b/README.md
index f5158750a176774782e3d5ab1dd04fb392c752db..f28ffec8e72854a5cb371756396f45a905e86990 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,16 @@ Gitlab-workhorse can listen on either a TCP or a Unix domain socket. It
 can also open a second listening TCP listening socket with the Go
 [net/http/pprof profiler server](http://golang.org/pkg/net/http/pprof/).
 
+### Relative URL support
+
+If you are mounting GitLab at a relative URL, e.g.
+`example.com/gitlab`, then you should also use this relative URL in
+the `authBackend` setting:
+
+```
+gitlab-workhorse -authBackend http://localhost:8080/gitlab
+```
+
 ## Installation
 
 To install into `/usr/local/bin` run `make install`.
diff --git a/VERSION b/VERSION
index 8f0916f768f0487bcf8d33827ce2c8dcecb645c1..4b9fcbec101a6ff8ec68e0f95131ccda4861407f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.5.0
+0.5.1
diff --git a/authorization.go b/authorization.go
index c12ac90118d3710e0ebe569cb120531b566c4d1b..4f58a6d270150649666fdf0effd8aa930cb3515d 100644
--- a/authorization.go
+++ b/authorization.go
@@ -9,7 +9,7 @@ import (
 )
 
 func (u *upstream) newUpstreamRequest(r *http.Request, body io.Reader, suffix string) (*http.Request, error) {
-	url := u.authBackend + r.URL.RequestURI() + suffix
+	url := u.authBackend + "/" + strings.TrimPrefix(r.URL.RequestURI(), u.relativeURLRoot) + suffix
 	authReq, err := http.NewRequest(r.Method, url, body)
 	if err != nil {
 		return nil, err
diff --git a/main.go b/main.go
index e58feb96593ad7cb94534b0885fc091f657a31de..360793268b28b2b9d57dddbbd9229aee83a99e71 100644
--- a/main.go
+++ b/main.go
@@ -36,7 +36,6 @@ var listenUmask = flag.Int("listenUmask", 022, "Umask for Unix socket, default:
 var authBackend = flag.String("authBackend", "http://localhost:8080", "Authentication/authorization backend")
 var authSocket = flag.String("authSocket", "", "Optional: Unix domain socket to dial authBackend at")
 var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening address, e.g. 'localhost:6060'")
-var relativeURLRoot = flag.String("relativeURLRoot", "/", "GitLab relative URL root")
 var documentRoot = flag.String("documentRoot", "public", "Path to static files content")
 var responseHeadersTimeout = flag.Duration("proxyHeadersTimeout", time.Minute, "How long to wait for response headers when proxying the request")
 var developmentMode = flag.Bool("developmentMode", false, "Allow to serve assets from Rails app")
@@ -180,6 +179,5 @@ func main() {
 	}
 
 	upstream := newUpstream(*authBackend, proxyTransport)
-	upstream.SetRelativeURLRoot(*relativeURLRoot)
 	log.Fatal(http.Serve(listener, upstream))
 }
diff --git a/main_test.go b/main_test.go
index 67ef3a5e0bdcf5bd8d947f5506b16c8f08a772c7..9caa11859d5797e2428086a15424f82c8a9ff85c 100644
--- a/main_test.go
+++ b/main_test.go
@@ -13,6 +13,7 @@ import (
 	"os/exec"
 	"path"
 	"regexp"
+	"strings"
 	"testing"
 	"time"
 )
@@ -238,6 +239,29 @@ func TestAllowedApiDownloadZip(t *testing.T) {
 	runOrFail(t, extractCmd)
 }
 
+func TestAllowedApiDownloadZipWithSlash(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := testAuthServer(nil, 200, archiveOkBody(t, archiveName))
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	// Use foo%2Fbar instead of a numeric ID
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/foo%%2Fbar/repository/archive.zip", ws.URL))
+	if !strings.Contains(downloadCmd.Args[3], `projects/foo%2Fbar/repository`) {
+		t.Fatalf("Cannot find percent-2F: %v", downloadCmd.Args)
+	}
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("unzip", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
 func TestDownloadCacheHit(t *testing.T) {
 	prepareDownloadDir(t)
 
diff --git a/upstream.go b/upstream.go
index b6ac589714f675b5057cfc62830f94445c7b337e..4f100165c4ce5bc642012d1c8cfa5e5ea02e66ae 100644
--- a/upstream.go
+++ b/upstream.go
@@ -64,29 +64,30 @@ type gitRequest struct {
 }
 
 func newUpstream(authBackend string, authTransport http.RoundTripper) *upstream {
-	u, err := url.Parse(authBackend)
+	gitlabURL, err := url.Parse(authBackend)
 	if err != nil {
 		log.Fatalln(err)
 	}
+	relativeURLRoot := gitlabURL.Path
+	if !strings.HasSuffix(relativeURLRoot, "/") {
+		relativeURLRoot += "/"
+	}
+
+	// If the relative URL is '/foobar' and we tell httputil.ReverseProxy to proxy
+	// to 'http://example.com/foobar' then we get a redirect loop, so we clear the
+	// Path field here.
+	gitlabURL.Path = ""
 
 	up := &upstream{
 		authBackend:     authBackend,
 		httpClient:      &http.Client{Transport: authTransport},
-		httpProxy:       httputil.NewSingleHostReverseProxy(u),
-		relativeURLRoot: "/",
+		httpProxy:       httputil.NewSingleHostReverseProxy(gitlabURL),
+		relativeURLRoot: relativeURLRoot,
 	}
 	up.httpProxy.Transport = authTransport
 	return up
 }
 
-func (u *upstream) SetRelativeURLRoot(relativeURLRoot string) {
-	u.relativeURLRoot = relativeURLRoot
-
-	if !strings.HasSuffix(u.relativeURLRoot, "/") {
-		u.relativeURLRoot += "/"
-	}
-}
-
 func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
 	var g httpRoute
 
@@ -106,8 +107,8 @@ func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check URL Root
-	URIPath := cleanURIPath(r.URL.Path)
-	if !strings.HasPrefix(URIPath, u.relativeURLRoot) {
+	URIPath := cleanURIPath(r.URL.EscapedPath())
+	if !strings.HasPrefix(URIPath, u.relativeURLRoot) && URIPath+"/" != u.relativeURLRoot {
 		httpError(&w, r, fmt.Sprintf("Not found %q", URIPath), http.StatusNotFound)
 		return
 	}