diff --git a/models/user/user.go b/models/user/user.go
index d5c4833cde..c1e3d5d1c7 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -565,7 +565,6 @@ var (
 		".",
 		"..",
 		".well-known",
-		"admin",
 		"api",
 		"assets",
 		"attachments",
diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go
index fa60836b7e..db481fbf59 100644
--- a/routers/api/v1/admin/hooks.go
+++ b/routers/api/v1/admin/hooks.go
@@ -45,7 +45,7 @@ func ListHooks(ctx *context.APIContext) {
 	}
 	hooks := make([]*api.Hook, len(sysHooks))
 	for i, hook := range sysHooks {
-		h, err := webhook_service.ToHook(setting.AppURL+"/admin", hook)
+		h, err := webhook_service.ToHook(setting.AppURL+"/-/admin", hook)
 		if err != nil {
 			ctx.Error(http.StatusInternalServerError, "convert.ToHook", err)
 			return
@@ -83,7 +83,7 @@ func GetHook(ctx *context.APIContext) {
 		}
 		return
 	}
-	h, err := webhook_service.ToHook("/admin/", hook)
+	h, err := webhook_service.ToHook("/-/admin/", hook)
 	if err != nil {
 		ctx.Error(http.StatusInternalServerError, "convert.ToHook", err)
 		return
diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index f1abd49a7d..4328878e19 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -100,7 +100,7 @@ func checkCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption)
 func AddSystemHook(ctx *context.APIContext, form *api.CreateHookOption) {
 	hook, ok := addHook(ctx, form, 0, 0)
 	if ok {
-		h, err := webhook_service.ToHook(setting.AppSubURL+"/admin", hook)
+		h, err := webhook_service.ToHook(setting.AppSubURL+"/-/admin", hook)
 		if err != nil {
 			ctx.Error(http.StatusInternalServerError, "convert.ToHook", err)
 			return
@@ -268,7 +268,7 @@ func EditSystemHook(ctx *context.APIContext, form *api.EditHookOption, hookID in
 		ctx.Error(http.StatusInternalServerError, "GetSystemOrDefaultWebhook", err)
 		return
 	}
-	h, err := webhook_service.ToHook(setting.AppURL+"/admin", updated)
+	h, err := webhook_service.ToHook(setting.AppURL+"/-/admin", updated)
 	if err != nil {
 		ctx.Error(http.StatusInternalServerError, "convert.ToHook", err)
 		return
diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go
index 6fc97c949e..37c54b5362 100644
--- a/routers/web/admin/admin.go
+++ b/routers/web/admin/admin.go
@@ -185,9 +185,9 @@ func DashboardPost(ctx *context.Context) {
 		}
 	}
 	if form.From == "monitor" {
-		ctx.Redirect(setting.AppSubURL + "/admin/monitor/cron")
+		ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/cron")
 	} else {
-		ctx.Redirect(setting.AppSubURL + "/admin")
+		ctx.Redirect(setting.AppSubURL + "/-/admin")
 	}
 }
 
diff --git a/routers/web/admin/applications.go b/routers/web/admin/applications.go
index 8583398074..9b48f21eca 100644
--- a/routers/web/admin/applications.go
+++ b/routers/web/admin/applications.go
@@ -23,8 +23,8 @@ var (
 func newOAuth2CommonHandlers() *user_setting.OAuth2CommonHandlers {
 	return &user_setting.OAuth2CommonHandlers{
 		OwnerID:            0,
-		BasePathList:       fmt.Sprintf("%s/admin/applications", setting.AppSubURL),
-		BasePathEditPrefix: fmt.Sprintf("%s/admin/applications/oauth2", setting.AppSubURL),
+		BasePathList:       fmt.Sprintf("%s/-/admin/applications", setting.AppSubURL),
+		BasePathEditPrefix: fmt.Sprintf("%s/-/admin/applications/oauth2", setting.AppSubURL),
 		TplAppEdit:         tplSettingsOauth2ApplicationEdit,
 	}
 }
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 3b89be0f8f..60e2b7c86f 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -324,7 +324,7 @@ func NewAuthSourcePost(ctx *context.Context) {
 	log.Trace("Authentication created by admin(%s): %s", ctx.Doer.Name, form.Name)
 
 	ctx.Flash.Success(ctx.Tr("admin.auths.new_success", form.Name))
-	ctx.Redirect(setting.AppSubURL + "/admin/auths")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/auths")
 }
 
 // EditAuthSource render editing auth source page
@@ -437,7 +437,7 @@ func EditAuthSourcePost(ctx *context.Context) {
 	log.Trace("Authentication changed by admin(%s): %d", ctx.Doer.Name, source.ID)
 
 	ctx.Flash.Success(ctx.Tr("admin.auths.update_success"))
-	ctx.Redirect(setting.AppSubURL + "/admin/auths/" + strconv.FormatInt(form.ID, 10))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/auths/" + strconv.FormatInt(form.ID, 10))
 }
 
 // DeleteAuthSource response for deleting an auth source
@@ -454,11 +454,11 @@ func DeleteAuthSource(ctx *context.Context) {
 		} else {
 			ctx.Flash.Error(fmt.Sprintf("auth_service.DeleteSource: %v", err))
 		}
-		ctx.JSONRedirect(setting.AppSubURL + "/admin/auths/" + url.PathEscape(ctx.PathParam(":authid")))
+		ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths/" + url.PathEscape(ctx.PathParam(":authid")))
 		return
 	}
 	log.Trace("Authentication deleted by admin(%s): %d", ctx.Doer.Name, source.ID)
 
 	ctx.Flash.Success(ctx.Tr("admin.auths.deletion_success"))
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/auths")
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths")
 }
diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go
index 2ae93e9cac..d067250a5b 100644
--- a/routers/web/admin/config.go
+++ b/routers/web/admin/config.go
@@ -40,7 +40,7 @@ func SendTestMail(ctx *context.Context) {
 		ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
 	}
 
-	ctx.Redirect(setting.AppSubURL + "/admin/config")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/config")
 }
 
 // TestCache test the cache settings
@@ -56,7 +56,7 @@ func TestCache(ctx *context.Context) {
 		}
 	}
 
-	ctx.Redirect(setting.AppSubURL + "/admin/config")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/config")
 }
 
 func shadowPasswordKV(cfgItem, splitter string) string {
diff --git a/routers/web/admin/emails.go b/routers/web/admin/emails.go
index f0d8555070..49338fbd7c 100644
--- a/routers/web/admin/emails.go
+++ b/routers/web/admin/emails.go
@@ -134,7 +134,7 @@ func ActivateEmail(ctx *context.Context) {
 		ctx.Flash.Info(ctx.Tr("admin.emails.updated"))
 	}
 
-	redirect, _ := url.Parse(setting.AppSubURL + "/admin/emails")
+	redirect, _ := url.Parse(setting.AppSubURL + "/-/admin/emails")
 	q := url.Values{}
 	if val := ctx.FormTrim("q"); len(val) > 0 {
 		q.Set("q", val)
diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go
index e40580b6e7..91ca6e3fa7 100644
--- a/routers/web/admin/hooks.go
+++ b/routers/web/admin/hooks.go
@@ -36,8 +36,8 @@ func DefaultOrSystemWebhooks(ctx *context.Context) {
 	sys["Title"] = ctx.Tr("admin.systemhooks")
 	sys["Description"] = ctx.Tr("admin.systemhooks.desc", "https://docs.gitea.com/usage/webhooks")
 	sys["Webhooks"], err = webhook.GetSystemWebhooks(ctx, optional.None[bool]())
-	sys["BaseLink"] = setting.AppSubURL + "/admin/hooks"
-	sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks"
+	sys["BaseLink"] = setting.AppSubURL + "/-/admin/hooks"
+	sys["BaseLinkNew"] = setting.AppSubURL + "/-/admin/system-hooks"
 	if err != nil {
 		ctx.ServerError("GetWebhooksAdmin", err)
 		return
@@ -46,8 +46,8 @@ func DefaultOrSystemWebhooks(ctx *context.Context) {
 	def["Title"] = ctx.Tr("admin.defaulthooks")
 	def["Description"] = ctx.Tr("admin.defaulthooks.desc", "https://docs.gitea.com/usage/webhooks")
 	def["Webhooks"], err = webhook.GetDefaultWebhooks(ctx)
-	def["BaseLink"] = setting.AppSubURL + "/admin/hooks"
-	def["BaseLinkNew"] = setting.AppSubURL + "/admin/default-hooks"
+	def["BaseLink"] = setting.AppSubURL + "/-/admin/hooks"
+	def["BaseLinkNew"] = setting.AppSubURL + "/-/admin/default-hooks"
 	if err != nil {
 		ctx.ServerError("GetWebhooksAdmin", err)
 		return
@@ -67,5 +67,5 @@ func DeleteDefaultOrSystemWebhook(ctx *context.Context) {
 		ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
 	}
 
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/hooks")
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/hooks")
 }
diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go
index 36303cbc06..5f7432e629 100644
--- a/routers/web/admin/notice.go
+++ b/routers/web/admin/notice.go
@@ -74,5 +74,5 @@ func EmptyNotices(ctx *context.Context) {
 
 	log.Trace("System notices deleted by admin (%s): [start: %d]", ctx.Doer.Name, 0)
 	ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
-	ctx.Redirect(setting.AppSubURL + "/admin/notices")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/notices")
 }
diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go
index 39f064a1be..2b9edc622d 100644
--- a/routers/web/admin/packages.go
+++ b/routers/web/admin/packages.go
@@ -99,7 +99,7 @@ func DeletePackageVersion(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("packages.settings.delete.success"))
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type")))
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type")))
 }
 
 func CleanupExpiredData(ctx *context.Context) {
@@ -109,5 +109,5 @@ func CleanupExpiredData(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("admin.packages.cleanup.success"))
-	ctx.Redirect(setting.AppSubURL + "/admin/packages")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/packages")
 }
diff --git a/routers/web/admin/queue.go b/routers/web/admin/queue.go
index dce8f8077f..59b17f88e6 100644
--- a/routers/web/admin/queue.go
+++ b/routers/web/admin/queue.go
@@ -53,7 +53,7 @@ func QueueSet(ctx *context.Context) {
 		maxNumber, err = strconv.Atoi(maxNumberStr)
 		if err != nil {
 			ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.maxnumberworkers.error"))
-			ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
+			ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
 			return
 		}
 		if maxNumber < -1 {
@@ -65,7 +65,7 @@ func QueueSet(ctx *context.Context) {
 
 	mq.SetWorkerMaxNumber(maxNumber)
 	ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.changed"))
-	ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
 }
 
 func QueueRemoveAllItems(ctx *context.Context) {
@@ -85,5 +85,5 @@ func QueueRemoveAllItems(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.remove_all_items_done"))
-	ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10))
 }
diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go
index e7c27145dc..75e5ee5d86 100644
--- a/routers/web/admin/repos.go
+++ b/routers/web/admin/repos.go
@@ -58,7 +58,7 @@ func DeleteRepo(ctx *context.Context) {
 	log.Trace("Repository deleted: %s", repo.FullName())
 
 	ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/repos?page=" + url.QueryEscape(ctx.FormString("page")) + "&sort=" + url.QueryEscape(ctx.FormString("sort")))
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/repos?page=" + url.QueryEscape(ctx.FormString("page")) + "&sort=" + url.QueryEscape(ctx.FormString("sort")))
 }
 
 // UnadoptedRepos lists the unadopted repositories
@@ -114,7 +114,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
 
 	dirSplit := strings.SplitN(dir, "/", 2)
 	if len(dirSplit) != 2 {
-		ctx.Redirect(setting.AppSubURL + "/admin/repos")
+		ctx.Redirect(setting.AppSubURL + "/-/admin/repos")
 		return
 	}
 
@@ -122,7 +122,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
 	if err != nil {
 		if user_model.IsErrUserNotExist(err) {
 			log.Debug("User does not exist: %s", dirSplit[0])
-			ctx.Redirect(setting.AppSubURL + "/admin/repos")
+			ctx.Redirect(setting.AppSubURL + "/-/admin/repos")
 			return
 		}
 		ctx.ServerError("GetUserByName", err)
@@ -160,5 +160,5 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
 		}
 		ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir))
 	}
-	ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + url.QueryEscape(page))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + url.QueryEscape(page))
 }
diff --git a/routers/web/admin/runners.go b/routers/web/admin/runners.go
index d73290a8db..4b89237364 100644
--- a/routers/web/admin/runners.go
+++ b/routers/web/admin/runners.go
@@ -9,5 +9,5 @@ import (
 )
 
 func RedirectToDefaultSetting(ctx *context.Context) {
-	ctx.Redirect(setting.AppSubURL + "/admin/actions/runners")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/actions/runners")
 }
diff --git a/routers/web/admin/stacktrace.go b/routers/web/admin/stacktrace.go
index b3b635af5b..ff751be621 100644
--- a/routers/web/admin/stacktrace.go
+++ b/routers/web/admin/stacktrace.go
@@ -42,5 +42,5 @@ func Stacktrace(ctx *context.Context) {
 func StacktraceCancel(ctx *context.Context) {
 	pid := ctx.PathParam("pid")
 	process.GetManager().Cancel(process.IDType(pid))
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/monitor/stacktrace")
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/monitor/stacktrace")
 }
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index 48ff8ea04b..a6b0b5c78b 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -215,14 +215,14 @@ func NewUserPost(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name))
-	ctx.Redirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10))
 }
 
 func prepareUserInfo(ctx *context.Context) *user_model.User {
 	u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64(":userid"))
 	if err != nil {
 		if user_model.IsErrUserNotExist(err) {
-			ctx.Redirect(setting.AppSubURL + "/admin/users")
+			ctx.Redirect(setting.AppSubURL + "/-/admin/users")
 		} else {
 			ctx.ServerError("GetUserByID", err)
 		}
@@ -481,7 +481,7 @@ func EditUserPost(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
-	ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 }
 
 // DeleteUser response for deleting a user
@@ -495,7 +495,7 @@ func DeleteUser(ctx *context.Context) {
 	// admin should not delete themself
 	if u.ID == ctx.Doer.ID {
 		ctx.Flash.Error(ctx.Tr("admin.users.cannot_delete_self"))
-		ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+		ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 		return
 	}
 
@@ -503,16 +503,16 @@ func DeleteUser(ctx *context.Context) {
 		switch {
 		case models.IsErrUserOwnRepos(err):
 			ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
-			ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+			ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 		case models.IsErrUserHasOrgs(err):
 			ctx.Flash.Error(ctx.Tr("admin.users.still_has_org"))
-			ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+			ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 		case models.IsErrUserOwnPackages(err):
 			ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages"))
-			ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+			ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 		case models.IsErrDeleteLastAdminUser(err):
 			ctx.Flash.Error(ctx.Tr("auth.last_admin"))
-			ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
+			ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid")))
 		default:
 			ctx.ServerError("DeleteUser", err)
 		}
@@ -521,7 +521,7 @@ func DeleteUser(ctx *context.Context) {
 	log.Trace("Account deleted by admin (%s): %s", ctx.Doer.Name, u.Name)
 
 	ctx.Flash.Success(ctx.Tr("admin.users.deletion_success"))
-	ctx.Redirect(setting.AppSubURL + "/admin/users")
+	ctx.Redirect(setting.AppSubURL + "/-/admin/users")
 }
 
 // AvatarPost response for change user's avatar request
@@ -538,7 +538,7 @@ func AvatarPost(ctx *context.Context) {
 		ctx.Flash.Success(ctx.Tr("settings.update_user_avatar_success"))
 	}
 
-	ctx.Redirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10))
+	ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10))
 }
 
 // DeleteAvatar render delete avatar page
@@ -552,5 +552,5 @@ func DeleteAvatar(ctx *context.Context) {
 		ctx.Flash.Error(err.Error())
 	}
 
-	ctx.JSONRedirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10))
+	ctx.JSONRedirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10))
 }
diff --git a/routers/web/repo/setting/runners.go b/routers/web/repo/setting/runners.go
index 93e6f518b0..3141d8f42a 100644
--- a/routers/web/repo/setting/runners.go
+++ b/routers/web/repo/setting/runners.go
@@ -76,7 +76,7 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
 			IsAdmin:            true,
 			RunnersTemplate:    tplAdminRunners,
 			RunnerEditTemplate: tplAdminRunnerEdit,
-			RedirectLink:       setting.AppSubURL + "/admin/actions/runners/",
+			RedirectLink:       setting.AppSubURL + "/-/admin/actions/runners/",
 		}, nil
 	}
 
diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go
index 45b6c0f39a..cc2e619f66 100644
--- a/routers/web/repo/setting/variables.go
+++ b/routers/web/repo/setting/variables.go
@@ -74,7 +74,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
 			RepoID:            0,
 			IsGlobal:          true,
 			VariablesTemplate: tplAdminVariables,
-			RedirectLink:      setting.AppSubURL + "/admin/actions/variables",
+			RedirectLink:      setting.AppSubURL + "/-/admin/actions/variables",
 		}, nil
 	}
 
diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go
index 7661599729..8d548c4e3d 100644
--- a/routers/web/repo/setting/webhook.go
+++ b/routers/web/repo/setting/webhook.go
@@ -100,8 +100,8 @@ func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) {
 		return &ownerRepoCtx{
 			IsAdmin:         true,
 			IsSystemWebhook: ctx.PathParam(":configType") == "system-hooks",
-			Link:            path.Join(setting.AppSubURL, "/admin/hooks"),
-			LinkNew:         path.Join(setting.AppSubURL, "/admin/", ctx.PathParam(":configType")),
+			Link:            path.Join(setting.AppSubURL, "/-/admin/hooks"),
+			LinkNew:         path.Join(setting.AppSubURL, "/-/admin/", ctx.PathParam(":configType")),
 			NewTemplate:     tplAdminHookNew,
 		}, nil
 	}
diff --git a/routers/web/web.go b/routers/web/web.go
index 69258bca18..80399ec499 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -683,7 +683,7 @@ func registerRoutes(m *web.Router) {
 	adminReq := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true, AdminRequired: true})
 
 	// ***** START: Admin *****
-	m.Group("/admin", func() {
+	m.Group("/-/admin", func() {
 		m.Get("", admin.Dashboard)
 		m.Get("/system_status", admin.SystemStatus)
 		m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl
index 174dda1e2a..7057169895 100644
--- a/templates/admin/auth/list.tmpl
+++ b/templates/admin/auth/list.tmpl
@@ -3,7 +3,7 @@
 		<h4 class="ui top attached header">
 			{{ctx.Locale.Tr "admin.auths.auth_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
 			<div class="ui right">
-				<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/auths/new">{{ctx.Locale.Tr "admin.auths.new"}}</a>
+				<a class="ui primary tiny button" href="{{AppSubUrl}}/-/admin/auths/new">{{ctx.Locale.Tr "admin.auths.new"}}</a>
 			</div>
 		</h4>
 		<div class="ui attached table segment">
@@ -23,12 +23,12 @@
 					{{range .Sources}}
 						<tr>
 							<td>{{.ID}}</td>
-							<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{.Name}}</a></td>
+							<td><a href="{{AppSubUrl}}/-/admin/auths/{{.ID}}">{{.Name}}</a></td>
 							<td>{{.TypeName}}</td>
 							<td>{{svg (Iif .IsActive "octicon-check" "octicon-x")}}</td>
 							<td>{{DateTime "short" .UpdatedUnix}}</td>
 							<td>{{DateTime "short" .CreatedUnix}}</td>
-							<td><a href="{{AppSubUrl}}/admin/auths/{{.ID}}">{{svg "octicon-pencil"}}</a></td>
+							<td><a href="{{AppSubUrl}}/-/admin/auths/{{.ID}}">{{svg "octicon-pencil"}}</a></td>
 						</tr>
 					{{end}}
 				</tbody>
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 87f18192a6..29a5e1b473 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -231,7 +231,7 @@
 					<div class="divider"></div>
 					<dt class="tw-py-1 tw-flex tw-items-center">{{ctx.Locale.Tr "admin.config.send_test_mail"}}</dt>
 					<dd class="tw-py-0">
-						<form class="ui form ignore-dirty" action="{{AppSubUrl}}/admin/config/test_mail" method="post">
+						<form class="ui form ignore-dirty" action="{{AppSubUrl}}/-/admin/config/test_mail" method="post">
 							{{.CsrfTokenHtml}}
 							<div class="ui tiny input">
 								<input type="email" name="email" placeholder="{{ctx.Locale.Tr "admin.config.test_email_placeholder"}}" size="29" required>
@@ -263,7 +263,7 @@
 				<div class="divider"></div>
 				<dt class="tw-py-1 tw-flex tw-items-center">{{ctx.Locale.Tr "admin.config.cache_test"}}</dt>
 				<dd class="tw-py-0">
-					<form class="ui form ignore-dirty" action="{{AppSubUrl}}/admin/config/test_cache" method="post">
+					<form class="ui form ignore-dirty" action="{{AppSubUrl}}/-/admin/config/test_cache" method="post">
 						{{.CsrfTokenHtml}}
 						<button class="ui tiny primary button">{{ctx.Locale.Tr "test"}}</button>
 					</form>
diff --git a/templates/admin/config_settings.tmpl b/templates/admin/config_settings.tmpl
index 02ab5fd0fb..6b9bb8275c 100644
--- a/templates/admin/config_settings.tmpl
+++ b/templates/admin/config_settings.tmpl
@@ -24,7 +24,7 @@
 	{{ctx.Locale.Tr "repository"}}
 </h4>
 <div class="ui attached segment">
-	<form class="ui form form-fetch-action" method="post" action="{{AppSubUrl}}/admin/config?key={{.SystemConfig.Repository.OpenWithEditorApps.DynKey}}">
+	<form class="ui form form-fetch-action" method="post" action="{{AppSubUrl}}/-/admin/config?key={{.SystemConfig.Repository.OpenWithEditorApps.DynKey}}">
 		<div class="field">
 			<details>
 				<summary>{{ctx.Locale.Tr "admin.config.open_with_editor_app_help"}}</summary>
diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl
index bb412ef146..1c16ed00ae 100644
--- a/templates/admin/cron.tmpl
+++ b/templates/admin/cron.tmpl
@@ -4,7 +4,7 @@
 		{{ctx.Locale.Tr "admin.monitor.cron"}}
 	</h4>
 	<div class="ui attached table segment">
-		<form method="post" action="{{AppSubUrl}}/admin">
+		<form method="post" action="{{AppSubUrl}}/-/admin">
 			<table class="ui very basic striped table unstackable tw-mb-0">
 				<thead>
 					<tr>
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index b82922df0c..af2349d288 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -9,7 +9,7 @@
 			{{ctx.Locale.Tr "admin.dashboard.maintenance_operations"}}
 		</h4>
 		<div class="ui attached table segment">
-			<form method="post" action="{{AppSubUrl}}/admin">
+			<form method="post" action="{{AppSubUrl}}/-/admin">
 				{{.CsrfTokenHtml}}
 				<table class="ui very basic table tw-mt-0 tw-px-4">
 					<tbody>
diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl
index 93fbb9dfc2..835b77ea17 100644
--- a/templates/admin/emails/list.tmpl
+++ b/templates/admin/emails/list.tmpl
@@ -80,7 +80,7 @@
 			<div class="content">
 				<p class="center">{{ctx.Locale.Tr "admin.emails.change_email_text"}}</p>
 
-				<form class="ui form" id="email-action-form" action="{{AppSubUrl}}/admin/emails/activate" method="post">
+				<form class="ui form" id="email-action-form" action="{{AppSubUrl}}/-/admin/emails/activate" method="post">
 					{{$.CsrfTokenHtml}}
 
 					<input type="hidden" id="query-sort" name="sort" value="{{.SortType}}">
diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl
index 1b3b9d6efc..4116357d1d 100644
--- a/templates/admin/navbar.tmpl
+++ b/templates/admin/navbar.tmpl
@@ -5,10 +5,10 @@
 		<details class="item toggleable-item" {{if or .PageIsAdminDashboard .PageIsAdminSelfCheck}}open{{end}}>
 			<summary>{{ctx.Locale.Tr "admin.maintenance"}}</summary>
 			<div class="menu">
-				<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/admin">
+				<a class="{{if .PageIsAdminDashboard}}active {{end}}item" href="{{AppSubUrl}}/-/admin">
 					{{ctx.Locale.Tr "admin.dashboard"}}
 				</a>
-				<a class="{{if .PageIsAdminSelfCheck}}active {{end}}item" href="{{AppSubUrl}}/admin/self_check">
+				<a class="{{if .PageIsAdminSelfCheck}}active {{end}}item" href="{{AppSubUrl}}/-/admin/self_check">
 					{{ctx.Locale.Tr "admin.self_check"}}
 				</a>
 			</div>
@@ -16,16 +16,16 @@
 		<details class="item toggleable-item" {{if or .PageIsAdminUsers .PageIsAdminEmails .PageIsAdminOrganizations .PageIsAdminAuthentications}}open{{end}}>
 			<summary>{{ctx.Locale.Tr "admin.identity_access"}}</summary>
 			<div class="menu">
-				<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/admin/auths">
+				<a class="{{if .PageIsAdminAuthentications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/auths">
 					{{ctx.Locale.Tr "admin.authentication"}}
 				</a>
-				<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/admin/orgs">
+				<a class="{{if .PageIsAdminOrganizations}}active {{end}}item" href="{{AppSubUrl}}/-/admin/orgs">
 					{{ctx.Locale.Tr "admin.organizations"}}
 				</a>
-				<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/admin/users">
+				<a class="{{if .PageIsAdminUsers}}active {{end}}item" href="{{AppSubUrl}}/-/admin/users">
 					{{ctx.Locale.Tr "admin.users"}}
 				</a>
-				<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/admin/emails">
+				<a class="{{if .PageIsAdminEmails}}active {{end}}item" href="{{AppSubUrl}}/-/admin/emails">
 					{{ctx.Locale.Tr "admin.emails"}}
 				</a>
 			</div>
@@ -34,11 +34,11 @@
 			<summary>{{ctx.Locale.Tr "admin.assets"}}</summary>
 			<div class="menu">
 				{{if .EnablePackages}}
-					<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/admin/packages">
+					<a class="{{if .PageIsAdminPackages}}active {{end}}item" href="{{AppSubUrl}}/-/admin/packages">
 						{{ctx.Locale.Tr "packages.title"}}
 					</a>
 				{{end}}
-				<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/admin/repos">
+				<a class="{{if .PageIsAdminRepositories}}active {{end}}item" href="{{AppSubUrl}}/-/admin/repos">
 					{{ctx.Locale.Tr "admin.repositories"}}
 				</a>
 			</div>
@@ -48,22 +48,22 @@
 			<details class="item toggleable-item" {{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks .PageIsAdminApplications}}open{{end}}>
 				<summary>{{ctx.Locale.Tr "admin.integrations"}}</summary>
 				<div class="menu">
-					<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
+					<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/applications">
 						{{ctx.Locale.Tr "settings.applications"}}
 					</a>
-					<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
+					<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/-/admin/hooks">
 						{{ctx.Locale.Tr "admin.hooks"}}
 					</a>
 				</div>
 			</details>
 		{{else}}
 			{{if not DisableWebhooks}}
-			<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/admin/hooks">
+			<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active {{end}}item" href="{{AppSubUrl}}/-/admin/hooks">
 				{{ctx.Locale.Tr "admin.hooks"}}
 			</a>
 			{{end}}
 			{{if .EnableOAuth2}}
-				<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/admin/applications">
+				<a class="{{if .PageIsAdminApplications}}active {{end}}item" href="{{AppSubUrl}}/-/admin/applications">
 					{{ctx.Locale.Tr "settings.applications"}}
 				</a>
 			{{end}}
@@ -72,10 +72,10 @@
 		<details class="item toggleable-item" {{if or .PageIsSharedSettingsRunners .PageIsSharedSettingsVariables}}open{{end}}>
 			<summary>{{ctx.Locale.Tr "actions.actions"}}</summary>
 			<div class="menu">
-				<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/runners">
+				<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/-/admin/actions/runners">
 					{{ctx.Locale.Tr "actions.runners"}}
 				</a>
-				<a class="{{if .PageIsSharedSettingsVariables}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/variables">
+				<a class="{{if .PageIsSharedSettingsVariables}}active {{end}}item" href="{{AppSubUrl}}/-/admin/actions/variables">
 					{{ctx.Locale.Tr "actions.variables"}}
 				</a>
 			</div>
@@ -84,30 +84,30 @@
 		<details class="item toggleable-item" {{if or .PageIsAdminConfig}}open{{end}}>
 			<summary>{{ctx.Locale.Tr "admin.config"}}</summary>
 			<div class="menu">
-				<a class="{{if .PageIsAdminConfigSummary}}active {{end}}item" href="{{AppSubUrl}}/admin/config">
+				<a class="{{if .PageIsAdminConfigSummary}}active {{end}}item" href="{{AppSubUrl}}/-/admin/config">
 					{{ctx.Locale.Tr "admin.config_summary"}}
 				</a>
-				<a class="{{if .PageIsAdminConfigSettings}}active {{end}}item" href="{{AppSubUrl}}/admin/config/settings">
+				<a class="{{if .PageIsAdminConfigSettings}}active {{end}}item" href="{{AppSubUrl}}/-/admin/config/settings">
 					{{ctx.Locale.Tr "admin.config_settings"}}
 				</a>
 			</div>
 		</details>
-		<a class="{{if .PageIsAdminNotices}}active {{end}}item" href="{{AppSubUrl}}/admin/notices">
+		<a class="{{if .PageIsAdminNotices}}active {{end}}item" href="{{AppSubUrl}}/-/admin/notices">
 			{{ctx.Locale.Tr "admin.notices"}}
 		</a>
 		<details class="item toggleable-item" {{if or .PageIsAdminMonitorStats .PageIsAdminMonitorCron .PageIsAdminMonitorQueue .PageIsAdminMonitorStacktrace}}open{{end}}>
 			<summary>{{ctx.Locale.Tr "admin.monitor"}}</summary>
 			<div class="menu">
-				<a class="{{if .PageIsAdminMonitorStats}}active {{end}}item" href="{{AppSubUrl}}/admin/monitor/stats">
+				<a class="{{if .PageIsAdminMonitorStats}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/stats">
 					{{ctx.Locale.Tr "admin.monitor.stats"}}
 				</a>
-				<a class="{{if .PageIsAdminMonitorCron}}active {{end}}item" href="{{AppSubUrl}}/admin/monitor/cron">
+				<a class="{{if .PageIsAdminMonitorCron}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/cron">
 					{{ctx.Locale.Tr "admin.monitor.cron"}}
 				</a>
-				<a class="{{if .PageIsAdminMonitorQueue}}active {{end}}item" href="{{AppSubUrl}}/admin/monitor/queue">
+				<a class="{{if .PageIsAdminMonitorQueue}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/queue">
 					{{ctx.Locale.Tr "admin.monitor.queues"}}
 				</a>
-				<a class="{{if .PageIsAdminMonitorStacktrace}}active {{end}}item" href="{{AppSubUrl}}/admin/monitor/stacktrace">
+				<a class="{{if .PageIsAdminMonitorStacktrace}}active {{end}}item" href="{{AppSubUrl}}/-/admin/monitor/stacktrace">
 					{{ctx.Locale.Tr "admin.monitor.stacktrace"}}
 				</a>
 			</div>
diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl
index 68703cc884..6e7eed7678 100644
--- a/templates/admin/notice.tmpl
+++ b/templates/admin/notice.tmpl
@@ -31,7 +31,7 @@
 						<tr>
 							<th></th>
 							<th colspan="5">
-								<form class="tw-float-right" method="post" action="{{AppSubUrl}}/admin/notices/empty">
+								<form class="tw-float-right" method="post" action="{{AppSubUrl}}/-/admin/notices/empty">
 									{{.CsrfTokenHtml}}
 									<button type="submit" class="ui red small button">{{ctx.Locale.Tr "admin.notices.delete_all"}}</button>
 								</form>
diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl
index d1d77b6220..a5ad93b89c 100644
--- a/templates/admin/packages/list.tmpl
+++ b/templates/admin/packages/list.tmpl
@@ -5,7 +5,7 @@
 			{{ctx.Locale.Tr "admin.packages.total_size" (FileSize .TotalBlobSize)}},
 			{{ctx.Locale.Tr "admin.packages.unreferenced_size" (FileSize .TotalUnreferencedBlobSize)}})
 			<div class="ui right">
-				<form method="post" action="{{AppSubUrl}}/admin/packages/cleanup">
+				<form method="post" action="{{AppSubUrl}}/-/admin/packages/cleanup">
 					{{.CsrfTokenHtml}}
 					<button class="ui primary tiny button">{{ctx.Locale.Tr "admin.packages.cleanup"}}</button>
 				</form>
diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl
index 69031e42eb..77a275427a 100644
--- a/templates/admin/repo/list.tmpl
+++ b/templates/admin/repo/list.tmpl
@@ -3,7 +3,7 @@
 		<h4 class="ui top attached header">
 			{{ctx.Locale.Tr "admin.repos.repo_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
 			<div class="ui right">
-				<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/repos/unadopted">{{ctx.Locale.Tr "admin.repos.unadopted"}}</a>
+				<a class="ui primary tiny button" href="{{AppSubUrl}}/-/admin/repos/unadopted">{{ctx.Locale.Tr "admin.repos.unadopted"}}</a>
 			</div>
 		</h4>
 		<div class="ui attached segment">
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl
index a95f6b5120..6f26fa5291 100644
--- a/templates/admin/repo/unadopted.tmpl
+++ b/templates/admin/repo/unadopted.tmpl
@@ -3,7 +3,7 @@
 		<h4 class="ui top attached header">
 			{{ctx.Locale.Tr "admin.repos.unadopted"}}
 			<div class="ui right">
-				<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/repos">{{ctx.Locale.Tr "admin.repos.repo_manage_panel"}}</a>
+				<a class="ui primary tiny button" href="{{AppSubUrl}}/-/admin/repos">{{ctx.Locale.Tr "admin.repos.repo_manage_panel"}}</a>
 			</div>
 		</h4>
 		<div class="ui attached segment">
@@ -31,7 +31,7 @@
 										<div class="content">
 											<p>{{ctx.Locale.Tr "repo.adopt_preexisting_content" $dir}}</p>
 										</div>
-										<form class="ui form" method="post" action="{{AppSubUrl}}/admin/repos/unadopted">
+										<form class="ui form" method="post" action="{{AppSubUrl}}/-/admin/repos/unadopted">
 											{{$.CsrfTokenHtml}}
 											<input type="hidden" name="id" value="{{$dir}}">
 											<input type="hidden" name="action" value="adopt">
@@ -48,7 +48,7 @@
 										<div class="content">
 											<p>{{ctx.Locale.Tr "repo.delete_preexisting_content" $dir}}</p>
 										</div>
-										<form class="ui form" method="post" action="{{AppSubUrl}}/admin/repos/unadopted">
+										<form class="ui form" method="post" action="{{AppSubUrl}}/-/admin/repos/unadopted">
 											{{$.CsrfTokenHtml}}
 											<input type="hidden" name="id" value="{{$dir}}">
 											<input type="hidden" name="action" value="delete">
diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl
index e324570c96..ce03d80555 100644
--- a/templates/admin/stacktrace.tmpl
+++ b/templates/admin/stacktrace.tmpl
@@ -8,7 +8,7 @@
 				<a class="{{if eq .ShowGoroutineList "stacktrace"}}active {{end}}item" href="?show=stacktrace">{{ctx.Locale.Tr "admin.monitor.stacktrace"}}</a>
 			</div>
 		</div>
-		<form target="_blank" action="{{AppSubUrl}}/admin/monitor/diagnosis" class="ui form">
+		<form target="_blank" action="{{AppSubUrl}}/-/admin/monitor/diagnosis" class="ui form">
 			<div class="ui inline field">
 				<button class="ui primary small button">{{ctx.Locale.Tr "admin.monitor.download_diagnosis_report"}}</button>
 				<input name="seconds" size="3" maxlength="3" value="10"> {{ctx.Locale.Tr "tool.raw_seconds"}}
diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl
index bc54d33431..bc3d83fc5c 100644
--- a/templates/admin/user/list.tmpl
+++ b/templates/admin/user/list.tmpl
@@ -3,7 +3,7 @@
 		<h4 class="ui top attached header">
 			{{ctx.Locale.Tr "admin.users.user_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})
 			<div class="ui right">
-				<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/users/new">{{ctx.Locale.Tr "admin.users.new_account"}}</a>
+				<a class="ui primary tiny button" href="{{AppSubUrl}}/-/admin/users/new">{{ctx.Locale.Tr "admin.users.new_account"}}</a>
 			</div>
 		</h4>
 		<div class="ui attached segment">
diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl
index 8d0d8e669c..4b9d9f5bbe 100644
--- a/templates/base/footer_content.tmpl
+++ b/templates/base/footer_content.tmpl
@@ -6,7 +6,7 @@
 		{{if (or .ShowFooterVersion .PageIsAdmin)}}
 			{{ctx.Locale.Tr "version"}}:
 			{{if .IsAdmin}}
-				<a href="{{AppSubUrl}}/admin/config">{{AppVer}}</a>
+				<a href="{{AppSubUrl}}/-/admin/config">{{AppVer}}</a>
 			{{else}}
 				{{AppVer}}
 			{{end}}
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl
index 7be2d96d74..951ee590d1 100644
--- a/templates/base/head_navbar.tmpl
+++ b/templates/base/head_navbar.tmpl
@@ -158,7 +158,7 @@
 					{{if .IsAdmin}}
 						<div class="divider"></div>
 
-						<a class="{{if .PageIsAdmin}}active {{end}}item" href="{{AppSubUrl}}/admin">
+						<a class="{{if .PageIsAdmin}}active {{end}}item" href="{{AppSubUrl}}/-/admin">
 							{{svg "octicon-server"}}
 							{{ctx.Locale.Tr "admin_panel"}}
 						</a>
diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl
index 1069209495..50d707176d 100644
--- a/templates/shared/user/profile_big_avatar.tmpl
+++ b/templates/shared/user/profile_big_avatar.tmpl
@@ -14,7 +14,7 @@
 	<div class="content tw-break-anywhere profile-avatar-name">
 		{{if .ContextUser.FullName}}<span class="header text center">{{.ContextUser.FullName}}</span>{{end}}
 		<span class="username text center">{{.ContextUser.Name}} {{if .IsAdmin}}
-					<a class="muted" href="{{AppSubUrl}}/admin/users/{{.ContextUser.ID}}" data-tooltip-content="{{ctx.Locale.Tr "admin.users.details"}}">
+					<a class="muted" href="{{AppSubUrl}}/-/admin/users/{{.ContextUser.ID}}" data-tooltip-content="{{ctx.Locale.Tr "admin.users.details"}}">
 						{{svg "octicon-gear" 18}}
 					</a>
 				{{end}}</span>
diff --git a/tests/integration/admin_config_test.go b/tests/integration/admin_config_test.go
index 860a92d6a3..eec7e75fd9 100644
--- a/tests/integration/admin_config_test.go
+++ b/tests/integration/admin_config_test.go
@@ -17,7 +17,7 @@ func TestAdminConfig(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
 
 	session := loginUser(t, "user1")
-	req := NewRequest(t, "GET", "/admin/config")
+	req := NewRequest(t, "GET", "/-/admin/config")
 	resp := session.MakeRequest(t, req, http.StatusOK)
 	assert.True(t, test.IsNormalPageCompleted(resp.Body.String()))
 }
diff --git a/tests/integration/admin_user_test.go b/tests/integration/admin_user_test.go
index 090e60da29..d5d7e70bc7 100644
--- a/tests/integration/admin_user_test.go
+++ b/tests/integration/admin_user_test.go
@@ -19,11 +19,11 @@ func TestAdminViewUsers(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
 
 	session := loginUser(t, "user1")
-	req := NewRequest(t, "GET", "/admin/users")
+	req := NewRequest(t, "GET", "/-/admin/users")
 	session.MakeRequest(t, req, http.StatusOK)
 
 	session = loginUser(t, "user2")
-	req = NewRequest(t, "GET", "/admin/users")
+	req = NewRequest(t, "GET", "/-/admin/users")
 	session.MakeRequest(t, req, http.StatusForbidden)
 }
 
@@ -31,11 +31,11 @@ func TestAdminViewUser(t *testing.T) {
 	defer tests.PrepareTestEnv(t)()
 
 	session := loginUser(t, "user1")
-	req := NewRequest(t, "GET", "/admin/users/1")
+	req := NewRequest(t, "GET", "/-/admin/users/1")
 	session.MakeRequest(t, req, http.StatusOK)
 
 	session = loginUser(t, "user2")
-	req = NewRequest(t, "GET", "/admin/users/1")
+	req = NewRequest(t, "GET", "/-/admin/users/1")
 	session.MakeRequest(t, req, http.StatusForbidden)
 }
 
@@ -52,7 +52,7 @@ func testSuccessfullEdit(t *testing.T, formData user_model.User) {
 func makeRequest(t *testing.T, formData user_model.User, headerCode int) {
 	session := loginUser(t, "user1")
 	csrf := GetUserCSRFToken(t, session)
-	req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{
+	req := NewRequestWithValues(t, "POST", "/-/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{
 		"_csrf":      csrf,
 		"user_name":  formData.Name,
 		"login_name": formData.LoginName,
@@ -73,7 +73,7 @@ func TestAdminDeleteUser(t *testing.T) {
 	session := loginUser(t, "user1")
 
 	csrf := GetUserCSRFToken(t, session)
-	req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{
+	req := NewRequestWithValues(t, "POST", "/-/admin/users/8/delete", map[string]string{
 		"_csrf": csrf,
 	})
 	session.MakeRequest(t, req, http.StatusSeeOther)
diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go
index deb79187eb..8c8b6b02d1 100644
--- a/tests/integration/auth_ldap_test.go
+++ b/tests/integration/auth_ldap_test.go
@@ -157,7 +157,7 @@ func addAuthSourceLDAP(t *testing.T, sshKeyAttribute, groupFilter string, groupM
 	}
 	session := loginUser(t, "user1")
 	csrf := GetUserCSRFToken(t, session)
-	req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, sshKeyAttribute, groupFilter, groupTeamMap, groupTeamMapRemoval))
+	req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", buildAuthSourceLDAPPayload(csrf, sshKeyAttribute, groupFilter, groupTeamMap, groupTeamMapRemoval))
 	session.MakeRequest(t, req, http.StatusSeeOther)
 }
 
@@ -187,7 +187,7 @@ func TestLDAPAuthChange(t *testing.T) {
 	addAuthSourceLDAP(t, "", "")
 
 	session := loginUser(t, "user1")
-	req := NewRequest(t, "GET", "/admin/auths")
+	req := NewRequest(t, "GET", "/-/admin/auths")
 	resp := session.MakeRequest(t, req, http.StatusOK)
 	doc := NewHTMLParser(t, resp.Body)
 	href, exists := doc.Find("table.table td a").Attr("href")
@@ -255,11 +255,11 @@ func TestLDAPUserSyncWithEmptyUsernameAttribute(t *testing.T) {
 	csrf := GetUserCSRFToken(t, session)
 	payload := buildAuthSourceLDAPPayload(csrf, "", "", "", "")
 	payload["attribute_username"] = ""
-	req := NewRequestWithValues(t, "POST", "/admin/auths/new", payload)
+	req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", payload)
 	session.MakeRequest(t, req, http.StatusSeeOther)
 
 	for _, u := range gitLDAPUsers {
-		req := NewRequest(t, "GET", "/admin/users?q="+u.UserName)
+		req := NewRequest(t, "GET", "/-/admin/users?q="+u.UserName)
 		resp := session.MakeRequest(t, req, http.StatusOK)
 
 		htmlDoc := NewHTMLParser(t, resp.Body)
@@ -488,6 +488,6 @@ func TestLDAPPreventInvalidGroupTeamMap(t *testing.T) {
 
 	session := loginUser(t, "user1")
 	csrf := GetUserCSRFToken(t, session)
-	req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, "", "", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`, "off"))
+	req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", buildAuthSourceLDAPPayload(csrf, "", "", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`, "off"))
 	session.MakeRequest(t, req, http.StatusOK) // StatusOK = failed, StatusSeeOther = ok
 }
diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go
index 53d88aeb37..2ba16b3d36 100644
--- a/tests/integration/user_test.go
+++ b/tests/integration/user_test.go
@@ -97,7 +97,6 @@ func TestRenameReservedUsername(t *testing.T) {
 
 	reservedUsernames := []string{
 		// ".", "..", ".well-known", // The names are not only reserved but also invalid
-		"admin",
 		"api",
 		"assets",
 		"attachments",
diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts
index 4ccbbacd5b..0d130703ae 100644
--- a/web_src/js/features/admin/config.ts
+++ b/web_src/js/features/admin/config.ts
@@ -10,7 +10,7 @@ export function initAdminConfigs() {
   for (const el of elAdminConfig.querySelectorAll('input[type="checkbox"][data-config-dyn-key]')) {
     el.addEventListener('change', async () => {
       try {
-        const resp = await POST(`${appSubUrl}/admin/config`, {
+        const resp = await POST(`${appSubUrl}/-/admin/config`, {
           data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key'), value: el.checked}),
         });
         const json = await resp.json();
diff --git a/web_src/js/features/admin/selfcheck.ts b/web_src/js/features/admin/selfcheck.ts
index 498c52ffb5..925a50130f 100644
--- a/web_src/js/features/admin/selfcheck.ts
+++ b/web_src/js/features/admin/selfcheck.ts
@@ -10,7 +10,7 @@ export async function initAdminSelfCheck() {
   const elContent = document.querySelector('.page-content.admin .admin-setting-content');
 
   // send frontend self-check request
-  const resp = await POST(`${appSubUrl}/admin/self_check`, {
+  const resp = await POST(`${appSubUrl}/-/admin/self_check`, {
     data: new URLSearchParams({
       location_origin: window.location.origin,
       now: Date.now(), // TODO: check time difference between server and client