diff --git a/fe/http.go b/fe/http.go
index 1e1b072ce80c742fcca54b38cb809ffd591f9f99..a0346d843dbf9bf7399ff06a44640a20aacaac22 100644
--- a/fe/http.go
+++ b/fe/http.go
@@ -10,6 +10,7 @@ import (
 	"net"
 	"net/http"
 	"net/url"
+	"path"
 	"path/filepath"
 	"strconv"
 	"strings"
@@ -129,6 +130,41 @@ func (h *HttpRedirector) serveM3U(mount *autoradio.Mount, w http.ResponseWriter,
 	io.WriteString(w, m3u)
 }
 
+// redirect replies to the request with a redirect to url, adding some
+// cache-busting headers. Code is mostly verbatim from net/http.
+func redirect(w http.ResponseWriter, r *http.Request, urlStr string, code int) {
+	if u, err := url.Parse(urlStr); err == nil {
+		oldpath := r.URL.Path
+		if oldpath == "" {
+			oldpath = "/"
+		}
+		if u.Scheme == "" {
+			if urlStr == "" || urlStr[0] != '/' {
+				olddir, _ := path.Split(oldpath)
+				urlStr = olddir + urlStr
+			}
+
+			var query string
+			if i := strings.Index(urlStr, "?"); i != -1 {
+				urlStr, query = urlStr[:i], urlStr[i:]
+			}
+
+			trailing := strings.HasSuffix(urlStr, "/")
+			urlStr = path.Clean(urlStr)
+			if trailing && !strings.HasSuffix(urlStr, "/") {
+				urlStr += "/"
+			}
+			urlStr += query
+		}
+	}
+
+	w.Header().Set("Location", urlStr)
+	w.Header().Set("Cache-Control", "max-age=0,no-cache,no-store")
+	w.Header().Set("Pragma", "no-cache")
+	w.Header().Set("Expires", "Thu, 1 Jan 1970 00:00:00 GMT")
+	w.WriteHeader(code)
+}
+
 // Serve a response for a client connection to a relay.
 func (h *HttpRedirector) serveRelay(mount *autoradio.Mount, w http.ResponseWriter, r *http.Request) {
 	// Find an active node.
@@ -144,7 +180,7 @@ func (h *HttpRedirector) serveRelay(mount *autoradio.Mount, w http.ResponseWrite
 		h.serveM3U(mount, w, r)
 	} else {
 		targetURL := streamUrl(relayAddr, mount.Name)
-		http.Redirect(w, r, targetURL, 302)
+		redirect(w, r, targetURL, 302)
 	}
 }