diff --git a/scripts/pull_release_artifacts.sh b/scripts/pull_release_artifacts.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2e288128c2c0b8d2d0b5dc250d0eb13ed4686756
--- /dev/null
+++ b/scripts/pull_release_artifacts.sh
@@ -0,0 +1,49 @@
+
+set -eu
+
+tag=v$1
+ver=$1
+
+dest=$2
+gpg_user=$3
+
+mkdir -p "${dest}"
+
+cd "${dest}"
+
+base_url="https://gitlab.haskell.org/api/v4/projects/618/jobs/artifacts/${tag}/raw"
+
+curl -f -o "x86_64-apple-darwin-ghcup-${ver}" \
+	"${base_url}/out/x86_64-apple-darwin-ghcup-${ver}?job=release:darwin"
+
+curl -f -o "aarch64-apple-darwin-ghcup-${ver}" \
+	"${base_url}/out/aarch64-apple-darwin-ghcup-${ver}?job=release:darwin:aarch64"
+
+curl -f -o "x86_64-freebsd12-ghcup-${ver}" \
+	"${base_url}/out/x86_64-portbld-freebsd-ghcup-${ver}?job=release:freebsd12"
+
+curl -f -o "x86_64-freebsd13-ghcup-${ver}" \
+	"${base_url}/out/x86_64-portbld-freebsd-ghcup-${ver}?job=release:freebsd13"
+
+curl -f -o "i386-linux-ghcup-${ver}" \
+	"${base_url}/out/i386-linux-ghcup-${ver}?job=release:linux:32bit"
+
+curl -f -o "x86_64-linux-ghcup-${ver}" \
+	"${base_url}/out/x86_64-linux-ghcup-${ver}?job=release:linux:64bit"
+
+curl -f -o "aarch64-linux-ghcup-${ver}" \
+	"${base_url}/out/aarch64-linux-ghcup-${ver}?job=release:linux:aarch64"
+
+curl -f -o "armv7-linux-ghcup-${ver}" \
+	"${base_url}/out/armv7-linux-ghcup-${ver}?job=release:linux:armv7"
+
+curl -f -o "x86_64-mingw64-ghcup-${ver}.exe" \
+	"${base_url}/out/x86_64-mingw64-ghcup-${ver}.exe?job=release:windows"
+
+rm -f *.sig
+sha256sum *-ghcup-* > SHA256SUMS
+gpg --detach-sign -u ${gpg_user} SHA256SUMS
+for f in *-ghcup-* ; do gpg --detach-sign -u ${gpg_user} $f ; done
+
+
+
diff --git a/scripts/update-sftp.sh b/scripts/update-sftp.sh
index 7c145f3f723e1151e4ab63ac6caea7da3bc0ba92..1f2f5543a74fac96f414f98d31d7a926573a977e 100755
--- a/scripts/update-sftp.sh
+++ b/scripts/update-sftp.sh
@@ -2,6 +2,7 @@
 
 url=$1
 ver=$2
+artifacts_dir=$3
 
 die() {
     (>&2 printf "%s\\n" "$1")
@@ -10,10 +11,38 @@ die() {
 
 [ -z $url ] && die "no url set"
 [ -z $ver ] && die "no version set"
+[ -z "${artifacts_dir}" ] && die "artifacts_dir not set"
+[ -e "${artifacts_dir}" ] && die "artifacts_dir \"${artifacts_dir}\" does not exist"
+
+cd "${artifacts_dir}"
 
 sftp $url <<EOF
 cd ghcup
 
+mkdir ${ver}
+cd ${ver}
+put SHA256SUMS
+put SHA256SUMS.sig
+put aarch64-apple-darwin-ghcup-${ver}
+put aarch64-apple-darwin-ghcup-${ver}.sig
+put aarch64-linux-ghcup-${ver}
+put aarch64-linux-ghcup-${ver}.sig
+put armv7-linux-ghcup-${ver}
+put armv7-linux-ghcup-${ver}.sig
+put i386-linux-ghcup-${ver}
+put i386-linux-ghcup-${ver}.sig
+put x86_64-apple-darwin-ghcup-${ver}
+put x86_64-apple-darwin-ghcup-${ver}.sig
+put x86_64-freebsd12-ghcup-${ver}
+put x86_64-freebsd12-ghcup-${ver}.sig
+put x86_64-freebsd13-ghcup-${ver}
+put x86_64-freebsd13-ghcup-${ver}.sig
+put x86_64-linux-ghcup-${ver}
+put x86_64-linux-ghcup-${ver}.sig
+put x86_64-mingw64-ghcup-${ver}.exe
+put x86_64-mingw64-ghcup-${ver}.exe.sig
+cd ..
+
 rm aarch64-apple-darwin-ghcup
 rm aarch64-linux-ghcup
 rm armv7-linux-ghcup
@@ -36,3 +65,6 @@ symlink ${ver}/x86_64-mingw64-ghcup-${ver}.exe x86_64-mingw64-ghcup.exe
 EOF
 
 curl -X PURGE https://downloads.haskell.org/~ghcup/
+curl -X PURGE https://downloads.haskell.org/ghcup/
+curl -X PURGE https://downloads.haskell.org/~ghcup/${ver}/
+curl -X PURGE https://downloads.haskell.org/ghcup/${ver}/