diff --git a/.forgejo/upgrades/legagy-relative-app.ini b/.forgejo/upgrades/legagy-relative-app.ini
new file mode 100644
index 0000000000..078b0da671
--- /dev/null
+++ b/.forgejo/upgrades/legagy-relative-app.ini
@@ -0,0 +1,28 @@
+RUN_MODE = prod
+WORK_PATH = ${WORK_PATH}
+
+[server]
+APP_DATA_PATH = ${WORK_PATH}/data
+HTTP_PORT = 3000
+SSH_LISTEN_PORT = 2222
+LFS_START_SERVER = true
+LFS_CONTENT_PATH = relative-lfs
+
+[database]
+DB_TYPE = sqlite3
+PATH = ${WORK_PATH}/forgejo.db
+
+[log]
+MODE = file
+LEVEL = debug
+ROUTER = file
+
+[log.file]
+FILE_NAME = forgejo.log
+
+[security]
+INSTALL_LOCK = true
+
+[picture]
+AVATAR_UPLOAD_PATH = relative-avatars
+REPOSITORY_AVATAR_UPLOAD_PATH = relative-repo-avatars
diff --git a/.forgejo/upgrades/relative-app.ini b/.forgejo/upgrades/relative-app.ini
new file mode 100644
index 0000000000..b587500dcf
--- /dev/null
+++ b/.forgejo/upgrades/relative-app.ini
@@ -0,0 +1,40 @@
+RUN_MODE = prod
+WORK_PATH = ${WORK_PATH}
+
+[server]
+APP_DATA_PATH = ${WORK_PATH}/data
+HTTP_PORT = 3000
+SSH_LISTEN_PORT = 2222
+LFS_START_SERVER = true
+
+[database]
+DB_TYPE = sqlite3
+
+[log]
+MODE = file
+LEVEL = debug
+ROUTER = file
+
+[log.file]
+FILE_NAME = forgejo.log
+
+[security]
+INSTALL_LOCK = true
+
+[attachment]
+PATH = relative-attachments
+
+[lfs]
+PATH = relative-lfs
+
+[avatar]
+PATH = relative-avatars
+
+[repo-avatar]
+PATH = relative-repo-avatars
+
+[repo-archive]
+PATH = relative-repo-archive
+
+[packages]
+PATH = relative-packages
diff --git a/.forgejo/upgrades/storage-relative-app.ini b/.forgejo/upgrades/storage-relative-app.ini
new file mode 100644
index 0000000000..c413811424
--- /dev/null
+++ b/.forgejo/upgrades/storage-relative-app.ini
@@ -0,0 +1,40 @@
+RUN_MODE = prod
+WORK_PATH = ${WORK_PATH}
+
+[server]
+APP_DATA_PATH = ${WORK_PATH}/data
+HTTP_PORT = 3000
+SSH_LISTEN_PORT = 2222
+LFS_START_SERVER = true
+
+[database]
+DB_TYPE = sqlite3
+
+[log]
+MODE = file
+LEVEL = debug
+ROUTER = file
+
+[log.file]
+FILE_NAME = forgejo.log
+
+[security]
+INSTALL_LOCK = true
+
+[storage.attachments]
+PATH = relative-attachments
+
+[storage.lfs]
+PATH = relative-lfs
+
+[storage.avatars]
+PATH = relative-avatars
+
+[storage.repo-avatars]
+PATH = relative-repo-avatars
+
+[storage.repo-archive]
+PATH = relative-repo-archive
+
+[storage.packages]
+PATH = relative-packages
diff --git a/.forgejo/upgrades/test-upgrade.sh b/.forgejo/upgrades/test-upgrade.sh
index 06bd9dd4e5..6ba1d87db3 100755
--- a/.forgejo/upgrades/test-upgrade.sh
+++ b/.forgejo/upgrades/test-upgrade.sh
@@ -1,6 +1,16 @@
 #!/bin/bash
 # SPDX-License-Identifier: MIT
 
+#
+# Debug loop from the source tree:
+#
+# ./.forgejo/upgrades/test-upgrade.sh dependencies
+# ./.forgejo/upgrades/test-upgrade.sh build_all
+# ./.forgejo/upgrades/test-upgrade.sh test_downgrade_1.20.2_fails
+#
+# Everything happens in /tmp/forgejo-upgrades
+#
+
 set -ex
 
 HOST_PORT=0.0.0.0:3000
@@ -156,7 +166,6 @@ function test_downgrade_1.20.2_fails() {
 
     echo "================ See also https://codeberg.org/forgejo/forgejo/pulls/1225"
 
-
     echo "================ downgrading from 1.20.3-0 to 1.20.2-0 fails"
     stop
     reset default
@@ -199,6 +208,88 @@ function test_bug_storage_merged() {
     fi
 }
 
+function test_bug_storage_relative_path() {
+    local work_path=$DIR/forgejo-work-path
+
+    echo "================ using < 1.20.3-0 legacy [server].XXXX and [picture].XXXX are relative to WORK_PATH"
+    for version in 1.18.5-0 1.19.4-0 1.20.2-0 ; do
+	stop
+	reset legagy-relative
+	start $version
+	test -d $work_path/relative-lfs
+	test -d $work_path/relative-avatars
+	test -d $work_path/relative-repo-avatars
+    done
+
+    echo "================ using >= 1.20.3-0 legacy [server].XXXX and [picture].XXXX are relative to APP_DATA_PATH"
+    for version in 1.20.3-0 1.21.0-0 ; do
+	stop
+	reset legagy-relative
+	start $version
+	test -d $work_path/data/relative-lfs
+	test -d $work_path/data/relative-avatars
+	test -d $work_path/data/relative-repo-avatars
+    done
+
+    echo "================ using >= 1.20.3-0 relative [storage.XXXX].PATHS are relative to APP_DATA_PATH"
+    for version in 1.20.3-0 1.21.0-0 ; do
+	stop
+	reset storage-relative
+	start $version
+	for path in ${STORAGE_PATHS} ; do
+	    test -d $work_path/data/relative-$path
+	done
+    done
+
+    echo "================ using 1.20.[12]-0 relative [storage.XXXX].PATHS are inconsistent"
+    for version in 1.20.2-0 ; do
+	stop
+	reset storage-relative
+	start $version
+	test -d $work_path/data/packages
+	test -d $work_path/relative-repo-archive
+	test -d $work_path/relative-attachments
+	test -d $work_path/relative-lfs
+	test -d $work_path/data/avatars
+	test -d $work_path/data/repo-avatars
+    done
+
+    echo "================ using < 1.20 relative [storage.XXXX].PATHS are inconsistent"
+    for version in 1.18.5-0 1.19.4-0 ; do
+	stop
+	reset storage-relative
+	start $version
+	test -d $work_path/relative-packages
+	test -d $work_path/relative-repo-archive
+	test -d $work_path/relative-attachments
+	test -d $work_path/data/lfs
+	test -d $work_path/data/avatars
+	test -d $work_path/data/repo-avatars
+    done
+
+    echo "================ using < 1.20.3-0 relative [XXXX].PATHS are relative to WORK_PATH"
+    for version in 1.18.5-0 1.19.4-0 1.20.2-0 ; do
+	stop
+	reset relative
+	start $version
+	for path in ${STORAGE_PATHS} ; do
+	    test -d $work_path/relative-$path
+	done
+    done
+
+    echo "================ using >= 1.20.3-0 relative [XXXX].PATHS are relative to APP_DATA_PATH"
+    for version in 1.20.3-0 1.21.0-0 ; do
+	stop
+	reset relative
+	start $version
+	for path in ${STORAGE_PATHS} ; do
+	    test -d $work_path/data/relative-$path
+	done
+    done
+
+    stop
+}
+
 function test_bug_storage_misplace() {
     local work_path=$DIR/forgejo-work-path