diff --git a/cmd/serve-templates/index.html b/cmd/serve-templates/index.html
new file mode 100644
index 0000000..791e6c8
--- /dev/null
+++ b/cmd/serve-templates/index.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>packwiz development server</title>
+    <style>
+        h1, p {
+            text-align: center;
+            margin: 1.5em;
+            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+        }
+        hr {
+            width: 100px;
+            height: 1px;
+            border: none;
+            background-color: #ccc;
+            color: #ccc;
+        }
+        code {
+            background-color: #f5f5f5;
+            border-radius: 2px;
+            padding: 1px 5px;
+            font-size: 0.85rem;
+        }
+    </style>
+</head>
+<body>
+    <h1>
+        It works! Packwiz development server is running!
+    </h1>
+    <p>
+        Use <a href="https://packwiz.infra.link/tutorials/installing/packwiz-installer/" target="_blank">packwiz-installer</a> to install the pack from this HTTP server - works best with MultiMC/PolyMC/ATLauncher, or standalone for servers.
+    </p>
+    <p>
+        Your <code>pack.toml</code> is hosted at <code>http://localhost:{{.Port}}/pack.toml</code>.
+    </p>
+    <hr>
+    <p>
+        <a href="https://packwiz.infra.link" target="_blank">packwiz</a>
+    </p>
+</body>
+</html>
diff --git a/cmd/serve.go b/cmd/serve.go
index e8da099..ced7567 100644
--- a/cmd/serve.go
+++ b/cmd/serve.go
@@ -1,7 +1,10 @@
 package cmd
 
 import (
+	"bytes"
+	_ "embed"
 	"fmt"
+	"html/template"
 	"io"
 	"net/http"
 	"os"
@@ -18,6 +21,9 @@ import (
 
 var refreshMutex sync.RWMutex
 
+//go:embed serve-templates/index.html
+var indexPage string
+
 // serveCmd represents the serve command
 var serveCmd = &cobra.Command{
 	Use:     "serve",
@@ -26,6 +32,8 @@ var serveCmd = &cobra.Command{
 	Aliases: []string{"server"},
 	Args:    cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
+		port := strconv.Itoa(viper.GetInt("serve.port"))
+
 		if viper.GetBool("serve.basic") {
 			http.Handle("/", http.FileServer(http.Dir(".")))
 		} else {
@@ -43,7 +51,21 @@ var serveCmd = &cobra.Command{
 			indexPath := filepath.Join(filepath.Dir(viper.GetString("pack-file")), filepath.FromSlash(pack.Index.File))
 			indexDir := filepath.Dir(indexPath)
 
+			t, err := template.New("index-page").Parse(indexPage)
+			if err != nil {
+				fmt.Println(err)
+				os.Exit(1)
+			}
+
+			indexPageBuf := new(bytes.Buffer)
+			t.Execute(indexPageBuf, struct{ Port string }{Port: port})
+
 			http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+				if req.URL.Path == "/" {
+					_, _ = w.Write(indexPageBuf.Bytes())
+					return
+				}
+
 				urlPath := strings.TrimPrefix(path.Clean("/"+strings.TrimPrefix(req.URL.Path, "/")), "/")
 				indexRelPath, err := filepath.Rel(indexDir, filepath.FromSlash(urlPath))
 				if err != nil {
@@ -144,7 +166,6 @@ var serveCmd = &cobra.Command{
 			})
 		}
 
-		port := strconv.Itoa(viper.GetInt("serve.port"))
 		fmt.Println("Running on port " + port)
 		err := http.ListenAndServe(":"+port, nil)
 		if err != nil {