diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index 0212964750..832e6cf2e8 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -151,6 +151,8 @@ FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
 PROTOCOL = http
 DOMAIN = localhost
 ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
+; when STATIC_URL_PREFIX is empty it will follow APP_URL
+STATIC_URL_PREFIX = 
 ; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket.
 HTTP_ADDR = 0.0.0.0
 HTTP_PORT = 3000
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 6a5c5a36d7..005f756b32 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -104,6 +104,7 @@ var (
 	LetsEncryptTOS       bool
 	LetsEncryptDirectory string
 	LetsEncryptEmail     string
+	StaticURLPrefix      string
 
 	SSH = struct {
 		Disabled                 bool           `ini:"DISABLE_SSH"`
@@ -582,7 +583,7 @@ func NewContext() {
 		defaultAppURL += ":" + HTTPPort
 	}
 	AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
-	AppURL = strings.TrimRight(AppURL, "/") + "/"
+	AppURL = strings.TrimSuffix(AppURL, "/") + "/"
 
 	// Check if has app suburl.
 	appURL, err := url.Parse(AppURL)
@@ -592,6 +593,7 @@ func NewContext() {
 	// Suburl should start with '/' and end without '/', such as '/{subpath}'.
 	// This value is empty if site does not have sub-url.
 	AppSubURL = strings.TrimSuffix(appURL.Path, "/")
+	StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/")
 	AppSubURLDepth = strings.Count(AppSubURL, "/")
 	// Check if Domain differs from AppURL domain than update it to AppURL's domain
 	// TODO: Can be replaced with url.Hostname() when minimal GoLang version is 1.8
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 5a3969c098..dc2865254c 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -48,6 +48,9 @@ func NewFuncMap() []template.FuncMap {
 		"AppSubUrl": func() string {
 			return setting.AppSubURL
 		},
+		"StaticUrlPrefix": func() string {
+			return setting.StaticURLPrefix
+		},
 		"AppUrl": func() string {
 			return setting.AppURL
 		},
@@ -110,12 +113,12 @@ func NewFuncMap() []template.FuncMap {
 			}
 			return str[start:end]
 		},
-		"EllipsisString":        base.EllipsisString,
-		"DiffTypeToStr":         DiffTypeToStr,
-		"DiffLineTypeToStr":     DiffLineTypeToStr,
-		"Sha1":                  Sha1,
-		"ShortSha":              base.ShortSha,
-		"MD5":                   base.EncodeMD5,
+		"EllipsisString":    base.EllipsisString,
+		"DiffTypeToStr":     DiffTypeToStr,
+		"DiffLineTypeToStr": DiffLineTypeToStr,
+		"Sha1":              Sha1,
+		"ShortSha":          base.ShortSha,
+		"MD5":               base.EncodeMD5,
 		"ActionContent2Commits": ActionContent2Commits,
 		"PathEscape":            url.PathEscape,
 		"EscapePound": func(str string) string {
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
index 13718620da..802175ce7e 100644
--- a/templates/base/footer.tmpl
+++ b/templates/base/footer.tmpl
@@ -12,38 +12,38 @@
 
 	{{template "base/footer_content" .}}
 
-	<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
 {{if .RequireSimpleMDE}}
-	<script src="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/codemirror/mode/meta.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/mode/meta.js"></script>
 	<script>
-		CodeMirror.modeURL =  "{{AppSubUrl}}/vendor/plugins/codemirror/mode/%N/%N.js";
+		CodeMirror.modeURL =  "{{StaticUrlPrefix}}/vendor/plugins/codemirror/mode/%N/%N.js";
 	</script>
 {{end}}
 {{if .RequireGitGraph}}
 	<!-- graph -->
-	<script src="{{AppSubUrl}}/vendor/plugins/gitgraph/gitgraph.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js"></script>
 	<script src="{{AppSubUrl}}/js/draw.js"></script>
 {{end}}
 
 <!-- Third-party libraries -->
 {{if .RequireHighlightJS}}
-	<script src="{{AppSubUrl}}/vendor/plugins/highlight/highlight.pack.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/highlight/highlight.pack.js"></script>
 {{end}}
 {{if .RequireMinicolors}}
-	<script src="{{AppSubUrl}}/vendor/plugins/jquery.minicolors/jquery.minicolors.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.min.js"></script>
 {{end}}
 {{if .RequireDatetimepicker}}
-	<script src="{{AppSubUrl}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.js"></script>
 {{end}}
 {{if .RequireDropzone}}
-	<script src="{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.js"></script>
 {{end}}
 {{if .RequireU2F}}
-	<script src="{{AppSubUrl}}/vendor/plugins/u2f/index.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/u2f/index.js"></script>
 {{end}}
 {{if .EnableCaptcha}}
 	{{if eq .CaptchaType "recaptcha"}}
@@ -51,7 +51,7 @@
 	{{end}}
 {{end}}
 {{if .RequireTribute}}
-	<script src="{{AppSubUrl}}/vendor/plugins/tribute/tribute.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.min.js"></script>
 	<script>
 		var issuesTribute = new Tribute({
 			values: [
@@ -101,7 +101,7 @@
 					return ':' + item.original + ':';
 				},
 				menuItemTemplate: function (item) {
-					return '<img class="emoji" src="{{AppSubUrl}}/vendor/plugins/emojify/images/' + item.original + '.png"/>' + item.original;
+					return '<img class="emoji" src="{{StaticUrlPrefix}}/vendor/plugins/emojify/images/' + item.original + '.png"/>' + item.original;
 				}
 			}]
 		});
@@ -115,16 +115,16 @@
 		}
 	</script>
 {{end}}
-	<script src="{{AppSubUrl}}/vendor/plugins/emojify/emojify.min.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/clipboard/clipboard.min.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/vue/vue.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/vue/vue.min.js"></script>
 
 	<!-- JavaScript -->
-	<script src="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js"></script>
 	<script src="{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}"></script>
 {{if .EnableHeatmap}}
-	<script src="{{AppSubUrl}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.browser.js" charset="utf-8"></script>
 	<script type="text/javascript">
 		initHeatmap('user-heatmap', '{{.HeatmapUser}}');
 	</script>
diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl
index 6f680d4cb8..364e58a3d0 100644
--- a/templates/base/footer_content.tmpl
+++ b/templates/base/footer_content.tmpl
@@ -16,7 +16,7 @@
 					{{end}}
 				</div>
 			</div>
-			<a href="{{AppSubUrl}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a>
+			<a href="{{StaticUrlPrefix}}/vendor/librejs.html" data-jslicense="1">JavaScript licenses</a>
 			{{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
 			<a target="_blank" rel="noopener noreferrer" href="https://gitea.io">{{.i18n.Tr "website"}}</a>
 			{{if (or .ShowFooterVersion .PageIsAdmin)}}<span class="version">{{GoVer}}</span>{{end}}
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index 7cdfdd34be..658fb33a78 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -5,7 +5,7 @@
 	<meta name="viewport" content="width=device-width, initial-scale=1">
 	<meta http-equiv="x-ua-compatible" content="ie=edge">
 	<title>{{if .Title}}{{.Title}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
-	<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
+	<link rel="manifest" href="{{StaticUrlPrefix}}/manifest.json" crossorigin="use-credentials">
 
 	<script>
 		if ('serviceWorker' in navigator) {
@@ -70,35 +70,35 @@
 	THE SOFTWARE.
 	---
 	Licensing information for additional javascript libraries can be found at:
-	  {{AppSubUrl}}/vendor/librejs.html
+	  {{StaticUrlPrefix}}/vendor/librejs.html
 
 	@licend  The above is the entire license notice
         for the JavaScript code in this page.
 	*/`}}
 	</script>
 
-	<link rel="shortcut icon" href="{{AppSubUrl}}/img/favicon.png" />
-	<link rel="mask-icon" href="{{AppSubUrl}}/img/gitea-safari.svg" color="#609926">
-	<link rel="preload" href="{{AppSubUrl}}/vendor/assets/font-awesome/css/font-awesome.min.css" as="style" onload="this.rel='stylesheet'">
-	<noscript><link rel="stylesheet" href="{{AppSubUrl}}/vendor/assets/font-awesome/css/font-awesome.min.css"></noscript>
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/assets/octicons/octicons.min.css">
+	<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png" />
+	<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/gitea-safari.svg" color="#609926">
+	<link rel="preload" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css" as="style" onload="this.rel='stylesheet'">
+	<noscript><link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"></noscript>
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/octicons/octicons.min.css">
 
 {{if .RequireSimpleMDE}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css">
 {{end}}
 
 {{if .RequireGitGraph}}
 	<!-- graph -->
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/gitgraph/gitgraph.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.css">
 {{end}}
 
 {{if .RequireTribute}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/tribute/tribute.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.css">
 {{end}}
 
 	<!-- Stylesheet -->
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.css">
-	<link rel="stylesheet" href="{{AppSubUrl}}/css/index.css?v={{MD5 AppVer}}">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/index.css?v={{MD5 AppVer}}">
 	<noscript>
 		<style>
 			.dropdown:hover > .menu { display: block; }
@@ -107,25 +107,25 @@
 	</noscript>
 
 {{if .RequireHighlightJS}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/highlight/github.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/highlight/github.css">
 {{end}}
 {{if .RequireMinicolors}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css">
 {{end}}
 {{if .RequireDatetimepicker}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.css">
 {{end}}
 {{if .RequireDropzone}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/dropzone/dropzone.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.css">
 {{end}}
 {{if .EnableHeatmap}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/vue-calendar-heatmap/vue-calendar-heatmap.css">
 {{end}}
 	<style class="list-search-style"></style>
 
-	<script src="{{AppSubUrl}}/vendor/plugins/promise-polyfill/polyfill.min.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/cssrelpreload/loadCSS.min.js"></script>
-	<script src="{{AppSubUrl}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/promise-polyfill/polyfill.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/loadCSS.min.js"></script>
+	<script src="{{StaticUrlPrefix}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js"></script>
 {{if .PageIsUserProfile}}
 	<meta property="og:title" content="{{.Owner.Name}}" />
 	<meta property="og:type" content="profile" />
@@ -144,16 +144,16 @@
 {{else}}
 	<meta property="og:title" content="{{AppName}}">
 	<meta property="og:type" content="website" />
-	<meta property="og:image" content="{{AppUrl}}img/gitea-lg.png" />
+	<meta property="og:image" content="{{StaticUrlPrefix}}img/gitea-lg.png" />
 	<meta property="og:url" content="{{AppUrl}}" />
 	<meta property="og:description" content="{{MetaDescription}}">
 {{end}}
 {{if .IsSigned }}
 	{{ if ne .SignedUser.Theme "gitea" }}
-		<link rel="stylesheet" href="{{AppSubUrl}}/css/theme-{{.SignedUser.Theme}}.css">
+		<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css">
 	{{end}}
 {{else if ne DefaultTheme "gitea"}}
-	<link rel="stylesheet" href="{{AppSubUrl}}/css/theme-{{DefaultTheme}}.css">
+	<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{DefaultTheme}}.css">
 {{end}}
 {{template "custom/header" .}}
 </head>
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl
index 30316e7e5b..2db2594422 100644
--- a/templates/base/head_navbar.tmpl
+++ b/templates/base/head_navbar.tmpl
@@ -1,7 +1,7 @@
 <div class="ui container" id="navbar">
 	<div class="item brand" style="justify-content: space-between;">
 		<a href="{{AppSubUrl}}/">
-			<img class="ui mini image" src="{{AppSubUrl}}/img/gitea-sm.png">
+			<img class="ui mini image" src="{{StaticUrlPrefix}}/img/gitea-sm.png">
 		</a>
 		<div class="ui basic icon button mobile-only" id="navbar-expand-toggle">
 			<i class="sidebar icon"></i>
diff --git a/templates/home.tmpl b/templates/home.tmpl
index fa48cdc1b6..6fbc7678e9 100644
--- a/templates/home.tmpl
+++ b/templates/home.tmpl
@@ -3,7 +3,7 @@
 	<div class="ui stackable middle very relaxed page grid">
 		<div class="sixteen wide center aligned centered column">
 			<div>
-				<img class="logo" src="{{AppSubUrl}}/img/gitea-lg.png" />
+				<img class="logo" src="{{StaticUrlPrefix}}/img/gitea-lg.png" />
 			</div>
 			<div class="hero">
 				<h1 class="ui icon header title">