diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a48cf0de7af6613887a8f33ce5957001234ac817
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+public
diff --git a/.gitlab-ci.yaml b/.gitlab-ci.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e1689914285145d8cf3da3fce43e12404b11d99c
--- /dev/null
+++ b/.gitlab-ci.yaml
@@ -0,0 +1,13 @@
+# This file is a template, and might need editing before it works on your project.
+# Full project: https://gitlab.com/pages/plain-html
+image: busybox
+pages:
+  stage: deploy
+  script:
+    - echo "The site will be deployed to $CI_PAGES_URL"
+    - ./scripts/generate-keys.sh
+  artifacts:
+    paths:
+      - public
+  rules:
+    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
diff --git a/groups/esslingen/gratuxri b/groups/esslingen/gratuxri
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/groups/esslingen/nrb b/groups/esslingen/nrb
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/groups/stuttgart/nrb b/groups/stuttgart/nrb
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/groups/stuttgart/roland b/groups/stuttgart/roland
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/keys/gratuxri b/keys/gratuxri
new file mode 100644
index 0000000000000000000000000000000000000000..1f1f9ea827fb2119c7096e226abf54e6051ac5b1
--- /dev/null
+++ b/keys/gratuxri
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINkAq1RVdQ69QJ31RVFZ8v9Lp1u5U7PloUns13DztlWm gratuxri
diff --git a/keys/nrb b/keys/nrb
new file mode 100644
index 0000000000000000000000000000000000000000..bf1c2451892fb68a1af3f8ae9782fa7694adbc31
--- /dev/null
+++ b/keys/nrb
@@ -0,0 +1,2 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDjhPOxchbA16Thfgp6YunuaQrJXkHGS0DJ8y326l4bhQw4ABwVngo8XLEvgL4N0vredsm90ZZgN+grLgUJGe4nsRVvwVaCkoY4uGw53HnQYfdTIuu6lJdPHgbvXsLTb8echHkla/BYiQm02yilKQKxih0+mGxZ1YN+Vsc9J2TcoDEmetQQkUUsKEJL9FRg+vHPD3sIZhI9MMm30E/1ZQCK1D6pr4f19j35GGy3jntWR0wT1g5CBaTKkugBrMFfA7f4QHo5gPE+0xuJVl0QmDhZ36TTB+76lLRsBh7XJ124oG69Kp8iTY8Zrb53AqJZHWCyEngAgn7k+EtesDhGOqdEg2CceoiHFXcqBEhfqjBS498do+GzS6izsaZ/WOBksWHUjAeXtCG+9VDgUv7W8/XG2yjDAbj/hCa88Xtyb+8fLjkaRFzx2aHYEKO0n4EvnmUY59ab9uP7gDhS/1FaBOnaoLE2YqEwFp4pZDPO7s5EzC6w15W9qjHNXMsLC27zICmvHnM91U7zA9G6QeOPJlh3lmrjc2AWy1EfJXPmaMaVoFBVjp3OLgQN6iIlmBzu6wqOiRO4Ao3mNeR+WIMkPOT1FpgIa+NmwN5h35VlK6aN3O58OFqsS2EjwIEIDUdD7k45WZdi8ibvhMuAjfy5xPkTWjkMM9HBO/DEG3FWKKw3ww== nrb 2023
+
diff --git a/keys/roland b/keys/roland
new file mode 100644
index 0000000000000000000000000000000000000000..3dd1f326226c32274436c196a042ca3d8f641278
--- /dev/null
+++ b/keys/roland
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAgEAlNMXHpEZbndLRaBG683wJhzfgNfd6l9wpEwswQO4sZC3wfaBenYW0+V4QxfWUaYsTONGFmukdjuKfksljVDr2o+EfJGNmuU/JitWtzgtGkX+c0YtunZCswFwopOtwNky8xQIYjwcJ+xS4uRdl0QRUp4A9x9mZZ/uCQoGMxt2WtZ/h+gHAtdaB6cWNKP4xrNt+2efpAJHZEFSHNjLovSQcAl4maTh1LziUy9kw007aq0EMM7pq65ldcoFcuaE3IU9NlFLD7XQMMrx07/oHjb10NLFpwYb0/j3ugYxVF2BjbuPwwrzzzrq5a6YKKVMNOcyM03ysJyVe3D32UcS9covKlM68pkk5xtDiS+HYN0qrydrkiO8T0K4mKoz+yYRsLNaaMXt9d/heT3Gv1KxamNRwmnHISWZuPviO61zw0uTa7ZeWHJ1xKeZ7g1/b979ne5iWOKKnvFstxSeOvzU5thHNxqvahqagUGuBENEKNVTHAYC7LjtlLA+yn6EUyaKvANRg3fKqwN92mA2gbzmizWpDR35xQ1J145vPbvytzYIVrFXTC95iJBQ7AEHhIyKkuCbGbAlnnQAI04EkTbvgKpnArJ7L/AI1uL4pJJb39IwsQWD7Uv9GSYcs/wPcg7XtAlQHdJ2+euj/pwMguqKb72g3alNn8UBkZtyd3nPWxLrwhs= ffs-roland
diff --git a/scripts/generate-keys.sh b/scripts/generate-keys.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2973b9d158c213b3596e607ef0fb9e5431578ebc
--- /dev/null
+++ b/scripts/generate-keys.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -eu
+
+rootdir=$(readlink -f "$(dirname "$0")/..")
+
+echo "$rootdir"
+
+mkdir -p "$rootdir/public/groups"
+mkdir -p "$rootdir/public/keys"
+
+echo "<h1>Gruppen</h1>" > public/list.html
+
+for grouppath in "$rootdir/groups/"*; do
+	group=$(basename "$grouppath")
+	echo "Group $group"
+	echo "<li><a href=\"groups/$group\">$group</a></li>" >> public/list.html
+	echo "# Gruppe $group https://pages.freifunk-stuttgart.net/firmware/ssh-keys" > "$rootdir/public/groups/$group"
+	for memberpath in "$rootdir/groups/$group/"*; do
+		member=$(basename "$memberpath")
+		echo "  Member $member"
+		memberkeyfile="$rootdir/keys/$member"
+		if [ ! -f "$memberkeyfile" ]; then
+			echo "  ERROR: Could not find keys for '$member' in '$memberkeyfile'"
+			exit 1
+		fi
+		echo "# $member" >> "$rootdir/public/groups/$group"
+		cat "$rootdir/keys/$member" >> "$rootdir/public/groups/$group"
+	done
+done
+
+echo "<h1>Nutzer*innen</h1>" >> public/list.html
+for keypath in "$rootdir/keys/"*; do
+	user=$(basename "$keypath")
+	echo "<li><a href=\"keys/$user\">$user</a></li>" >> public/list.html
+	echo "# $user" >> "$rootdir/public/keys/$user"
+	cat "$rootdir/keys/$member" >> "$rootdir/public/keys/$user"
+done