diff --git a/.codespellrc b/.codespellrc
index 8141e737daf270273c494f5327ff22940b3e4589..41b0ecd2c37dbcb2aec6af2f33d2cb28483b9a6a 100644
--- a/.codespellrc
+++ b/.codespellrc
@@ -1,3 +1,3 @@
 [codespell]
-skip = .cargo,.git,target,.env,Cargo.lock,*.asc
+skip = .cargo,.git,target,.env,Cargo.lock,*.asc,output,*.js
 ignore-words-list = crate,passt,ser
diff --git a/.env b/.env
index b328be2aee5f74c244f35926b22f8884d6d0e390..46ff96057fecc8b21c8c6bab9e22f3eb786c8723 100644
--- a/.env
+++ b/.env
@@ -1,4 +1,4 @@
 # Contains project specific variables
 
 # List of packages required specifically by this project
-PACMAN_PACKAGES="acl cargo-deny cargo-machete cargo-nextest clang cmake cocogitto codespell cpio edk2-ovmf erofs-utils git jq just lychee make mkosi mold mtools openssl pkgconf podman qemu release-plz reuse ripgrep rsop rustup rust-script sbsigntools sequoia-sq shellcheck swtpm systemd-ukify tangler zstd"
+PACMAN_PACKAGES="acl cargo-deny cargo-machete cargo-nextest clang cmake cocogitto codespell cpio edk2-ovmf erofs-utils git jq just lychee make mdbook mdbook-mermaid miniserve mkosi mold mtools openssl pkgconf podman qemu release-plz reuse ripgrep rsop rustup rust-script sbsigntools sequoia-sq shellcheck swtpm systemd-ukify tangler watchexec zstd"
diff --git a/.gitignore b/.gitignore
index 94c8def6f6178466b7d8fcd4395cfd075bad95eb..a6b5d838e40b1806cf83eeaf88c5f2b6f544713d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 # GnuPG only supports binary keyrings, because reasons, but we don't want to add binary keyrings to the repo
+output/
+resources/docs/*.js
 resources/mkosi/signstar/mkosi.extra/usr/lib/systemd/import-pubring.gpg
 resources/mkosi/signstar/mkosi.output
 resources/mkosi/signstar/mkosi.profiles/local-testing/mkosi.extra/usr/local/bin/
diff --git a/justfile b/justfile
index ff495c5eeb691648053554677470f1c6ec0f04e5..c28f88b45efa34a95dd1fc140fe06acf0b34b11c 100755
--- a/justfile
+++ b/justfile
@@ -7,6 +7,10 @@ set dotenv-load := true
 
 ignored := "false"
 
+# The output directory for documentation artifacts
+
+output_dir := "output"
+
 # Runs all checks and tests. Since this is the first recipe it is run by default.
 run-pre-commit-hook: check test
 
@@ -556,3 +560,35 @@ build-test-image openpgp_signing_key signing_key="resources/mkosi/signstar/mkosi
 run-image mkosi_options="" qemu_options="":
     just ensure-command mkosi
     mkosi -C resources/mkosi/signstar/ {{ mkosi_options }} qemu {{ qemu_options }}
+
+# Builds the documentation book using mdbook and stages all necessary rustdocs alongside
+build-book: docs
+    #!/usr/bin/env bash
+    set -euo pipefail
+
+    just ensure-command mdbook mdbook-mermaid
+
+    readonly target_dir="${CARGO_TARGET_DIR:-$PWD/target}"
+    readonly output_dir="{{ output_dir }}"
+    readonly rustdoc_dir="$output_dir/docs/rustdoc/"
+    mapfile -t workspace_members < <(just get-workspace-members 2>/dev/null)
+
+    mdbook-mermaid install resources/docs/
+    mdbook build resources/docs/
+
+    # move rust docs to their own namespaced dir
+    mkdir -p "$rustdoc_dir"
+    for name in "${workspace_members[@]}"; do
+        cp -r "$target_dir/doc/${name//-/_}" "$rustdoc_dir"
+    done
+
+# Serves the documentation book using miniserve
+serve-book: build-book
+    just ensure-command miniserve
+    miniserve --index=index.html {{ output_dir }}/docs
+
+# Watches the documentation book contents and rebuilds on change using mdbook (useful for development)
+watch-book:
+    just ensure-command watchexec
+    watchexec --exts md,toml,js --delay-run 5s :w
+    just build-book
diff --git a/resources/docs/book.toml b/resources/docs/book.toml
new file mode 100644
index 0000000000000000000000000000000000000000..aad0de21659c38ed1dcb558beab4b977bdb8b179
--- /dev/null
+++ b/resources/docs/book.toml
@@ -0,0 +1,22 @@
+[book]
+authors = [
+    "David Runge",
+    "Wiktor Kwapisiewicz",
+]
+language = "en"
+multilingual = false
+src = "src"
+title = "Signstar"
+
+[build]
+build-dir = "../../output/docs"
+
+[preprocessor]
+
+[preprocessor.mermaid]
+command = "mdbook-mermaid"
+
+[output]
+
+[output.html]
+additional-js = ["mermaid.min.js", "mermaid-init.js"]
diff --git a/resources/docs/src/CONTRIBUTING.md b/resources/docs/src/CONTRIBUTING.md
new file mode 120000
index 0000000000000000000000000000000000000000..c97564d93a7f0a753a23cd97d2467d595bd154ff
--- /dev/null
+++ b/resources/docs/src/CONTRIBUTING.md
@@ -0,0 +1 @@
+../../../CONTRIBUTING.md
\ No newline at end of file
diff --git a/resources/docs/src/README.md b/resources/docs/src/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..8a33348c7d811afb28795f9d529a9d96e6762eaf
--- /dev/null
+++ b/resources/docs/src/README.md
@@ -0,0 +1 @@
+../../../README.md
\ No newline at end of file
diff --git a/resources/docs/src/SUMMARY.md b/resources/docs/src/SUMMARY.md
new file mode 100644
index 0000000000000000000000000000000000000000..d14fdc391ea8c0fa0b4be1e9ec246a9e74001a56
--- /dev/null
+++ b/resources/docs/src/SUMMARY.md
@@ -0,0 +1,27 @@
+# Summary
+
+[Introduction](./README.md)
+
+# Components
+
+- [nethsm](./nethsm/README.md)
+  - [CHANGELOG](./nethsm/CHANGELOG.md)
+- [nethsm-backup](./nethsm-backup/README.md)
+- [nethsm-cli](./nethsm-cli/README.md)
+  - [CHANGELOG](./nethsm-cli/CHANGELOG.md)
+- [nethsm-config](./nethsm-config/README.md)
+  - [CHANGELOG](./nethsm-config/CHANGELOG.md)
+- [nethsm-tests](./nethsm-tests/README.md)
+  - [CHANGELOG](./nethsm-tests/CHANGELOG.md)
+- [signstar-configure-build](./signstar-configure-build/README.md)
+  - [CHANGELOG](./signstar-configure-build/CHANGELOG.md)
+
+# Architecture
+
+- [Design](./architecture/design.md)
+- [Evaluated Setups](./architecture/evaluated-setups.md)
+- [Previous Setup](./architecture/previous-setup.md)
+
+# Development
+
+- [Contributing Guidelines](./CONTRIBUTING.md)
diff --git a/resources/docs/src/architecture/design.md b/resources/docs/src/architecture/design.md
new file mode 120000
index 0000000000000000000000000000000000000000..a6b7fe8ae00f412262427e67e3f8cf50cbe19b5d
--- /dev/null
+++ b/resources/docs/src/architecture/design.md
@@ -0,0 +1 @@
+../../design.md
\ No newline at end of file
diff --git a/resources/docs/src/architecture/evaluated-setups.md b/resources/docs/src/architecture/evaluated-setups.md
new file mode 120000
index 0000000000000000000000000000000000000000..b8c3274a563e22af1e07db5e9b6dd9957362c73d
--- /dev/null
+++ b/resources/docs/src/architecture/evaluated-setups.md
@@ -0,0 +1 @@
+../../evaluated-setups.md
\ No newline at end of file
diff --git a/resources/docs/src/architecture/previous-setup.md b/resources/docs/src/architecture/previous-setup.md
new file mode 120000
index 0000000000000000000000000000000000000000..67dccbb12fda2f23d5d5e6b6fc53c00f99c2f45e
--- /dev/null
+++ b/resources/docs/src/architecture/previous-setup.md
@@ -0,0 +1 @@
+../../previous-setup.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-backup/README.md b/resources/docs/src/nethsm-backup/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..eb3a6eff0ff072523925a629cd224ca60696e4ff
--- /dev/null
+++ b/resources/docs/src/nethsm-backup/README.md
@@ -0,0 +1 @@
+../../../../nethsm-backup/README.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-cli/CHANGELOG.md b/resources/docs/src/nethsm-cli/CHANGELOG.md
new file mode 120000
index 0000000000000000000000000000000000000000..884cf66a606af76a0047498b46c015808e701746
--- /dev/null
+++ b/resources/docs/src/nethsm-cli/CHANGELOG.md
@@ -0,0 +1 @@
+../../../../nethsm-cli/CHANGELOG.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-cli/README.md b/resources/docs/src/nethsm-cli/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..50632e047757a63ad2eead9e62c36ee32ec01d5b
--- /dev/null
+++ b/resources/docs/src/nethsm-cli/README.md
@@ -0,0 +1 @@
+../../../../nethsm-cli/README.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-config/CHANGELOG.md b/resources/docs/src/nethsm-config/CHANGELOG.md
new file mode 120000
index 0000000000000000000000000000000000000000..4ed1c5276914c992de2729f1b932b04173b77b04
--- /dev/null
+++ b/resources/docs/src/nethsm-config/CHANGELOG.md
@@ -0,0 +1 @@
+../../../../nethsm-config/CHANGELOG.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-config/README.md b/resources/docs/src/nethsm-config/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..ec9c50c239bb7bb71f7b3b40bc33d8c01cf1d860
--- /dev/null
+++ b/resources/docs/src/nethsm-config/README.md
@@ -0,0 +1 @@
+../../../../nethsm-config/README.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-tests/CHANGELOG.md b/resources/docs/src/nethsm-tests/CHANGELOG.md
new file mode 120000
index 0000000000000000000000000000000000000000..4a085a0787905d28089df85afa317387a88a915a
--- /dev/null
+++ b/resources/docs/src/nethsm-tests/CHANGELOG.md
@@ -0,0 +1 @@
+../../../../nethsm-tests/CHANGELOG.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm-tests/README.md b/resources/docs/src/nethsm-tests/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..806f5b2ac99e3b0c2d5ecf05742d3d6b2fd26d5a
--- /dev/null
+++ b/resources/docs/src/nethsm-tests/README.md
@@ -0,0 +1 @@
+../../../../nethsm-tests/README.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm/CHANGELOG.md b/resources/docs/src/nethsm/CHANGELOG.md
new file mode 120000
index 0000000000000000000000000000000000000000..8bfd26f2e642e17ab3f951b9e9f314df6243ad8b
--- /dev/null
+++ b/resources/docs/src/nethsm/CHANGELOG.md
@@ -0,0 +1 @@
+../../../../nethsm/CHANGELOG.md
\ No newline at end of file
diff --git a/resources/docs/src/nethsm/README.md b/resources/docs/src/nethsm/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..6bb11408bf61457bd6ed907eff12e12008f241eb
--- /dev/null
+++ b/resources/docs/src/nethsm/README.md
@@ -0,0 +1 @@
+../../../../nethsm/README.md
\ No newline at end of file
diff --git a/resources/docs/src/signstar-configure-build/CHANGELOG.md b/resources/docs/src/signstar-configure-build/CHANGELOG.md
new file mode 120000
index 0000000000000000000000000000000000000000..b9150ad017bbae0c3a21e8bb5020268dc3a684c3
--- /dev/null
+++ b/resources/docs/src/signstar-configure-build/CHANGELOG.md
@@ -0,0 +1 @@
+../../../../signstar-configure-build/CHANGELOG.md
\ No newline at end of file
diff --git a/resources/docs/src/signstar-configure-build/README.md b/resources/docs/src/signstar-configure-build/README.md
new file mode 120000
index 0000000000000000000000000000000000000000..1a186b2c84663c40a1e6ba5f637ce539dc2e0aac
--- /dev/null
+++ b/resources/docs/src/signstar-configure-build/README.md
@@ -0,0 +1 @@
+../../../../signstar-configure-build/README.md
\ No newline at end of file