diff --git a/Makefile b/Makefile
index f023608b1e..e12660e4a7 100644
--- a/Makefile
+++ b/Makefile
@@ -639,7 +639,7 @@ test-e2e: test-e2e-sqlite
 
 .PHONY: test-e2e-sqlite
 test-e2e-sqlite: playwright e2e.sqlite.test generate-ini-sqlite
-	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e
 
 .PHONY: test-e2e-sqlite\#%
 test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite
@@ -647,7 +647,7 @@ test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite
 
 .PHONY: test-e2e-mysql
 test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql
-	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e
 
 .PHONY: test-e2e-mysql\#%
 test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
@@ -655,7 +655,7 @@ test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
 
 .PHONY: test-e2e-pgsql
 test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
-	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e
 
 .PHONY: test-e2e-pgsql\#%
 test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
@@ -663,12 +663,17 @@ test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
 
 .PHONY: test-e2e-mssql
 test-e2e-mssql: playwright e2e.mssql.test generate-ini-mssql
-	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e
 
 .PHONY: test-e2e-mssql\#%
 test-e2e-mssql\#%: playwright e2e.mssql.test generate-ini-mssql
 	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
 
+.PHONY: test-e2e-debugserver
+test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite
+	sed -i s/3003/3000/g tests/sqlite.ini
+	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestDebugserver -test.timeout 24h
+
 .PHONY: bench-sqlite
 bench-sqlite: integrations.sqlite.test generate-ini-sqlite
 	GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
diff --git a/tests/e2e/debugserver_test.go b/tests/e2e/debugserver_test.go
new file mode 100644
index 0000000000..f0f54665e1
--- /dev/null
+++ b/tests/e2e/debugserver_test.go
@@ -0,0 +1,30 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+// This "test" is meant to be run with `make test-e2e-debugserver` and will just
+// keep open a gitea instance in a test environment (with the data from
+// `models/fixtures`) on port 3000. This is useful for debugging e2e tests, for
+// example with the playwright vscode extension.
+
+//nolint:forbidigo
+package e2e
+
+import (
+	"net/url"
+	"os"
+	"os/signal"
+	"syscall"
+	"testing"
+
+	"code.gitea.io/gitea/modules/setting"
+)
+
+func TestDebugserver(t *testing.T) {
+	done := make(chan os.Signal, 1)
+	signal.Notify(done, syscall.SIGINT, syscall.SIGTERM)
+
+	onGiteaRun(t, func(*testing.T, *url.URL) {
+		println(setting.AppURL)
+		<-done
+	})
+}