diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fc7f6bc02a330a4c580044760d9526c8e00299af..d055ab7609b7e7dd8798d8c6af4e0ffcc4827037 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,7 +16,7 @@ site:
         CHECKOUT_BRANCH: $UPSTREAM_BRANCH
     - when: on_success
   before_script:
-    - apt-get update && apt-get install -y --no-install-recommends python3-pip python3 make git wget software-properties-common
+    - apt-get update && apt-get install -y --no-install-recommends python3-pip python3 python3-venv make git wget software-properties-common
     - pip3 install -r requirements.txt
     - "echo \"CHECKOUT_BRANCH: $CHECKOUT_BRANCH UPSTREAM_BRANCH: $UPSTREAM_BRANCH\""
     - git clone https://gitlab.gwdg.de/GAUMI-fginfo/fg-website-data.git content --branch $CHECKOUT_BRANCH
@@ -30,7 +30,7 @@ site:
 docs:
   stage: build
   before_script:
-    - apt-get update && apt-get install -y --no-install-recommends python3-pip python3 make git wget software-properties-common
+    - apt-get update && apt-get install -y --no-install-recommends python3-pip python3 python3-venv make git wget software-properties-common
     - pip3 install -r requirements.txt
   script:
     - make docs
diff --git a/Makefile b/Makefile
index 473183306757e37cf39e305d765c389459c8444d..c45f2d19fd7657cbdda53f7ab58caad4f51cc3f0 100644
--- a/Makefile
+++ b/Makefile
@@ -5,20 +5,26 @@ html: docs build
 publish: build
 
 .PHONY: build
-build: pandoc mathjax
-	cd fgs && python3 __main__.py "../content" "../output" "../theme" "../config.json" "../lang.json"
+build: venv/bin/activate pandoc mathjax
+	. venv/bin/activate && cd fgs && python3 __main__.py "../content" "../output" "../theme" "../config.json" "../lang.json"
 
 .PHONY: docs
-docs: pandoc mathjax
-	cd fgs && python3 __main__.py "../docs" "../docs-output" "../theme" "../config.json" "../lang.json"
+docs: venv/bin/activate pandoc mathjax
+	. venv/bin/activate && cd fgs && python3 __main__.py "../docs" "../docs-output" "../theme" "../config.json" "../lang.json"
 
 .PHONY: mathjax
 mathjax:
+	git submodule init
+	git submodule update
 	[ ! -d output/mathjax ] && mkdir -p output && cp -vr mathjax/es5 output/mathjax || true
 
 .PHONY: devserver
-devserver:
-	python -m http.server 8000
+devserver: venv/bin/activate
+	. venv/bin/activate && python3 -m http.server 8000
+
+.PHONY: clean
+clean:
+	$(RM) -r venv output
 
 .PHONY: pandoc
 pandoc: pandoc-2.18
@@ -32,4 +38,7 @@ pandoc-2.18:
 	|| true
 	[ -x pandoc-2.18/bin/pandoc ]
 
+venv/bin/activate: requirements.txt
+	python3 -m venv venv
+	. venv/bin/activate && pip3 install -r requirements.txt
 
diff --git a/README.md b/README.md
index aa391f1b53ddd53f19dc3c66e993c8e21812ded2..a278a64aa46dc95bcde66b726d060d3b0ef4985e 100644
--- a/README.md
+++ b/README.md
@@ -24,10 +24,9 @@ Um an der Seite zu arbeiten ist es meistens sinnvoll diese auch lokal zu hosten.
 
 Die folgenden Befehle sind für Ubuntu 20.04 LTS (Focal) gedacht.
 
-1. Pakete installieren: `apt-get update && apt-get install -y --no-install-recommends python3-pip python3 make git wget software-properties-common`
-1. Metarepo klonen: `git clone --recurse-submodules git@gitlab.gwdg.de:GAUMI-fginfo/fg-website.git`
+1. Pakete installieren: `apt-get update && apt-get install -y --no-install-recommends python3-pip python3 python3-venv make git wget software-properties-common`
+1. Metarepo klonen: `git clone git@gitlab.gwdg.de:GAUMI-fginfo/fg-website.git`
 1. `cd fg-website`
-1. Python Pakete installieren: `pip3 install -r requirements.txt`
 1. Inhaltsrepo klonen: `git clone git@gitlab.gwdg.de:GAUMI-fginfo/fg-website-data.git content`
 
 ### (Automatisch) Bauen und Hosten