diff --git a/models/activities/action.go b/models/activities/action.go
index 4baedbfe12..8e7492c008 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -223,18 +223,24 @@ func (a *Action) GetRepoAbsoluteLink() string {
 	return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
 }
 
-// GetCommentLink returns link to action comment.
-func (a *Action) GetCommentLink() string {
-	return a.getCommentLink(db.DefaultContext)
+// GetCommentHTMLURL returns link to action comment.
+func (a *Action) GetCommentHTMLURL() string {
+	return a.getCommentHTMLURL(db.DefaultContext)
 }
 
-func (a *Action) getCommentLink(ctx context.Context) string {
+func (a *Action) loadComment(ctx context.Context) (err error) {
+	if a.CommentID == 0 || a.Comment != nil {
+		return nil
+	}
+	a.Comment, err = issues_model.GetCommentByID(ctx, a.CommentID)
+	return err
+}
+
+func (a *Action) getCommentHTMLURL(ctx context.Context) string {
 	if a == nil {
 		return "#"
 	}
-	if a.Comment == nil && a.CommentID != 0 {
-		a.Comment, _ = issues_model.GetCommentByID(ctx, a.CommentID)
-	}
+	_ = a.loadComment(ctx)
 	if a.Comment != nil {
 		return a.Comment.HTMLURL()
 	}
@@ -260,6 +266,41 @@ func (a *Action) getCommentLink(ctx context.Context) string {
 	return issue.HTMLURL()
 }
 
+// GetCommentLink returns link to action comment.
+func (a *Action) GetCommentLink() string {
+	return a.getCommentLink(db.DefaultContext)
+}
+
+func (a *Action) getCommentLink(ctx context.Context) string {
+	if a == nil {
+		return "#"
+	}
+	_ = a.loadComment(ctx)
+	if a.Comment != nil {
+		return a.Comment.Link()
+	}
+	if len(a.GetIssueInfos()) == 0 {
+		return "#"
+	}
+	// Return link to issue
+	issueIDString := a.GetIssueInfos()[0]
+	issueID, err := strconv.ParseInt(issueIDString, 10, 64)
+	if err != nil {
+		return "#"
+	}
+
+	issue, err := issues_model.GetIssueByID(ctx, issueID)
+	if err != nil {
+		return "#"
+	}
+
+	if err = issue.LoadRepo(ctx); err != nil {
+		return "#"
+	}
+
+	return issue.Link()
+}
+
 // GetBranch returns the action's repository branch.
 func (a *Action) GetBranch() string {
 	return strings.TrimPrefix(a.RefName, git.BranchPrefix)
diff --git a/models/activities/action_test.go b/models/activities/action_test.go
index 29312bd482..f37e58f685 100644
--- a/models/activities/action_test.go
+++ b/models/activities/action_test.go
@@ -36,7 +36,7 @@ func TestAction_GetRepoLink(t *testing.T) {
 	expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
 	assert.Equal(t, expected, action.GetRepoLink())
 	assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
-	assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
+	assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
 }
 
 func TestGetFeeds(t *testing.T) {
diff --git a/models/activities/notification.go b/models/activities/notification.go
index f153eb0589..75276a0443 100644
--- a/models/activities/notification.go
+++ b/models/activities/notification.go
@@ -459,6 +459,22 @@ func (n *Notification) HTMLURL() string {
 	return ""
 }
 
+// Link formats a relative URL-string to the notification
+func (n *Notification) Link() string {
+	switch n.Source {
+	case NotificationSourceIssue, NotificationSourcePullRequest:
+		if n.Comment != nil {
+			return n.Comment.Link()
+		}
+		return n.Issue.Link()
+	case NotificationSourceCommit:
+		return n.Repository.Link() + "/commit/" + url.PathEscape(n.CommitID)
+	case NotificationSourceRepository:
+		return n.Repository.Link()
+	}
+	return ""
+}
+
 // APIURL formats a URL-string to the notification
 func (n *Notification) APIURL() string {
 	return setting.AppURL + "api/v1/notifications/threads/" + strconv.FormatInt(n.ID, 10)
diff --git a/models/issues/comment.go b/models/issues/comment.go
index 9ad538fcc6..c935e4ac91 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -391,21 +391,40 @@ func (c *Comment) HTMLURL() string {
 		log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
 		return ""
 	}
+	return c.Issue.HTMLURL() + c.hashLink()
+}
+
+// Link formats a relative URL-string to the issue-comment
+func (c *Comment) Link() string {
+	err := c.LoadIssue(db.DefaultContext)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error("LoadIssue(%d): %v", c.IssueID, err)
+		return ""
+	}
+	err = c.Issue.LoadRepo(db.DefaultContext)
+	if err != nil { // Silently dropping errors :unamused:
+		log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
+		return ""
+	}
+	return c.Issue.Link() + c.hashLink()
+}
+
+func (c *Comment) hashLink() string {
 	if c.Type == CommentTypeCode {
 		if c.ReviewID == 0 {
-			return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+			return "/files#" + c.HashTag()
 		}
 		if c.Review == nil {
 			if err := c.LoadReview(); err != nil {
 				log.Warn("LoadReview(%d): %v", c.ReviewID, err)
-				return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+				return "/files#" + c.HashTag()
 			}
 		}
 		if c.Review.Type <= ReviewTypePending {
-			return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+			return "/files#" + c.HashTag()
 		}
 	}
-	return fmt.Sprintf("%s#%s", c.Issue.HTMLURL(), c.HashTag())
+	return "#" + c.HashTag()
 }
 
 // APIURL formats a API-string to the issue-comment
@@ -708,8 +727,8 @@ func (c *Comment) UnsignedLine() uint64 {
 	return uint64(c.Line)
 }
 
-// CodeCommentURL returns the url to a comment in code
-func (c *Comment) CodeCommentURL() string {
+// CodeCommentLink returns the url to a comment in code
+func (c *Comment) CodeCommentLink() string {
 	err := c.LoadIssue(db.DefaultContext)
 	if err != nil { // Silently dropping errors :unamused:
 		log.Error("LoadIssue(%d): %v", c.IssueID, err)
@@ -720,7 +739,7 @@ func (c *Comment) CodeCommentURL() string {
 		log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
 		return ""
 	}
-	return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
+	return fmt.Sprintf("%s/files#%s", c.Issue.Link(), c.HashTag())
 }
 
 // LoadPushCommits Load push commits
diff --git a/models/issues/issue.go b/models/issues/issue.go
index 3ddc799270..62b936331b 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -419,7 +419,7 @@ func (issue *Issue) HTMLURL() string {
 	return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index)
 }
 
-// Link returns the Link URL to this issue.
+// Link returns the issue's relative URL.
 func (issue *Issue) Link() string {
 	var path string
 	if issue.IsPull {
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 044fb5fa04..3f8b0bc7ac 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -759,8 +759,8 @@ func GetPullRequestsByHeadBranch(ctx context.Context, headBranch string, headRep
 	return prs, nil
 }
 
-// GetBaseBranchHTMLURL returns the HTML URL of the base branch
-func (pr *PullRequest) GetBaseBranchHTMLURL() string {
+// GetBaseBranchLink returns the relative URL of the base branch
+func (pr *PullRequest) GetBaseBranchLink() string {
 	if err := pr.LoadBaseRepo(db.DefaultContext); err != nil {
 		log.Error("LoadBaseRepo: %v", err)
 		return ""
@@ -768,11 +768,11 @@ func (pr *PullRequest) GetBaseBranchHTMLURL() string {
 	if pr.BaseRepo == nil {
 		return ""
 	}
-	return pr.BaseRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
+	return pr.BaseRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
 }
 
-// GetHeadBranchHTMLURL returns the HTML URL of the head branch
-func (pr *PullRequest) GetHeadBranchHTMLURL() string {
+// GetHeadBranchLink returns the relative URL of the head branch
+func (pr *PullRequest) GetHeadBranchLink() string {
 	if pr.Flow == PullRequestFlowAGit {
 		return ""
 	}
@@ -784,7 +784,7 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
 	if pr.HeadRepo == nil {
 		return ""
 	}
-	return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
+	return pr.HeadRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
 }
 
 // UpdateAllowEdits update if PR can be edited from maintainers
diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go
index 96f34a22ee..f4be21e74e 100644
--- a/models/packages/descriptor.go
+++ b/models/packages/descriptor.go
@@ -65,7 +65,7 @@ type PackageFileDescriptor struct {
 
 // PackageWebLink returns the package web link
 func (pd *PackageDescriptor) PackageWebLink() string {
-	return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
+	return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
 }
 
 // FullWebLink returns the package version web link
diff --git a/models/project/project.go b/models/project/project.go
index 273823ac9d..9074fd0c15 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -116,6 +116,7 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) {
 	return err
 }
 
+// Link returns the project's relative URL.
 func (p *Project) Link() string {
 	if p.OwnerID > 0 {
 		err := p.LoadOwner(db.DefaultContext)
diff --git a/models/repo/release.go b/models/repo/release.go
index 08b429f5e1..abf91bc4bb 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -130,6 +130,11 @@ func (r *Release) HTMLURL() string {
 	return r.Repo.HTMLURL() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
 }
 
+// Link the relative url for a release on the web UI. release must have attributes loaded
+func (r *Release) Link() string {
+	return r.Repo.Link() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
+}
+
 // IsReleaseExist returns true if release with given tag name already exists.
 func IsReleaseExist(ctx context.Context, repoID int64, tagName string) (bool, error) {
 	if len(tagName) == 0 {
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 06ec34ed63..5d3753620d 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -480,7 +480,7 @@ func (repo *Repository) RepoPath() string {
 	return RepoPath(repo.OwnerName, repo.Name)
 }
 
-// Link returns the repository link
+// Link returns the repository relative url
 func (repo *Repository) Link() string {
 	return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name)
 }
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index 16f3d9dd26..ee4bec4df7 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -63,6 +63,7 @@ type Repository struct {
 	Language      string      `json:"language"`
 	LanguagesURL  string      `json:"languages_url"`
 	HTMLURL       string      `json:"html_url"`
+	Link          string      `json:"link"`
 	SSHURL        string      `json:"ssh_url"`
 	CloneURL      string      `json:"clone_url"`
 	OriginalURL   string      `json:"original_url"`
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index 7c375a085f..76dc769c65 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -73,7 +73,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
 
 		var content, desc, title string
 
-		link := &feeds.Link{Href: act.GetCommentLink()}
+		link := &feeds.Link{Href: act.GetCommentHTMLURL()}
 
 		// title
 		title = act.ActUser.DisplayName() + " "
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 11d336d4ec..ad17005d90 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -339,8 +339,8 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
 		ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch
 	}
 	ctx.Data["BaseTarget"] = pull.BaseBranch
-	ctx.Data["HeadBranchHTMLURL"] = pull.GetHeadBranchHTMLURL()
-	ctx.Data["BaseBranchHTMLURL"] = pull.GetBaseBranchHTMLURL()
+	ctx.Data["HeadBranchLink"] = pull.GetHeadBranchLink()
+	ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink()
 }
 
 // PrepareMergedViewPullInfo show meta information for a merged pull request view page
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index f9c67f170b..0a51dfa733 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -569,6 +569,7 @@ func SearchRepo(ctx *context.Context) {
 			Mirror:   repo.IsMirror,
 			Stars:    repo.NumStars,
 			HTMLURL:  repo.HTMLURL(),
+			Link:     repo.Link(),
 			Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
 		}
 	}
diff --git a/templates/code/searchresults.tmpl b/templates/code/searchresults.tmpl
index e21a50e1f1..f9b17aee41 100644
--- a/templates/code/searchresults.tmpl
+++ b/templates/code/searchresults.tmpl
@@ -13,13 +13,13 @@
 		<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
 			<h4 class="ui top attached normal header">
 				<span class="file">
-					<a rel="nofollow" href="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
+					<a rel="nofollow" href="{{$repo.Link}}">{{$repo.FullName}}</a>
 						{{if $repo.IsArchived}}
 							<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
 						{{end}}
 					- {{.Filename}}
 				</span>
-				<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
+				<a class="ui basic tiny button" rel="nofollow" href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
 			</h4>
 			<div class="ui attached table segment">
 				<div class="file-body file-code code-view">
@@ -28,7 +28,7 @@
 							<tr>
 								<td class="lines-num">
 									{{range .LineNumbers}}
-										<a href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
+										<a href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
 									{{end}}
 								</td>
 								<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>
diff --git a/templates/mail/issue/assigned.tmpl b/templates/mail/issue/assigned.tmpl
index 05bed69022..232a41b56f 100644
--- a/templates/mail/issue/assigned.tmpl
+++ b/templates/mail/issue/assigned.tmpl
@@ -8,7 +8,7 @@
 	<title>{{.Subject}}</title>
 </head>
 
-{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.HTMLURL) (Escape .Issue.Repo.FullName)}}
+{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.Link) (Escape .Issue.Repo.FullName)}}
 {{$link := printf "<a href='%s'>#%d</a>" (Escape .Link) .Issue.Index}}
 <body>
 	<p>
diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl
index 64dbb3df68..3bda408a05 100644
--- a/templates/mail/issue/default.tmpl
+++ b/templates/mail/issue/default.tmpl
@@ -20,11 +20,11 @@
 	{{if eq .ActionName "push"}}
 		<p>
 			{{if .Comment.IsForcePush}}
-				{{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.OldCommit}}
+				{{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.Link .Comment.OldCommit}}
 				{{$oldShortSha := ShortSha .Comment.OldCommit}}
 				{{$oldCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $oldCommitUrl) (Escape $oldShortSha)}}
 
-				{{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.NewCommit}}
+				{{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.Link .Comment.NewCommit}}
 				{{$newShortSha := ShortSha .Comment.NewCommit}}
 				{{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}}
 
@@ -72,7 +72,7 @@
 			<ul>
 			{{range .Comment.Commits}}
 				<li>
-					<a href="{{$.Comment.Issue.PullRequest.BaseRepo.HTMLURL}}/commit/{{.ID}}">
+					<a href="{{$.Comment.Issue.PullRequest.BaseRepo.Link}}/commit/{{.ID}}">
 						{{ShortSha .ID.String}}
 					</a>  -  {{.Summary}}
 				</li>
diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl
index b2acdce8b2..4250433523 100644
--- a/templates/mail/release.tmpl
+++ b/templates/mail/release.tmpl
@@ -11,8 +11,8 @@
 
 </head>
 
-{{$release_url := printf "<a href='%s'>%s</a>" (.Release.HTMLURL | Escape) (.Release.TagName | Escape)}}
-{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}}
+{{$release_url := printf "<a href='%s'>%s</a>" (.Release.Link | Escape) (.Release.TagName | Escape)}}
+{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.Link | Escape) (.Release.Repo.FullName | Escape)}}
 <body>
 	<p>
 		{{.locale.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url | Str2html}}
diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl
index ec2e88c854..01e0cb49a6 100644
--- a/templates/package/shared/list.tmpl
+++ b/templates/package/shared/list.tmpl
@@ -28,7 +28,7 @@
 							{{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}}
 						{{end}}
 						{{if $hasRepositoryAccess}}
-							{{$.locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.HTMLURL (.Repository.FullName | Escape) | Safe}}
+							{{$.locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.Link (.Repository.FullName | Escape) | Safe}}
 						{{else}}
 							{{$.locale.Tr "packages.published_by" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}}
 						{{end}}
@@ -41,7 +41,7 @@
 					{{svg "octicon-package" 32}}
 					<h2>{{.locale.Tr "packages.empty"}}</h2>
 					{{if and .Repository .CanWritePackages}}
-						{{$packagesUrl := URLJoin .Owner.HTMLURL "-" "packages"}}
+						{{$packagesUrl := URLJoin .Owner.HomeLink "-" "packages"}}
 						<p>{{.locale.Tr "packages.empty.repo" $packagesUrl | Safe}}</p>
 					{{end}}
 					<p>{{.locale.Tr "packages.empty.documentation" | Safe}}</p>
diff --git a/templates/package/view.tmpl b/templates/package/view.tmpl
index a548d9e0b6..2b32139681 100644
--- a/templates/package/view.tmpl
+++ b/templates/package/view.tmpl
@@ -11,7 +11,7 @@
 					<div>
 						{{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.locale}}
 						{{if .HasRepositoryAccess}}
-							{{.locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.HTMLURL (.PackageDescriptor.Repository.FullName | Escape) | Safe}}
+							{{.locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.Link (.PackageDescriptor.Repository.FullName | Escape) | Safe}}
 						{{else}}
 							{{.locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) | Safe}}
 						{{end}}
@@ -41,7 +41,7 @@
 						<div class="ui relaxed list">
 							<div class="item">{{svg .PackageDescriptor.Package.Type.SVGName 16 "mr-3"}} {{.PackageDescriptor.Package.Type.Name}}</div>
 							{{if .HasRepositoryAccess}}
-							<div class="item">{{svg "octicon-repo" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.HTMLURL}}">{{.PackageDescriptor.Repository.FullName}}</a></div>
+							<div class="item">{{svg "octicon-repo" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.Link}}">{{.PackageDescriptor.Repository.FullName}}</a></div>
 							{{end}}
 							<div class="item">{{svg "octicon-calendar" 16 "mr-3"}} {{TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.locale}}</div>
 							<div class="item">{{svg "octicon-download" 16 "mr-3"}} {{.PackageDescriptor.Version.DownloadCount}}</div>
@@ -91,7 +91,7 @@
 							<div class="ui divider"></div>
 							<div class="ui relaxed list">
 								{{if .HasRepositoryAccess}}
-								<div class="item">{{svg "octicon-issue-opened" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.HTMLURL}}/issues">{{.locale.Tr "repo.issues"}}</a></div>
+								<div class="item">{{svg "octicon-issue-opened" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.Link}}/issues">{{.locale.Tr "repo.issues"}}</a></div>
 								{{end}}
 								{{if .CanWritePackages}}
 								<div class="item">{{svg "octicon-tools" 16 "mr-3"}} <a href="{{.Link}}/settings">{{.locale.Tr "repo.settings"}}</a></div>
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index ee844299ab..1a68c90e51 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -96,13 +96,13 @@
 											</a>
 											{{end}}
 										{{else}}
-											<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="vm ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
+											<a href="{{.LatestPullRequest.Issue.Link}}" class="vm ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
 											{{if .LatestPullRequest.HasMerged}}
-												<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label purple large label vm">{{svg "octicon-git-merge" 16 "mr-2"}}{{$.locale.Tr "repo.pulls.merged"}}</a>
+												<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label purple large label vm">{{svg "octicon-git-merge" 16 "mr-2"}}{{$.locale.Tr "repo.pulls.merged"}}</a>
 											{{else if .LatestPullRequest.Issue.IsClosed}}
-												<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label red large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.closed_title"}}</a>
+												<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label red large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.closed_title"}}</a>
 											{{else}}
-												<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label green large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.open_title"}}</a>
+												<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label green large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.open_title"}}</a>
 											{{end}}
 										{{end}}
 									</td>
diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl
index 798a7eae14..4bc211f931 100644
--- a/templates/repo/diff/box.tmpl
+++ b/templates/repo/diff/box.tmpl
@@ -151,7 +151,7 @@
 											{{end}}
 										</div>
 									{{else}}
-										<table class="chroma" data-new-comment-url="{{$.Issue.HTMLURL}}/files/reviews/new_comment" data-path="{{$file.Name}}">
+										<table class="chroma" data-new-comment-url="{{$.Issue.Link}}/files/reviews/new_comment" data-path="{{$file.Name}}">
 											{{if $.IsSplitStyle}}
 												{{template "repo/diff/section_split" dict "file" . "root" $}}
 											{{else}}
@@ -191,7 +191,7 @@
 				<div class="ui comment form">
 					<div class="ui top attached tabular menu">
 						<a class="active write item">{{$.locale.Tr "write"}}</a>
-						<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
+						<a class="preview item" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
 					</div>
 					<div class="ui bottom attached active write tab segment">
 						<textarea class="review-textarea js-quick-submit" tabindex="1" name="content"></textarea>
diff --git a/templates/repo/diff/comment_form.tmpl b/templates/repo/diff/comment_form.tmpl
index 9325c754ce..f51e840721 100644
--- a/templates/repo/diff/comment_form.tmpl
+++ b/templates/repo/diff/comment_form.tmpl
@@ -1,5 +1,5 @@
 {{if and $.root.SignedUserID (not $.Repository.IsArchived)}}
-	<form class="ui form {{if $.hidden}}hide comment-form comment-form-reply{{end}}" action="{{$.root.Issue.HTMLURL}}/files/reviews/comments" method="post">
+	<form class="ui form {{if $.hidden}}hide comment-form comment-form-reply{{end}}" action="{{$.root.Issue.Link}}/files/reviews/comments" method="post">
 	{{$.root.CsrfTokenHtml}}
 		<input type="hidden" name="origin" value="{{if $.root.PageIsPullFiles}}diff{{else}}timeline{{end}}">
 		<input type="hidden" name="latest_commit_id" value="{{$.root.AfterCommitID}}"/>
@@ -11,7 +11,7 @@
 		<input type="hidden" name="diff_base_cid">
 		<div class="ui top tabular menu" data-write="write" data-preview="preview">
 			<a class="active item" data-tab="write">{{$.root.locale.Tr "write"}}</a>
-			<a class="item" data-tab="preview" data-url="{{$.root.Repository.HTMLURL}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.locale.Tr "preview"}}</a>
+			<a class="item" data-tab="preview" data-url="{{$.root.Repository.Link}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.locale.Tr "preview"}}</a>
 		</div>
 		<div class="field">
 			<div class="ui active tab" data-tab="write">
diff --git a/templates/repo/editor/edit.tmpl b/templates/repo/editor/edit.tmpl
index 3bc9da99b0..c4a48af9f5 100644
--- a/templates/repo/editor/edit.tmpl
+++ b/templates/repo/editor/edit.tmpl
@@ -31,13 +31,13 @@
 				<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
 					<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{.locale.Tr "repo.editor.new_file"}}{{else}}{{.locale.Tr "repo.editor.edit_file"}}{{end}}</a>
 					{{if not .IsNewFile}}
-					<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.locale.Tr "preview"}}</a>
+					<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.locale.Tr "preview"}}</a>
 					<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.locale.Tr "repo.editor.preview_changes"}}</a>
 					{{end}}
 				</div>
 				<div class="ui bottom attached active tab segment" data-tab="write">
 					<textarea id="edit_area" name="content" class="hide" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
-						data-url="{{.Repository.HTMLURL}}/markdown"
+						data-url="{{.Repository.Link}}/markdown"
 						data-context="{{.RepoLink}}"
 						data-markdown-file-exts="{{.MarkdownFileExts}}"
 						data-line-wrap-extensions="{{.LineWrapExtensions}}">
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl
index b860c1d26c..7a7201eb30 100644
--- a/templates/repo/header.tmpl
+++ b/templates/repo/header.tmpl
@@ -217,7 +217,7 @@
 				{{end}}
 
 				{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}}
-					<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.HTMLURL)))}} target="_blank" rel="noopener noreferrer" {{end}}>
+					<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.Link)))}} target="_blank" rel="noopener noreferrer" {{end}}>
 						{{svg "octicon-book"}} {{.locale.Tr "repo.wiki"}}
 					</a>
 				{{end}}
diff --git a/templates/repo/issue/comment_tab.tmpl b/templates/repo/issue/comment_tab.tmpl
index b70433a966..86efa8c833 100644
--- a/templates/repo/issue/comment_tab.tmpl
+++ b/templates/repo/issue/comment_tab.tmpl
@@ -16,11 +16,11 @@
 {{else}}
 	<div class="ui top tabular menu" data-write="write" data-preview="preview">
 		<a class="active item" data-tab="write">{{.locale.Tr "write"}}</a>
-		<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{.locale.Tr "preview"}}</a>
+		<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}">{{.locale.Tr "preview"}}</a>
 	</div>
 	<div class="field">
 		<div class="ui bottom active tab" data-tab="write">
-		<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.Repo.RepoLink}}">
+		<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.Link}}/markdown" data-context="{{.Repo.RepoLink}}">
 			{{- if .BodyQuery}}{{.BodyQuery}}{{else if .IssueTemplate}}{{.IssueTemplate}}{{else if .PullRequestTemplate}}{{.PullRequestTemplate}}{{else}}{{.content}}{{end -}}
 		</textarea>
 		</div>
diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl
index 9c5f9a4779..7b318d51f1 100644
--- a/templates/repo/issue/view_content.tmpl
+++ b/templates/repo/issue/view_content.tmpl
@@ -198,7 +198,7 @@
 	<div class="ui comment form">
 		<div class="ui top tabular menu">
 			<a class="active write item">{{$.locale.Tr "write"}}</a>
-			<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
+			<a class="preview item" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
 		</div>
 		<div class="field">
 			<div class="ui bottom active tab write">
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index 3012b09d58..39fbc638ce 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -123,7 +123,7 @@
 				{{template "shared/user/avatarlink" .Poster}}
 				<span class="text grey muted-links">
 					{{template "shared/user/authorlink" .Poster}}
-					{{$link := printf "%s/commit/%s" $.Repository.HTMLURL ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
+					{{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
 					{{if eq $.Issue.PullRequest.Status 3}}
 						{{$.locale.Tr "repo.issues.manually_pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Str2html}}
 					{{else}}
@@ -329,7 +329,7 @@
 					<div class="detail">
 						{{svg "octicon-plus"}}
 						<span class="text grey muted-links">
-							<a href="{{.DependentIssue.HTMLURL}}">
+							<a href="{{.DependentIssue.Link}}">
 								{{if eq .DependentIssue.RepoID .Issue.RepoID}}
 									#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
 								{{else}}
@@ -352,7 +352,7 @@
 					<div class="detail">
 						<span class="text grey muted-links">{{svg "octicon-trash"}}</span>
 						<span class="text grey muted-links">
-							<a href="{{.DependentIssue.HTMLURL}}">
+							<a href="{{.DependentIssue.Link}}">
 								{{if eq .DependentIssue.RepoID .Issue.RepoID}}
 									#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
 								{{else}}
@@ -476,7 +476,7 @@
 										{{$resolveDoer := (index $comms 0).ResolveDoer}}
 										{{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}}
 										<div class="df ac">
-											<a href="{{(index $comms 0).CodeCommentURL}}" class="file-comment ml-3 word-break">{{$filename}}</a>
+											<a href="{{(index $comms 0).CodeCommentLink}}" class="file-comment ml-3 word-break">{{$filename}}</a>
 											{{if $invalid}}
 												<span class="ui label basic small ml-3">
 													{{$.locale.Tr "repo.issues.review.outdated"}}
diff --git a/templates/repo/issue/view_content/context_menu.tmpl b/templates/repo/issue/view_content/context_menu.tmpl
index 7459623a54..b96fd86af5 100644
--- a/templates/repo/issue/view_content/context_menu.tmpl
+++ b/templates/repo/issue/view_content/context_menu.tmpl
@@ -6,11 +6,11 @@
 	<div class="menu">
 		{{$referenceUrl := ""}}
 		{{if .issue}}
-			{{$referenceUrl = Printf "%s#%s" .ctx.Issue.HTMLURL .item.HashTag}}
+			{{$referenceUrl = Printf "%s#%s" .ctx.Issue.Link .item.HashTag}}
 		{{else}}
-			{{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.HTMLURL .item.HashTag}}
+			{{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.Link .item.HashTag}}
 		{{end}}
-		<div class="item context" data-clipboard-text="{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.copy_link"}}</div>
+		<div class="item context" data-clipboard-text-type="url" data-clipboard-text="{{AppSubUrl}}{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.copy_link"}}</div>
 		<div class="item context quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.HashTag}}-raw">{{.ctx.locale.Tr "repo.issues.context.quote_reply"}}</div>
 		{{if not .ctx.UnitIssuesGlobalDisabled}}
 			<div class="item context reference-issue" data-target="{{.item.HashTag}}-raw" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-poster-username="{{.item.Poster.Name}}" data-reference="{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}</div>
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl
index dc671eb6d6..c68a150832 100644
--- a/templates/repo/issue/view_content/pull.tmpl
+++ b/templates/repo/issue/view_content/pull.tmpl
@@ -133,7 +133,7 @@
 			{{if .Issue.PullRequest.HasMerged}}
 				<div class="item text">
 					{{if .Issue.PullRequest.MergedCommitID}}
-						{{$link := printf "%s/commit/%s" $.Repository.HTMLURL (.Issue.PullRequest.MergedCommitID|PathEscape)}}
+						{{$link := printf "%s/commit/%s" $.Repository.Link (.Issue.PullRequest.MergedCommitID|PathEscape)}}
 						{{if eq $.Issue.PullRequest.Status 3}}
 							{{$.locale.Tr "repo.pulls.manually_merged_as" ($link|Escape) (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}}
 						{{else}}
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl
index 58f4722e28..74fe1ff248 100644
--- a/templates/repo/issue/view_title.tmpl
+++ b/templates/repo/issue/view_title.tmpl
@@ -35,13 +35,13 @@
 
 	{{if .Issue.IsPull}}
 		{{$headHref := .HeadTarget|Escape}}
-		{{if .HeadBranchHTMLURL}}
-			{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchHTMLURL | Escape) $headHref}}
+		{{if .HeadBranchLink}}
+			{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchLink | Escape) $headHref}}
 		{{end}}
 		{{$headHref = printf "%s <a class=\"tooltip\" data-content=\"%s\" data-clipboard-text=\"%s\">%s</a>" $headHref (.locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}}
 		{{$baseHref := .BaseTarget|Escape}}
-		{{if .BaseBranchHTMLURL}}
-			{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
+		{{if .BaseBranchLink}}
+			{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchLink | Escape) $baseHref}}
 		{{end}}
 		{{if .Issue.PullRequest.HasMerged}}
 			{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.locale}}
diff --git a/templates/repo/projects/view.tmpl b/templates/repo/projects/view.tmpl
index 1c09aade35..63d2727b63 100644
--- a/templates/repo/projects/view.tmpl
+++ b/templates/repo/projects/view.tmpl
@@ -242,7 +242,7 @@
 							{{end}}
 							<div class="right floated">
 								{{range .Assignees}}
-									<a class="tooltip" target="_blank" href="{{.HTMLURL}}" data-content="{{$.locale.Tr "repo.projects.board.assigned_to"}} {{.Name}}">{{avatar . 28 "mini mr-3"}}</a>
+									<a class="tooltip" target="_blank" href="{{.HomeLink}}" data-content="{{$.locale.Tr "repo.projects.board.assigned_to"}} {{.Name}}">{{avatar . 28 "mini mr-3"}}</a>
 								{{end}}
 							</div>
 						</div>
diff --git a/templates/repo/release/new.tmpl b/templates/repo/release/new.tmpl
index b4b7186a9a..738b3bd174 100644
--- a/templates/repo/release/new.tmpl
+++ b/templates/repo/release/new.tmpl
@@ -48,7 +48,7 @@
 					<label>{{.locale.Tr "repo.release.content"}}</label>
 					<div class="ui top tabular menu" data-write="write" data-preview="preview">
 						<a class="active write item" data-tab="write">{{$.locale.Tr "write"}}</a>
-						<a class="preview item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
+						<a class="preview item" data-tab="preview" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
 					</div>
 					<div class="ui bottom active tab" data-tab="write">
 						<textarea name="content">{{.content}}</textarea>
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index 711a37461e..85ff0120b2 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -110,10 +110,11 @@
 				</table>
 				<div class="code-line-menu ui vertical pointing menu tippy-target">
 					{{if $.Permission.CanRead $.UnitTypeIssues}}
+						{{/* FIXME: Here we use HTMLURL but not link, see https://github.com/go-gitea/gitea/pull/21986/files#r1096532186*/}}
 						<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/"}}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" rel="nofollow noindex">{{.locale.Tr "repo.issues.context.reference_issue"}}</a>
 					{{end}}
-					<a class="item view_git_blame" href="{{.Repository.HTMLURL}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.view_git_blame"}}</a>
-					<a class="item copy-line-permalink" data-url="{{.Repository.HTMLURL}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
+					<a class="item view_git_blame" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.view_git_blame"}}</a>
+					<a class="item copy-line-permalink" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
 				</div>
 				{{end}}
 			{{end}}
diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl
index 194e40122b..9e9de99022 100644
--- a/templates/repo/wiki/new.tmpl
+++ b/templates/repo/wiki/new.tmpl
@@ -21,11 +21,11 @@
 			</div>
 			<div class="ui top attached tabular menu previewtabs" data-write="write" data-preview="preview">
 				<a class="active item" data-tab="write">{{.locale.Tr "write"}}</a>
-				<a class="item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
+				<a class="item" data-tab="preview" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
 			</div>
 			<div class="field content" data-loading="{{.locale.Tr "loading"}}">
 				<div class="ui bottom active tab" data-tab="write">
-					<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.locale.Tr "repo.wiki.welcome"}}{{end}}</textarea>
+					<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.locale.Tr "repo.wiki.welcome"}}{{end}}</textarea>
 				</div>
 			</div>
 			<div class="field">
diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl
index 93d54930ff..9e3f605456 100644
--- a/templates/shared/issuelist.tmpl
+++ b/templates/shared/issuelist.tmpl
@@ -34,7 +34,7 @@
 			</div>
 			<div class="issue-item-main f1 fc df">
 				<div class="issue-item-top-row">
-					<a class="title tdn issue-title" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a>
+					<a class="title tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a>
 					{{if .IsPull}}
 						{{if (index $.CommitStatuses .PullRequest.ID)}}
 							{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
@@ -47,7 +47,7 @@
 					</span>
 				</div>
 				<div class="desc issue-item-bottom-row df ac fw my-1">
-					<a class="index ml-0 mr-2" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
+					<a class="index ml-0 mr-2" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
 						{{if eq $.listType "dashboard"}}
 							{{.Repo.FullName}}#{{.Index}}
 						{{else}}
@@ -65,7 +65,7 @@
 					{{if .IsPull}}
 						<div class="branches df ac">
 							<div class="branch">
-								<a href="{{.PullRequest.BaseRepo.HTMLURL}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
+								<a href="{{.PullRequest.BaseRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
 									{{/* inline to remove the spaces between spans */}}
 									{{if ne .RepoID .PullRequest.BaseRepoID}}<span class="truncated-name">{{.PullRequest.BaseRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.BaseBranch}}</span>
 								</a>
@@ -73,7 +73,7 @@
 							{{svg "gitea-double-chevron-left" 12 "mx-1"}}
 							{{if .PullRequest.HeadRepo}}
 							<div class="branch">
-								<a href="{{.PullRequest.HeadRepo.HTMLURL}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
+								<a href="{{.PullRequest.HeadRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
 									{{/* inline to remove the spaces between spans */}}
 									{{if ne .RepoID .PullRequest.HeadRepoID}}<span class="truncated-name">{{.PullRequest.HeadRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.HeadBranch}}</span>
 								</a>
@@ -159,7 +159,7 @@
 				</div>
 				<div class="issue-item-icon-right text grey">
 					{{if .NumComments}}
-						<a class="tdn muted" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
+						<a class="tdn muted" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
 							{{svg "octicon-comment" 16 "mr-2"}}{{.NumComments}}
 						</a>
 					{{end}}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 812e626d2d..5b07965d2a 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -19098,6 +19098,10 @@
           "type": "string",
           "x-go-name": "LanguagesURL"
         },
+        "link": {
+          "type": "string",
+          "x-go-name": "Link"
+        },
         "mirror": {
           "type": "boolean",
           "x-go-name": "Mirror"
diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl
index 9d0ea01ec5..8fb5763f3a 100644
--- a/templates/user/dashboard/repolist.tmpl
+++ b/templates/user/dashboard/repolist.tmpl
@@ -127,7 +127,7 @@
 			<div v-if="repos.length" class="ui attached table segment rounded-bottom">
 				<ul class="repo-owner-name-list">
 					<li v-for="repo in repos" :class="{'private': repo.private || repo.internal}">
-						<a class="repo-list-link df ac sb" :href="repo.html_url">
+						<a class="repo-list-link df ac sb" :href="repo.link">
 							<div class="item-name df ac f1 mr-2">
 								<component v-bind:is="repoIcon(repo)" size="16" class="mr-2"></component>
 								<div class="text bold truncate ml-1">${repo.full_name}</div>
diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl
index 702dd419a3..0ea001ff3d 100644
--- a/templates/user/notification/notification_div.tmpl
+++ b/templates/user/notification/notification_div.tmpl
@@ -35,7 +35,7 @@
 							{{$issue := .Issue}}
 							{{$repo := .Repository}}
 							<tr id="notification_{{.ID}}">
-								<td class="collapsing" data-href="{{.HTMLURL}}">
+								<td class="collapsing" data-href="{{.Link}}">
 									{{if eq .Status 3}}
 										<span class="blue">{{svg "octicon-pin"}}</span>
 									{{else if not $issue}}
@@ -58,8 +58,8 @@
 										{{end}}
 									{{end}}
 								</td>
-								<td class="eleven wide" data-href="{{.HTMLURL}}">
-									<a class="item" href="{{.HTMLURL}}">
+								<td class="eleven wide" data-href="{{.Link}}">
+									<a class="item" href="{{.Link}}">
 										{{if $issue}}
 											#{{$issue.Index}} - {{$issue.Title}}
 										{{else}}
diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js
index f8486cdc6c..07c439504e 100644
--- a/web_src/js/features/clipboard.js
+++ b/web_src/js/features/clipboard.js
@@ -1,4 +1,5 @@
 import {showTemporaryTooltip} from '../modules/tippy.js';
+import {toAbsoluteUrl} from '../utils.js';
 
 const {copy_success, copy_error} = window.config.i18n;
 
@@ -50,7 +51,11 @@ export function initGlobalCopyToClipboardListener() {
     // in case <button data-clipboard-text><svg></button>, so we just search
     // up to 3 levels for performance
     for (let i = 0; i < 3 && target; i++) {
-      const text = target.getAttribute('data-clipboard-text') || document.querySelector(target.getAttribute('data-clipboard-target'))?.value;
+      let txt = target.getAttribute('data-clipboard-text');
+      if (txt && target.getAttribute('data-clipboard-text-type') === 'url') {
+        txt = toAbsoluteUrl(txt);
+      }
+      const text = txt || document.querySelector(target.getAttribute('data-clipboard-target'))?.value;
 
       if (text) {
         e.preventDefault();
diff --git a/web_src/js/test/setup.js b/web_src/js/test/setup.js
index 7c208eb0d2..e0e2c71e29 100644
--- a/web_src/js/test/setup.js
+++ b/web_src/js/test/setup.js
@@ -2,4 +2,5 @@ window.config = {
   csrfToken: 'test-csrf-token-123456',
   pageData: {},
   i18n: {},
+  appSubUrl: '',
 };
diff --git a/web_src/js/utils.js b/web_src/js/utils.js
index 01c076aeba..b9cd69e15a 100644
--- a/web_src/js/utils.js
+++ b/web_src/js/utils.js
@@ -133,3 +133,10 @@ export function convertImage(blob, mime) {
     }
   });
 }
+
+export function toAbsoluteUrl(relUrl) {
+  if (relUrl.startsWith('http://') || relUrl.startsWith('https://')) {
+    return relUrl;
+  }
+  return `${window.location.origin}${relUrl}`;
+}
diff --git a/web_src/js/utils.test.js b/web_src/js/utils.test.js
index 1df0caa211..4efe916231 100644
--- a/web_src/js/utils.test.js
+++ b/web_src/js/utils.test.js
@@ -2,6 +2,7 @@ import {expect, test} from 'vitest';
 import {
   basename, extname, isObject, uniq, stripTags, joinPaths, parseIssueHref,
   prettyNumber, parseUrl, translateMonth, translateDay, blobToDataURI,
+  toAbsoluteUrl,
 } from './utils.js';
 
 test('basename', () => {
@@ -136,3 +137,8 @@ test('blobToDataURI', async () => {
   const blob = new Blob([JSON.stringify({test: true})], {type: 'application/json'});
   expect(await blobToDataURI(blob)).toEqual('data:application/json;base64,eyJ0ZXN0Ijp0cnVlfQ==');
 });
+
+test('toAbsoluteUrl', () => {
+  expect(toAbsoluteUrl('')).toEqual('http://localhost:3000');
+  expect(toAbsoluteUrl('/user/repo')).toEqual('http://localhost:3000/user/repo');
+});