diff --git a/.gitignore b/.gitignore
index b2401589b35a8c6a9e89e16c7a1e74cce482f225..df9d1126777b5c095feb8d14e395bdefefbc2849 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,8 @@
 node_modules
 /dist
 dev/.env
-dev/backend
+dev/backend-files/backend
+dev/backend-files/kit-ca-api-server.toml
 
 # yarn
 .pnp.*
diff --git a/dev/Caddyfile b/dev/Caddyfile
index 1d4a534f6a67b4d2a06e29ed02415648f300a4bc..355f52cb6fdca94cd181a1a7bb566afffe063788 100644
--- a/dev/Caddyfile
+++ b/dev/Caddyfile
@@ -7,6 +7,7 @@
 		path /api/*
 		path /login
 		path /oidc/*
+		path /swagger/*
 	}
 
 	reverse_proxy * http://portal:3000
diff --git a/dev/backend-files/PortalDevRootCA.key b/dev/backend-files/PortalDevRootCA.key
new file mode 100644
index 0000000000000000000000000000000000000000..7cf76f777bfba6eda58c7e960ddc78aa8fe2fb54
--- /dev/null
+++ b/dev/backend-files/PortalDevRootCA.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
++0xaP1Q6Nlqoc49mFc5QJeoIX5OAKA==
+-----END PRIVATE KEY-----
diff --git a/dev/backend-files/PortalDevRootCA.pem b/dev/backend-files/PortalDevRootCA.pem
new file mode 100644
index 0000000000000000000000000000000000000000..2ed1186fc6210d4f3d31be9733870c0e0635e55a
--- /dev/null
+++ b/dev/backend-files/PortalDevRootCA.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFrTCCA5WgAwIBAgITVQvW+lefH7mrjnivIycweaPVbTANBgkqhkiG9w0BAQsF
+ADBdMQswCQYDVQQGEwJERTEqMCgGA1UECgwhS2FybHNydWhlIEluc3RpdHV0ZSBv
+ZiBUZWNobm9sb2d5MSIwIAYDVQQDDBlLSVQtQ0EgUG9ydGFsIERldiBSb290IENB
+MB4XDTIzMDkwMTIxMzM0NFoXDTIzMTAwMTIxMzM0NFowXTELMAkGA1UEBhMCREUx
+KjAoBgNVBAoMIUthcmxzcnVoZSBJbnN0aXR1dGUgb2YgVGVjaG5vbG9neTEiMCAG
+A1UEAwwZS0lULUNBIFBvcnRhbCBEZXYgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAL3DhN7S8rOxfouQK1LRFMgpRyOtp42eP4H5DrxiO8wJ
+36e65EIeQMB8thwjccx6kqA6OjHQSzJGs+YSj46ess/+wfaPO/zl62K3Lpo7WreW
+EUoIUHNdvrl9Qqmudflfyejc3dR/X/UsJDyBv9x5D+daboC1XeNg1P7I7K6MRtMu
+Phg8TAbtxQ41gMRtZDhkbiXd7LyagHCDpthJwqaEjf1c0ibac1/Z5dKMDxKuvrMb
+mHrpsjGVzIv3Sxt2Qc0VoCRj2i2fCnh9hMbgj+IJ1Sd9uPtwwKfBA1bwVbNh36AW
+EWIi8d0Wb+Y3yppsc2e2A8a9HYz6Ceyyoeo00W7WbMTEmBNS7FuMOxB6BtlWhHk6
+4+0t3hUakt+opcvBaQqIg98cwft+/kiTQvBOns1p6Ics73GmnfCSTWmG6HukY0Ry
+rDEf/1fzn3zh1F/D3fcFRumyRxu0hosmTUZpb7VnjjcN5/z+F64cEAucja0MFHq/
+jx7IVpHimYlEEUPl9xVwwKvXhGZ2uod0dzhJeV4iZN8LzL1Z99CR9ll9woXnFS+L
+5fMjSjq4HKOUXi4ykeanCs/R7FOa2j4POsZCiH90miSoGTI4pD+5uSZ1OltWiShF
+E4E6Nzn2ptPyXFYYQCfuN+poSktt/0eeQbpjKZC13DBn2e8ecUVIFC3InGbN45lH
+AgMBAAGjZjBkMB8GA1UdIwQYMBaAFFlVJq4sKrxd9XdeNTLXE2aH/rbgMA4GA1Ud
+DwEB/wQEAwICBDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRZVSauLCq8
+XfV3XjUy1xNmh/624DANBgkqhkiG9w0BAQsFAAOCAgEANQQdoFCk5+1+r9bQwa/n
+U046LIS0kZCHw4sFlxgJajt3jKxzNdhftKZbj6iqPXDycNEJun4TPTqV/EmClXxN
+yO4C7noUaesz9IXuXhp288ZmGWmPBqOwWxuOlM9TKAkPNF0efd35xczR0/sys3N0
+Q1wzFO+AA+KvmK9D7DfwSkOm22YKqRdmvUqTqdHyAvQAHwi4PfYbRtdVeSRW7t0q
+odEQS38N5D3RdEZ4QsN5+UzieaxzhaxKYxSWlR4x/cFnC/lZCgq30hLKjXz30I/m
+gvMxgKMqGISDxByk6X1lOnDaxKvPeH+FWXYYQ0UEFDQlADcQvz+OI8hV0xVv+g6m
+3JfNcgnNLlyv8ydBnbZBieY1JCrSCWaF8H3h2pk21/G3UbOXVcuxclQpP6DEbpDw
+oj4QNTQ3ed3VyCliVz3b+qUVYh+8pzQdF1uuhUH1O2MGjEQyGfC5k6CWtkQiK/6x
+gRLTgMiF7v20mi0V3Ka8BD/IpSJngZc0O6MEwu8fqloM6zBoNcEUCLEQ0aypSNme
+uBjvw74tedbd4Vv8sG3GNYSxjxd3RYda/cdnMUe4rvSZiZmHChzygI6CFJFJ6D4a
+k/lqXY3iLXBvNWLBHEhbQXvXxk/2a4/S1Sfj2JHhid4iK4nEjrabXN0qvu+Df7WK
+5JhVy/m62Zz2AnGR7x6sr2E=
+-----END CERTIFICATE-----
diff --git a/dev/backend-files/kit-ca-api-server.toml.j2 b/dev/backend-files/kit-ca-api-server.toml.j2
new file mode 100644
index 0000000000000000000000000000000000000000..9d7b95c26576ce45feb84825a24c1a6deed1c9f0
--- /dev/null
+++ b/dev/backend-files/kit-ca-api-server.toml.j2
@@ -0,0 +1,25 @@
+[web]
+baseurl = "http://localhost"
+listenAddr = ":3100"
+
+[oidc]
+clientid = "tcs-devel-ca-kit-edu"
+returnURL = "http://localhost:3100/oidc/callback"
+loginSuccessPath = "/"
+tokenLifetime = "1h"
+
+[ldap]
+bindDN = "scc-ism-ca2ad"
+bindPassword = "{{ LDAP_PW }}"
+
+[postgresql]
+databaseURL = "postgresql://tcs-devel:{{ DB_PW }}@postgres-v4.ca.kit.edu:5432/tcs-devel?sslmode=verify-full"
+
+[email]
+server = "smarthost.kit.edu:25"
+fromaddr = "portal-dev@portal-dev.local"
+fromname = "KIT-CA Portal Robot"
+adminaddrs = {{ ADMIN_MAIL_ADDR_ARRAY_STR }}
+signingKey = "/tmp/smime.key"
+signingCert = "/tmp/smime.pem"
+signingChain = "/PortalDevRootCA.pem"
diff --git a/dev/backend.dockerfile b/dev/backend.dockerfile
index 7b32fb4f7feae9ac698c07e165d9ae8346de0fa6..9e7a462016ed2a702a21f778f45c7f699529ca67 100644
--- a/dev/backend.dockerfile
+++ b/dev/backend.dockerfile
@@ -1,4 +1,27 @@
 FROM docker.io/golang:latest
 
-COPY backend /backend
+ENV DEBIAN_FRONTEND=noninteractive
+
+COPY backend-files /
+
+RUN cat /kit-ca-api-server.toml
+RUN mkdir /root/.config/ && ln -s /kit-ca-api-server.toml /root/.config/
+RUN apt-get update && apt-get install -y bsdmainutils && rm -rf /var/lib/apt/lists/*
+# Root CA created with `openssl req -x509 -nodes -new -newkey rsa:4096 -keyout PortalDevRootCA.key -out PortalDevRootCA.pem -subj '/C=DE/O=Karlsruhe Institute of Technology/CN=KIT-CA Portal Dev Root CA' -addext keyUsage=critical,keyCertSign -addext basicConstraints=critical,CA:true,pathlen:0 -addext subjectKeyIdentifier=hash`
+RUN openssl req \
+	-x509 \
+    -nodes \
+    -new \
+    -newkey rsa:4096 \
+    -keyout /tmp/smime.key \
+    -out /tmp/smime.pem \
+    -CA /PortalDevRootCA.pem \
+    -CAkey /PortalDevRootCA.key \
+    -set_serial 0x$(dd if=/dev/urandom count=12 bs=1 | hexdump -e '"%x"') \
+    -subj '/C=DE/O=Karlsruhe Institute of Technology/CN=KIT-CA Portal Robot/emailAddress=portal-dev@portal-dev.local' \
+    -addext keyUsage=critical,digitalSignature,keyEncipherment,nonRepudiation \
+    -addext extendedKeyUsage=emailProtection \
+    -addext basicConstraints=CA:false \
+    -addext subjectAltName=email:portal-dev@portal-dev.local
+
 ENTRYPOINT ["/backend"]
\ No newline at end of file
diff --git a/dev/compose.sh b/dev/compose.sh
index b109ace0ab743e3c7b68af3368794fcc470d641f..8b0b9636a51e1f4eb4ea93c403dcbd8ba04e2c47 100644
--- a/dev/compose.sh
+++ b/dev/compose.sh
@@ -6,25 +6,40 @@ else
 	executable=docker-compose
 fi
 
+if ! command -v $executable > /dev/null; then
+	echo "Neither podman-compose nor docker-compose found."
+	exit 1
+fi
+
+if ! command -v j2 > /dev/null; then
+	echo "Please install j2cli via your package manager or pipx."
+	exit 1
+fi
+
 $executable down
 
 set -o allexport
 source .env
 set +o allexport
 
-target_dir=$(pwd)
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+target_dir="$SCRIPT_DIR"/backend-files
 cd "$BACKEND_REPO_PATH/cmd/api-server/" || exit 1
 go build -o "$target_dir/backend" main.go || { echo "Go build failed."; exit 1; }
 cd - > /dev/null || exit 1
 
+j2 backend-files/kit-ca-api-server.toml.j2 > backend-files/kit-ca-api-server.toml
+
 $executable up -d --build
 
+rm backend-files/kit-ca-api-server.toml
+
 if command -v tmux > /dev/null && ! tmux has-session -t portal-dev 2> /dev/null; then
 	tmux new-session -d -s portal-dev
 	tmux split-window -v
 	tmux split-window -v
 	tmux select-layout even-vertical
-	tmux send-keys -t portal-dev.0 "while true; do podman logs -f portal-dev-backend; sleep 1; done" Enter
+	tmux send-keys -t portal-dev.0 "while true; do podman logs -f portal-dev-backend 2>&1 | tee >(jq -R 'fromjson?'); sleep 1; done" Enter
 	tmux send-keys -t portal-dev.1 "while true; do podman logs -f portal-dev-portal; sleep 1; done" Enter
 	tmux send-keys -t portal-dev.2 "while true; do podman logs -f portal-dev-caddy | jq -R 'fromjson? | \"[\(.ts | strflocaltime(\"%Y-%m-%dT%H:%M:%S%z\"))] \(.request.remote_ip) \(if .user_id == \"\" then \"-\" else .user_id end) \(.request.method) \(.request.uri) \(.request.proto) \(.status) \(.size)\"'; sleep 1; done" Enter
 	echo "You can now tmux a -t portal-dev!"