diff --git a/models/user.go b/models/user.go
index 06f11c968c..50635273bd 100644
--- a/models/user.go
+++ b/models/user.go
@@ -844,16 +844,20 @@ func (u *User) IsGhost() bool {
 
 var (
 	reservedUsernames = []string{
-		"attachments",
+		".",
+		"..",
+		".well-known",
 		"admin",
 		"api",
 		"assets",
+		"attachments",
 		"avatars",
 		"commits",
 		"css",
 		"debug",
 		"error",
 		"explore",
+		"fomantic",
 		"ghost",
 		"help",
 		"img",
@@ -861,6 +865,7 @@ var (
 		"issues",
 		"js",
 		"less",
+		"login",
 		"manifest.json",
 		"metrics",
 		"milestones",
@@ -871,16 +876,12 @@ var (
 		"pulls",
 		"raw",
 		"repo",
+		"robots.txt",
+		"search",
 		"stars",
 		"template",
 		"user",
 		"vendor",
-		"login",
-		"robots.txt",
-		".",
-		"..",
-		".well-known",
-		"search",
 	}
 	reservedUserPatterns = []string{"*.keys", "*.gpg"}
 )
diff --git a/modules/public/public.go b/modules/public/public.go
index 2617d31aea..fb8d9c1955 100644
--- a/modules/public/public.go
+++ b/modules/public/public.go
@@ -30,6 +30,15 @@ type Options struct {
 	Prefix       string
 }
 
+// List of known entries inside the `public` directory
+var knownEntries = []string{
+	"css",
+	"fomantic",
+	"img",
+	"js",
+	"vendor",
+}
+
 // Custom implements the macaron static handler for serving custom assets.
 func Custom(opts *Options) macaron.Handler {
 	return opts.staticHandler(path.Join(setting.CustomPath, "public"))
@@ -99,6 +108,19 @@ func (opts *Options) handle(ctx *macaron.Context, log *log.Logger, opt *Options)
 
 	f, err := opt.FileSystem.Open(file)
 	if err != nil {
+		// 404 requests to any known entries in `public`
+		if path.Base(opts.Directory) == "public" {
+			parts := strings.Split(file, "/")
+			if len(parts) < 2 {
+				return false
+			}
+			for _, entry := range knownEntries {
+				if entry == parts[1] {
+					ctx.Resp.WriteHeader(404)
+					return true
+				}
+			}
+		}
 		return false
 	}
 	defer f.Close()