diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index 242306a..4ed7be0 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -29,3 +29,17 @@ jobs: run: | test -d docs/public test -n "$(find docs/public -mindepth 1 -print -quit)" + - name: Install Graphviz and MkDocs + run: | + sudo apt-get update + sudo apt-get install -y graphviz + dot -V + python3 -m pip install --user mkdocs + - name: Validate public docs and diagrams + run: | + test -f docs/public/physical-topology.svg + test -f docs/public/docker-traefik-dynu.svg + ! rg -n "Graphviz dot not found" docs/public/*.svg + ! rg -n "lan\.ddnsgeek\.com" docs/public/*.svg docs/public/*.md + ! rg -n -i "password|token|api_key|secret" docs/public/*.svg + python3 -m mkdocs build -f mkdocs-public.yml --strict diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 337fc84..1757d6d 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -28,13 +28,26 @@ jobs: test -d docs/public test -n "$(find docs/public -mindepth 1 -print -quit)" + - name: Install Graphviz + run: | + sudo apt-get update + sudo apt-get install -y graphviz + dot -V + + - name: Validate sanitized diagram artifacts + run: | + test -f docs/public/physical-topology.svg + test -f docs/public/docker-traefik-dynu.svg + ! rg -n "Graphviz dot not found" docs/public/*.svg + ! rg -n "lan\.ddnsgeek\.com" docs/public/*.svg docs/public/*.md + ! rg -n -i "password|token|api_key|secret" docs/public/*.svg + - name: Install MkDocs run: | python3 -m pip install --user mkdocs - name: Build public MkDocs site run: | - python3 -m mkdocs build -f mkdocs-public.yml --strict - name: Verify published content excludes internal/generated docs diff --git a/docs/README.md b/docs/README.md index 6716d57..7fdf925 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,21 +2,37 @@ ## Local generation +Install prerequisites: + +```bash +sudo apt-get update +sudo apt-get install -y graphviz +``` + +Then generate and validate public docs: + ```bash chmod +x scripts/docs/*.sh scripts/docs/generate-all.sh +python3 -m mkdocs build -f mkdocs-public.yml --strict +``` + +NixOS-friendly alternative: + +```bash +nix shell nixpkgs#graphviz nixpkgs#python3 nixpkgs#python3Packages.pyyaml ``` This pipeline only runs `docker compose config` and static parsing. It does **not** start containers. ## CI behaviour -GitHub Actions workflow `.github/workflows/generate-docs.yml` runs on pushes/PRs to `main` and manual dispatch. It generates docs and uploads them as the `generated-documentation` artifact. +GitHub Actions workflow `.github/workflows/generate-docs.yml` validates committed public docs and diagrams and runs a strict public MkDocs build. ## Outputs - `docs/generated`: resolved compose config and markdown inventories -- `docs/diagrams`: DOT and SVG architecture diagram +- `docs/diagrams`: generated DOT and SVG diagrams - `docs/public`: sanitized copy for public sharing ## Publication safety diff --git a/docs/diagrams/docker-compose.dot b/docs/diagrams/docker-compose.dot index 487ec63..9c78dfa 100644 --- a/docs/diagrams/docker-compose.dot +++ b/docs/diagrams/docker-compose.dot @@ -1,6 +1,6 @@ digraph Compose { rankdir=LR; - node [fontname=Helvetica]; + node [fontname="Helvetica"]; "svc:authelia" [label="authelia", shape=box, style=filled, fillcolor="#dfefff"]; "svc:crowdsec" [label="crowdsec", shape=box, style=filled, fillcolor="#dfefff"]; "svc:docker-socket-proxy" [label="docker-socket-proxy", shape=box, style=filled, fillcolor="#dfefff"]; diff --git a/docs/diagrams/docker-compose.svg b/docs/diagrams/docker-compose.svg index cd8a7c6..1991277 100644 --- a/docs/diagrams/docker-compose.svg +++ b/docs/diagrams/docker-compose.svg @@ -1 +1,463 @@ -Graphviz dot not found in environment. + + + + + + +Compose + + + +svc:authelia + +authelia + + + +net:traefik + +traefik + + + +svc:authelia->net:traefik + + + + + +svc:crowdsec + +crowdsec + + + +svc:crowdsec->net:traefik + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +net:monitor + +monitor + + + +svc:docker-socket-proxy->net:monitor + + + + + +svc:docker-socket-proxy->net:traefik + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +svc:docker-update-exporter->net:monitor + + + + + +svc:error-pages + +error-pages + + + +svc:error-pages->net:traefik + + + + + +svc:gitea + +gitea + + + +svc:gitea->net:traefik + + + + + +svc:gitea-runner + +gitea-runner + + + +svc:gitea-runner->net:traefik + + + + + +svc:gotify + +gotify + + + +svc:gotify->net:traefik + + + + + +svc:grafana + +grafana + + + +svc:grafana->net:monitor + + + + + +svc:grafana->net:traefik + + + + + +svc:gramps-redis + +gramps-redis + + + +net:gramps + +gramps + + + +svc:gramps-redis->net:gramps + + + + + +svc:grampsweb + +grampsweb + + + +svc:grampsweb->net:gramps + + + + + +svc:grampsweb->net:traefik + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +svc:grampsweb_celery->net:gramps + + + + + +svc:influxdb + +influxdb + + + +svc:influxdb->net:monitor + + + + + +svc:influxdb->net:traefik + + + + + +svc:monitor-kuma + +monitor-kuma + + + +svc:monitor-kuma->net:monitor + + + + + +svc:monitor-kuma->net:traefik + + + + + +svc:mtls-bridge + +mtls-bridge + + + +svc:mtls-bridge->net:monitor + + + + + +svc:mtls-bridge->net:traefik + + + + + +svc:nextcloud-db + +nextcloud-db + + + +net:nextcloud + +nextcloud + + + +svc:nextcloud-db->net:nextcloud + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +svc:nextcloud-redis->net:nextcloud + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +svc:nextcloud-webapp->net:nextcloud + + + + + +svc:nextcloud-webapp->net:traefik + + + + + +svc:node-exporter + +node-exporter + + + +svc:node-exporter->net:monitor + + + + + +svc:node-red + +node-red + + + +svc:node-red->net:monitor + + + + + +svc:node-red->net:traefik + + + + + +svc:passbolt-db + +passbolt-db + + + +net:passbolt + +passbolt + + + +svc:passbolt-db->net:passbolt + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +svc:passbolt-webapp->net:passbolt + + + + + +svc:passbolt-webapp->net:traefik + + + + + +svc:pihole-exporter + +pihole-exporter + + + +svc:pihole-exporter->net:monitor + + + + + +svc:portainer + +portainer + + + +svc:portainer->net:traefik + + + + + +svc:prometheus + +prometheus + + + +svc:prometheus->net:monitor + + + + + +svc:prometheus->net:traefik + + + + + +svc:searxng-webapp + +searxng-webapp + + + +svc:searxng-webapp->net:traefik + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +svc:shift-recorder-web->net:traefik + + + + + +svc:stockfill + +stockfill + + + +svc:stockfill->net:traefik + + + + + +svc:telegraf + +telegraf + + + +svc:telegraf->net:monitor + + + + + +svc:traefik + +traefik + + + +svc:traefik->net:traefik + + + + + diff --git a/docs/diagrams/docker-traefik-dynu.dot b/docs/diagrams/docker-traefik-dynu.dot new file mode 100644 index 0000000..d8ce9bf --- /dev/null +++ b/docs/diagrams/docker-traefik-dynu.dot @@ -0,0 +1,260 @@ +digraph DockerTraefikDynu { + graph [rankdir=LR, compound=true, splines=true, nodesep=0.5, ranksep=1.0, fontname="Helvetica"]; + node [fontname="Helvetica", fontsize=10, style="rounded,filled"]; + edge [fontname="Helvetica", fontsize=9]; + "ext:dynu" [label="Dynu / Public DNS", shape=oval, fillcolor="#fde68a"]; + "svc:traefik" [label="traefik", shape=box, fillcolor="#bfdbfe"]; + "net:gramps" [label="gramps", shape=ellipse, fillcolor="#f3f4f6"]; + "net:monitor" [label="monitor", shape=ellipse, fillcolor="#f3f4f6"]; + "net:nextcloud" [label="nextcloud", shape=ellipse, fillcolor="#f3f4f6"]; + "net:passbolt" [label="passbolt", shape=ellipse, fillcolor="#f3f4f6"]; + "net:traefik" [label="traefik", shape=ellipse, fillcolor="#f3f4f6"]; + "svc:authelia" [label="authelia", shape=box, fillcolor="#dcfce7"]; + "svc:authelia" -> "net:traefik" [color="#6b7280"]; + "router:authelia" [label="router:authelia\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:authelia"; + "traefik-service:authelia" [label="service:authelia", shape=component, fillcolor="#fecaca"]; + "router:authelia" -> "traefik-service:authelia"; + "dns:service-1." [label="service-1.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-1."; + "dns:service-1." -> "router:authelia"; + "svc:crowdsec" [label="crowdsec", shape=box, fillcolor="#dcfce7"]; + "svc:crowdsec" -> "net:traefik" [color="#6b7280"]; + "svc:docker-socket-proxy" [label="docker-socket-proxy", shape=box, fillcolor="#dcfce7"]; + "svc:docker-socket-proxy" -> "net:monitor" [color="#6b7280"]; + "svc:docker-socket-proxy" -> "net:traefik" [color="#6b7280"]; + "svc:docker-update-exporter" [label="docker-update-exporter", shape=box, fillcolor="#dcfce7"]; + "svc:docker-update-exporter" -> "net:monitor" [color="#6b7280"]; + "svc:error-pages" [label="error-pages", shape=box, fillcolor="#dcfce7"]; + "svc:error-pages" -> "net:traefik" [color="#6b7280"]; + "router:error-pages-router" [label="router:error-pages-router\nentry:web tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:error-pages-router"; + "traefik-service:error-pages" [label="service:error-pages", shape=component, fillcolor="#fecaca"]; + "router:error-pages-router" -> "traefik-service:error-pages"; + "mw:error-pages-middleware" [label="error-pages-middleware", shape=hexagon, fillcolor="#ddd6fe"]; + "router:error-pages-router" -> "mw:error-pages-middleware" [style=dashed]; + "traefik-service:error-pages-service" [label="service:error-pages-service\nport:8080", shape=component, fillcolor="#fecaca"]; + "traefik-service:error-pages-service" -> "svc:error-pages"; + "svc:gitea" [label="gitea", shape=box, fillcolor="#dcfce7"]; + "svc:gitea" -> "net:traefik" [color="#6b7280"]; + "router:gitea" [label="router:gitea\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:gitea"; + "traefik-service:gitea" [label="service:gitea", shape=component, fillcolor="#fecaca"]; + "router:gitea" -> "traefik-service:gitea"; + "dns:service-2." [label="service-2.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-2."; + "dns:service-2." -> "router:gitea"; + "traefik-service:gitea" [label="service:gitea\nport:3000", shape=component, fillcolor="#fecaca"]; + "traefik-service:gitea" -> "svc:gitea"; + "svc:gitea-runner" [label="gitea-runner", shape=box, fillcolor="#dcfce7"]; + "svc:gitea-runner" -> "net:traefik" [color="#6b7280"]; + "svc:gotify" [label="gotify", shape=box, fillcolor="#dcfce7"]; + "svc:gotify" -> "net:traefik" [color="#6b7280"]; + "router:gotify" [label="router:gotify\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:gotify"; + "traefik-service:gotify" [label="service:gotify", shape=component, fillcolor="#fecaca"]; + "router:gotify" -> "traefik-service:gotify"; + "dns:service-3." [label="service-3.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-3."; + "dns:service-3." -> "router:gotify"; + "traefik-service:gotify" [label="service:gotify\nport:80", shape=component, fillcolor="#fecaca"]; + "traefik-service:gotify" -> "svc:gotify"; + "svc:grafana" [label="grafana", shape=box, fillcolor="#dcfce7"]; + "svc:grafana" -> "net:monitor" [color="#6b7280"]; + "svc:grafana" -> "net:traefik" [color="#6b7280"]; + "router:grafana" [label="router:grafana\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:grafana"; + "traefik-service:grafana" [label="service:grafana", shape=component, fillcolor="#fecaca"]; + "router:grafana" -> "traefik-service:grafana"; + "dns:service-4." [label="service-4.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-4."; + "dns:service-4." -> "router:grafana"; + "traefik-service:grafana" [label="service:grafana\nport:3000", shape=component, fillcolor="#fecaca"]; + "traefik-service:grafana" -> "svc:grafana"; + "svc:gramps-redis" [label="gramps-redis", shape=box, fillcolor="#dcfce7"]; + "svc:gramps-redis" -> "net:gramps" [color="#6b7280"]; + "svc:grampsweb" [label="grampsweb", shape=box, fillcolor="#dcfce7"]; + "svc:grampsweb" -> "net:gramps" [color="#6b7280"]; + "svc:grampsweb" -> "net:traefik" [color="#6b7280"]; + "router:gramps" [label="router:gramps\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:gramps"; + "traefik-service:grampsweb" [label="service:grampsweb", shape=component, fillcolor="#fecaca"]; + "router:gramps" -> "traefik-service:grampsweb"; + "dns:service-5." [label="service-5.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-5."; + "dns:service-5." -> "router:gramps"; + "traefik-service:gramps" [label="service:gramps\nport:5000", shape=component, fillcolor="#fecaca"]; + "traefik-service:gramps" -> "svc:grampsweb"; + "svc:grampsweb_celery" [label="grampsweb_celery", shape=box, fillcolor="#dcfce7"]; + "svc:grampsweb_celery" -> "net:gramps" [color="#6b7280"]; + "svc:influxdb" [label="influxdb", shape=box, fillcolor="#dcfce7"]; + "svc:influxdb" -> "net:monitor" [color="#6b7280"]; + "svc:influxdb" -> "net:traefik" [color="#6b7280"]; + "router:influxdb" [label="router:influxdb\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:influxdb"; + "traefik-service:influxdb" [label="service:influxdb", shape=component, fillcolor="#fecaca"]; + "router:influxdb" -> "traefik-service:influxdb"; + "dns:service-6." [label="service-6.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-6."; + "dns:service-6." -> "router:influxdb"; + "mw:authelia" [label="authelia", shape=hexagon, fillcolor="#ddd6fe"]; + "router:influxdb" -> "mw:authelia" [style=dashed]; + "traefik-service:influxdb" [label="service:influxdb\nport:8086", shape=component, fillcolor="#fecaca"]; + "traefik-service:influxdb" -> "svc:influxdb"; + "svc:monitor-kuma" [label="monitor-kuma", shape=box, fillcolor="#dcfce7"]; + "svc:monitor-kuma" -> "net:monitor" [color="#6b7280"]; + "svc:monitor-kuma" -> "net:traefik" [color="#6b7280"]; + "router:monitor" [label="router:monitor\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:monitor"; + "traefik-service:monitor-kuma" [label="service:monitor-kuma", shape=component, fillcolor="#fecaca"]; + "router:monitor" -> "traefik-service:monitor-kuma"; + "dns:service-7." [label="service-7.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-7."; + "dns:service-7." -> "router:monitor"; + "traefik-service:monitor" [label="service:monitor\nport:3001", shape=component, fillcolor="#fecaca"]; + "traefik-service:monitor" -> "svc:monitor-kuma"; + "svc:mtls-bridge" [label="mtls-bridge", shape=box, fillcolor="#dcfce7"]; + "svc:mtls-bridge" -> "net:monitor" [color="#6b7280"]; + "svc:mtls-bridge" -> "net:traefik" [color="#6b7280"]; + "router:mtls-bridge" [label="router:mtls-bridge\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:mtls-bridge"; + "traefik-service:mtls-bridge" [label="service:mtls-bridge", shape=component, fillcolor="#fecaca"]; + "router:mtls-bridge" -> "traefik-service:mtls-bridge"; + "dns:service-8." [label="service-8.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-8."; + "dns:service-8." -> "router:mtls-bridge"; + "mw:mtls-bridge-auth" [label="mtls-bridge-auth", shape=hexagon, fillcolor="#ddd6fe"]; + "router:mtls-bridge" -> "mw:mtls-bridge-auth" [style=dashed]; + "mw:mtls-bridge-cors" [label="mtls-bridge-cors", shape=hexagon, fillcolor="#ddd6fe"]; + "router:mtls-bridge" -> "mw:mtls-bridge-cors" [style=dashed]; + "router:mtls-bridge-preflight" [label="router:mtls-bridge-preflight\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:mtls-bridge-preflight"; + "traefik-service:mtls-bridge" [label="service:mtls-bridge", shape=component, fillcolor="#fecaca"]; + "router:mtls-bridge-preflight" -> "traefik-service:mtls-bridge"; + "dns:service-8." [label="service-8.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-8."; + "dns:service-8." -> "router:mtls-bridge-preflight"; + "mw:mtls-bridge-cors" [label="mtls-bridge-cors", shape=hexagon, fillcolor="#ddd6fe"]; + "router:mtls-bridge-preflight" -> "mw:mtls-bridge-cors" [style=dashed]; + "traefik-service:mtls-bridge" [label="service:mtls-bridge\nport:8080", shape=component, fillcolor="#fecaca"]; + "traefik-service:mtls-bridge" -> "svc:mtls-bridge"; + "svc:nextcloud-db" [label="nextcloud-db", shape=box, fillcolor="#dcfce7"]; + "svc:nextcloud-db" -> "net:nextcloud" [color="#6b7280"]; + "svc:nextcloud-redis" [label="nextcloud-redis", shape=box, fillcolor="#dcfce7"]; + "svc:nextcloud-redis" -> "net:nextcloud" [color="#6b7280"]; + "svc:nextcloud-webapp" [label="nextcloud-webapp", shape=box, fillcolor="#dcfce7"]; + "svc:nextcloud-webapp" -> "net:nextcloud" [color="#6b7280"]; + "svc:nextcloud-webapp" -> "net:traefik" [color="#6b7280"]; + "router:nextcloud" [label="router:nextcloud\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:nextcloud"; + "traefik-service:nextcloud-webapp" [label="service:nextcloud-webapp", shape=component, fillcolor="#fecaca"]; + "router:nextcloud" -> "traefik-service:nextcloud-webapp"; + "dns:service-9." [label="service-9.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-9."; + "dns:service-9." -> "router:nextcloud"; + "mw:nextcloud-dav" [label="nextcloud-dav", shape=hexagon, fillcolor="#ddd6fe"]; + "router:nextcloud" -> "mw:nextcloud-dav" [style=dashed]; + "mw:nextcloud-webfinger" [label="nextcloud-webfinger", shape=hexagon, fillcolor="#ddd6fe"]; + "router:nextcloud" -> "mw:nextcloud-webfinger" [style=dashed]; + "svc:node-exporter" [label="node-exporter", shape=box, fillcolor="#dcfce7"]; + "svc:node-exporter" -> "net:monitor" [color="#6b7280"]; + "svc:node-red" [label="node-red", shape=box, fillcolor="#dcfce7"]; + "svc:node-red" -> "net:monitor" [color="#6b7280"]; + "svc:node-red" -> "net:traefik" [color="#6b7280"]; + "router:node-red" [label="router:node-red\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:node-red"; + "traefik-service:node-red" [label="service:node-red", shape=component, fillcolor="#fecaca"]; + "router:node-red" -> "traefik-service:node-red"; + "dns:service-10." [label="service-10.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-10."; + "dns:service-10." -> "router:node-red"; + "mw:authelia" [label="authelia", shape=hexagon, fillcolor="#ddd6fe"]; + "router:node-red" -> "mw:authelia" [style=dashed]; + "traefik-service:node-red" [label="service:node-red\nport:1880", shape=component, fillcolor="#fecaca"]; + "traefik-service:node-red" -> "svc:node-red"; + "svc:passbolt-db" [label="passbolt-db", shape=box, fillcolor="#dcfce7"]; + "svc:passbolt-db" -> "net:passbolt" [color="#6b7280"]; + "svc:passbolt-webapp" [label="passbolt-webapp", shape=box, fillcolor="#dcfce7"]; + "svc:passbolt-webapp" -> "net:passbolt" [color="#6b7280"]; + "svc:passbolt-webapp" -> "net:traefik" [color="#6b7280"]; + "router:passbolt" [label="router:passbolt\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:passbolt"; + "traefik-service:passbolt-webapp" [label="service:passbolt-webapp", shape=component, fillcolor="#fecaca"]; + "router:passbolt" -> "traefik-service:passbolt-webapp"; + "dns:service-11." [label="service-11.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-11."; + "dns:service-11." -> "router:passbolt"; + "svc:pihole-exporter" [label="pihole-exporter", shape=box, fillcolor="#dcfce7"]; + "svc:pihole-exporter" -> "net:monitor" [color="#6b7280"]; + "svc:portainer" [label="portainer", shape=box, fillcolor="#dcfce7"]; + "svc:portainer" -> "net:traefik" [color="#6b7280"]; + "router:portainer" [label="router:portainer\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:portainer"; + "traefik-service:portainer" [label="service:portainer", shape=component, fillcolor="#fecaca"]; + "router:portainer" -> "traefik-service:portainer"; + "dns:service-12." [label="service-12.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-12."; + "dns:service-12." -> "router:portainer"; + "traefik-service:portainer" [label="service:portainer\nport:9000", shape=component, fillcolor="#fecaca"]; + "traefik-service:portainer" -> "svc:portainer"; + "svc:prometheus" [label="prometheus", shape=box, fillcolor="#dcfce7"]; + "svc:prometheus" -> "net:monitor" [color="#6b7280"]; + "svc:prometheus" -> "net:traefik" [color="#6b7280"]; + "router:prometheus" [label="router:prometheus\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:prometheus"; + "traefik-service:prometheus" [label="service:prometheus", shape=component, fillcolor="#fecaca"]; + "router:prometheus" -> "traefik-service:prometheus"; + "dns:service-13." [label="service-13.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-13."; + "dns:service-13." -> "router:prometheus"; + "mw:authelia" [label="authelia", shape=hexagon, fillcolor="#ddd6fe"]; + "router:prometheus" -> "mw:authelia" [style=dashed]; + "traefik-service:prometheus" [label="service:prometheus\nport:9090", shape=component, fillcolor="#fecaca"]; + "traefik-service:prometheus" -> "svc:prometheus"; + "svc:searxng-webapp" [label="searxng-webapp", shape=box, fillcolor="#dcfce7"]; + "svc:searxng-webapp" -> "net:traefik" [color="#6b7280"]; + "router:searxng" [label="router:searxng\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:searxng"; + "traefik-service:searxng-webapp" [label="service:searxng-webapp", shape=component, fillcolor="#fecaca"]; + "router:searxng" -> "traefik-service:searxng-webapp"; + "dns:service-14." [label="service-14.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-14."; + "dns:service-14." -> "router:searxng"; + "traefik-service:searxng" [label="service:searxng\nport:8080", shape=component, fillcolor="#fecaca"]; + "traefik-service:searxng" -> "svc:searxng-webapp"; + "svc:shift-recorder-web" [label="shift-recorder-web", shape=box, fillcolor="#dcfce7"]; + "svc:shift-recorder-web" -> "net:traefik" [color="#6b7280"]; + "router:shifts" [label="router:shifts\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:shifts"; + "traefik-service:shift-recorder-web" [label="service:shift-recorder-web", shape=component, fillcolor="#fecaca"]; + "router:shifts" -> "traefik-service:shift-recorder-web"; + "dns:service-15." [label="service-15.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-15."; + "dns:service-15." -> "router:shifts"; + "traefik-service:shifts" [label="service:shifts\nport:80", shape=component, fillcolor="#fecaca"]; + "traefik-service:shifts" -> "svc:shift-recorder-web"; + "svc:stockfill" [label="stockfill", shape=box, fillcolor="#dcfce7"]; + "svc:stockfill" -> "net:traefik" [color="#6b7280"]; + "router:stockfill" [label="router:stockfill\nentry:websecure tls:true", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:stockfill"; + "traefik-service:stockfill" [label="service:stockfill", shape=component, fillcolor="#fecaca"]; + "router:stockfill" -> "traefik-service:stockfill"; + "dns:service-16." [label="service-16.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-16."; + "dns:service-16." -> "router:stockfill"; + "traefik-service:stockfill" [label="service:stockfill\nport:80", shape=component, fillcolor="#fecaca"]; + "traefik-service:stockfill" -> "svc:stockfill"; + "svc:telegraf" [label="telegraf", shape=box, fillcolor="#dcfce7"]; + "svc:telegraf" -> "net:monitor" [color="#6b7280"]; + "svc:traefik" [label="traefik", shape=box, fillcolor="#dcfce7"]; + "svc:traefik" -> "net:traefik" [color="#6b7280"]; + "router:traefik" [label="router:traefik\nentry:websecure tls:false", shape=diamond, fillcolor="#fbcfe8"]; + "svc:traefik" -> "router:traefik"; + "traefik-service:api@internal" [label="service:api@internal", shape=component, fillcolor="#fecaca"]; + "router:traefik" -> "traefik-service:api@internal"; + "dns:service-17." [label="service-17.", shape=note, fillcolor="#fde68a"]; + "ext:dynu" -> "dns:service-17."; + "dns:service-17." -> "router:traefik"; + "mw:authelia" [label="authelia", shape=hexagon, fillcolor="#ddd6fe"]; + "router:traefik" -> "mw:authelia" [style=dashed]; +} diff --git a/docs/diagrams/docker-traefik-dynu.svg b/docs/diagrams/docker-traefik-dynu.svg new file mode 100644 index 0000000..3011e6a --- /dev/null +++ b/docs/diagrams/docker-traefik-dynu.svg @@ -0,0 +1,1560 @@ + + + + + + +DockerTraefikDynu + + + +ext:dynu + +Dynu / Public DNS + + + +dns:service-1.<internal-domain> + + + +service-1.<internal-domain> + + + +ext:dynu->dns:service-1.<internal-domain> + + + + + +dns:service-2.<internal-domain> + + + +service-2.<internal-domain> + + + +ext:dynu->dns:service-2.<internal-domain> + + + + + +dns:service-3.<internal-domain> + + + +service-3.<internal-domain> + + + +ext:dynu->dns:service-3.<internal-domain> + + + + + +dns:service-4.<internal-domain> + + + +service-4.<internal-domain> + + + +ext:dynu->dns:service-4.<internal-domain> + + + + + +dns:service-5.<internal-domain> + + + +service-5.<internal-domain> + + + +ext:dynu->dns:service-5.<internal-domain> + + + + + +dns:service-6.<internal-domain> + + + +service-6.<internal-domain> + + + +ext:dynu->dns:service-6.<internal-domain> + + + + + +dns:service-7.<internal-domain> + + + +service-7.<internal-domain> + + + +ext:dynu->dns:service-7.<internal-domain> + + + + + +dns:service-8.<internal-domain> + + + +service-8.<internal-domain> + + + +ext:dynu->dns:service-8.<internal-domain> + + + + + +ext:dynu->dns:service-8.<internal-domain> + + + + + +dns:service-9.<internal-domain> + + + +service-9.<internal-domain> + + + +ext:dynu->dns:service-9.<internal-domain> + + + + + +dns:service-10.<internal-domain> + + + +service-10.<internal-domain> + + + +ext:dynu->dns:service-10.<internal-domain> + + + + + +dns:service-11.<internal-domain> + + + +service-11.<internal-domain> + + + +ext:dynu->dns:service-11.<internal-domain> + + + + + +dns:service-12.<internal-domain> + + + +service-12.<internal-domain> + + + +ext:dynu->dns:service-12.<internal-domain> + + + + + +dns:service-13.<internal-domain> + + + +service-13.<internal-domain> + + + +ext:dynu->dns:service-13.<internal-domain> + + + + + +dns:service-14.<internal-domain> + + + +service-14.<internal-domain> + + + +ext:dynu->dns:service-14.<internal-domain> + + + + + +dns:service-15.<internal-domain> + + + +service-15.<internal-domain> + + + +ext:dynu->dns:service-15.<internal-domain> + + + + + +dns:service-16.<internal-domain> + + + +service-16.<internal-domain> + + + +ext:dynu->dns:service-16.<internal-domain> + + + + + +dns:service-17.<internal-domain> + + + +service-17.<internal-domain> + + + +ext:dynu->dns:service-17.<internal-domain> + + + + + +svc:traefik + +traefik + + + +net:traefik + +traefik + + + +svc:traefik->net:traefik + + + + + +router:authelia + +router:authelia +entry:websecure tls:true + + + +svc:traefik->router:authelia + + + + + +router:error-pages-router + +router:error-pages-router +entry:web tls:false + + + +svc:traefik->router:error-pages-router + + + + + +router:gitea + +router:gitea +entry:websecure tls:true + + + +svc:traefik->router:gitea + + + + + +router:gotify + +router:gotify +entry:websecure tls:false + + + +svc:traefik->router:gotify + + + + + +router:grafana + +router:grafana +entry:websecure tls:false + + + +svc:traefik->router:grafana + + + + + +router:gramps + +router:gramps +entry:websecure tls:false + + + +svc:traefik->router:gramps + + + + + +router:influxdb + +router:influxdb +entry:websecure tls:false + + + +svc:traefik->router:influxdb + + + + + +router:monitor + +router:monitor +entry:websecure tls:true + + + +svc:traefik->router:monitor + + + + + +router:mtls-bridge + +router:mtls-bridge +entry:websecure tls:false + + + +svc:traefik->router:mtls-bridge + + + + + +router:mtls-bridge-preflight + +router:mtls-bridge-preflight +entry:websecure tls:false + + + +svc:traefik->router:mtls-bridge-preflight + + + + + +router:nextcloud + +router:nextcloud +entry:websecure tls:false + + + +svc:traefik->router:nextcloud + + + + + +router:node-red + +router:node-red +entry:websecure tls:false + + + +svc:traefik->router:node-red + + + + + +router:passbolt + +router:passbolt +entry:websecure tls:false + + + +svc:traefik->router:passbolt + + + + + +router:portainer + +router:portainer +entry:websecure tls:true + + + +svc:traefik->router:portainer + + + + + +router:prometheus + +router:prometheus +entry:websecure tls:false + + + +svc:traefik->router:prometheus + + + + + +router:searxng + +router:searxng +entry:websecure tls:false + + + +svc:traefik->router:searxng + + + + + +router:shifts + +router:shifts +entry:websecure tls:true + + + +svc:traefik->router:shifts + + + + + +router:stockfill + +router:stockfill +entry:websecure tls:true + + + +svc:traefik->router:stockfill + + + + + +router:traefik + +router:traefik +entry:websecure tls:false + + + +svc:traefik->router:traefik + + + + + +net:gramps + +gramps + + + +net:monitor + +monitor + + + +net:nextcloud + +nextcloud + + + +net:passbolt + +passbolt + + + +svc:authelia + +authelia + + + +svc:authelia->net:traefik + + + + + +traefik-service:authelia + + + +service:authelia + + + +router:authelia->traefik-service:authelia + + + + + +dns:service-1.<internal-domain>->router:authelia + + + + + +svc:crowdsec + +crowdsec + + + +svc:crowdsec->net:traefik + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +svc:docker-socket-proxy->net:monitor + + + + + +svc:docker-socket-proxy->net:traefik + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +svc:docker-update-exporter->net:monitor + + + + + +svc:error-pages + +error-pages + + + +svc:error-pages->net:traefik + + + + + +traefik-service:error-pages + + + +service:error-pages + + + +router:error-pages-router->traefik-service:error-pages + + + + + +mw:error-pages-middleware + +error-pages-middleware + + + +router:error-pages-router->mw:error-pages-middleware + + + + + +traefik-service:error-pages-service + + + +service:error-pages-service +port:8080 + + + +traefik-service:error-pages-service->svc:error-pages + + + + + +svc:gitea + +gitea + + + +svc:gitea->net:traefik + + + + + +traefik-service:gitea + + + +service:gitea +port:3000 + + + +router:gitea->traefik-service:gitea + + + + + +traefik-service:gitea->svc:gitea + + + + + +dns:service-2.<internal-domain>->router:gitea + + + + + +svc:gitea-runner + +gitea-runner + + + +svc:gitea-runner->net:traefik + + + + + +svc:gotify + +gotify + + + +svc:gotify->net:traefik + + + + + +traefik-service:gotify + + + +service:gotify +port:80 + + + +router:gotify->traefik-service:gotify + + + + + +traefik-service:gotify->svc:gotify + + + + + +dns:service-3.<internal-domain>->router:gotify + + + + + +svc:grafana + +grafana + + + +svc:grafana->net:monitor + + + + + +svc:grafana->net:traefik + + + + + +traefik-service:grafana + + + +service:grafana +port:3000 + + + +router:grafana->traefik-service:grafana + + + + + +traefik-service:grafana->svc:grafana + + + + + +dns:service-4.<internal-domain>->router:grafana + + + + + +svc:gramps-redis + +gramps-redis + + + +svc:gramps-redis->net:gramps + + + + + +svc:grampsweb + +grampsweb + + + +svc:grampsweb->net:gramps + + + + + +svc:grampsweb->net:traefik + + + + + +traefik-service:grampsweb + + + +service:grampsweb + + + +router:gramps->traefik-service:grampsweb + + + + + +dns:service-5.<internal-domain>->router:gramps + + + + + +traefik-service:gramps + + + +service:gramps +port:5000 + + + +traefik-service:gramps->svc:grampsweb + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +svc:grampsweb_celery->net:gramps + + + + + +svc:influxdb + +influxdb + + + +svc:influxdb->net:monitor + + + + + +svc:influxdb->net:traefik + + + + + +traefik-service:influxdb + + + +service:influxdb +port:8086 + + + +router:influxdb->traefik-service:influxdb + + + + + +mw:authelia + +authelia + + + +router:influxdb->mw:authelia + + + + + +traefik-service:influxdb->svc:influxdb + + + + + +dns:service-6.<internal-domain>->router:influxdb + + + + + +svc:monitor-kuma + +monitor-kuma + + + +svc:monitor-kuma->net:monitor + + + + + +svc:monitor-kuma->net:traefik + + + + + +traefik-service:monitor-kuma + + + +service:monitor-kuma + + + +router:monitor->traefik-service:monitor-kuma + + + + + +dns:service-7.<internal-domain>->router:monitor + + + + + +traefik-service:monitor + + + +service:monitor +port:3001 + + + +traefik-service:monitor->svc:monitor-kuma + + + + + +svc:mtls-bridge + +mtls-bridge + + + +svc:mtls-bridge->net:monitor + + + + + +svc:mtls-bridge->net:traefik + + + + + +traefik-service:mtls-bridge + + + +service:mtls-bridge +port:8080 + + + +router:mtls-bridge->traefik-service:mtls-bridge + + + + + +mw:mtls-bridge-auth + +mtls-bridge-auth + + + +router:mtls-bridge->mw:mtls-bridge-auth + + + + + +mw:mtls-bridge-cors + +mtls-bridge-cors + + + +router:mtls-bridge->mw:mtls-bridge-cors + + + + + +traefik-service:mtls-bridge->svc:mtls-bridge + + + + + +dns:service-8.<internal-domain>->router:mtls-bridge + + + + + +dns:service-8.<internal-domain>->router:mtls-bridge-preflight + + + + + +router:mtls-bridge-preflight->traefik-service:mtls-bridge + + + + + +router:mtls-bridge-preflight->mw:mtls-bridge-cors + + + + + +svc:nextcloud-db + +nextcloud-db + + + +svc:nextcloud-db->net:nextcloud + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +svc:nextcloud-redis->net:nextcloud + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +svc:nextcloud-webapp->net:nextcloud + + + + + +svc:nextcloud-webapp->net:traefik + + + + + +traefik-service:nextcloud-webapp + + + +service:nextcloud-webapp + + + +router:nextcloud->traefik-service:nextcloud-webapp + + + + + +mw:nextcloud-dav + +nextcloud-dav + + + +router:nextcloud->mw:nextcloud-dav + + + + + +mw:nextcloud-webfinger + +nextcloud-webfinger + + + +router:nextcloud->mw:nextcloud-webfinger + + + + + +dns:service-9.<internal-domain>->router:nextcloud + + + + + +svc:node-exporter + +node-exporter + + + +svc:node-exporter->net:monitor + + + + + +svc:node-red + +node-red + + + +svc:node-red->net:monitor + + + + + +svc:node-red->net:traefik + + + + + +router:node-red->mw:authelia + + + + + +traefik-service:node-red + + + +service:node-red +port:1880 + + + +router:node-red->traefik-service:node-red + + + + + +traefik-service:node-red->svc:node-red + + + + + +dns:service-10.<internal-domain>->router:node-red + + + + + +svc:passbolt-db + +passbolt-db + + + +svc:passbolt-db->net:passbolt + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +svc:passbolt-webapp->net:passbolt + + + + + +svc:passbolt-webapp->net:traefik + + + + + +traefik-service:passbolt-webapp + + + +service:passbolt-webapp + + + +router:passbolt->traefik-service:passbolt-webapp + + + + + +dns:service-11.<internal-domain>->router:passbolt + + + + + +svc:pihole-exporter + +pihole-exporter + + + +svc:pihole-exporter->net:monitor + + + + + +svc:portainer + +portainer + + + +svc:portainer->net:traefik + + + + + +traefik-service:portainer + + + +service:portainer +port:9000 + + + +router:portainer->traefik-service:portainer + + + + + +traefik-service:portainer->svc:portainer + + + + + +dns:service-12.<internal-domain>->router:portainer + + + + + +svc:prometheus + +prometheus + + + +svc:prometheus->net:monitor + + + + + +svc:prometheus->net:traefik + + + + + +router:prometheus->mw:authelia + + + + + +traefik-service:prometheus + + + +service:prometheus +port:9090 + + + +router:prometheus->traefik-service:prometheus + + + + + +traefik-service:prometheus->svc:prometheus + + + + + +dns:service-13.<internal-domain>->router:prometheus + + + + + +svc:searxng-webapp + +searxng-webapp + + + +svc:searxng-webapp->net:traefik + + + + + +traefik-service:searxng-webapp + + + +service:searxng-webapp + + + +router:searxng->traefik-service:searxng-webapp + + + + + +dns:service-14.<internal-domain>->router:searxng + + + + + +traefik-service:searxng + + + +service:searxng +port:8080 + + + +traefik-service:searxng->svc:searxng-webapp + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +svc:shift-recorder-web->net:traefik + + + + + +traefik-service:shift-recorder-web + + + +service:shift-recorder-web + + + +router:shifts->traefik-service:shift-recorder-web + + + + + +dns:service-15.<internal-domain>->router:shifts + + + + + +traefik-service:shifts + + + +service:shifts +port:80 + + + +traefik-service:shifts->svc:shift-recorder-web + + + + + +svc:stockfill + +stockfill + + + +svc:stockfill->net:traefik + + + + + +traefik-service:stockfill + + + +service:stockfill +port:80 + + + +router:stockfill->traefik-service:stockfill + + + + + +traefik-service:stockfill->svc:stockfill + + + + + +dns:service-16.<internal-domain>->router:stockfill + + + + + +svc:telegraf + +telegraf + + + +svc:telegraf->net:monitor + + + + + +router:traefik->mw:authelia + + + + + +traefik-service:api@internal + + + +service:api@internal + + + +router:traefik->traefik-service:api@internal + + + + + +dns:service-17.<internal-domain>->router:traefik + + + + + diff --git a/docs/diagrams/physical-topology.dot b/docs/diagrams/physical-topology.dot new file mode 100644 index 0000000..476f76b --- /dev/null +++ b/docs/diagrams/physical-topology.dot @@ -0,0 +1,79 @@ +digraph PhysicalTopology { + graph [rankdir=LR, compound=true, splines=ortho, nodesep=0.45, ranksep=0.75, fontname="Helvetica"]; + node [fontname="Helvetica", fontsize=10, style="rounded,filled", fillcolor="#ffffff"]; + edge [fontname="Helvetica", fontsize=9]; + subgraph "cluster_docker" { + label="docker"; + style="rounded,filled"; + color="#c7d6f5"; + fillcolor="#eef3ff"; + "host:docker" [label="docker", shape=box3d, fillcolor="#d4e3ff"]; + "svc:authelia" [label="authelia", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:authelia" [style=dashed, color="#6b7280"]; + "svc:crowdsec" [label="crowdsec", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:crowdsec" [style=dashed, color="#6b7280"]; + "svc:docker-socket-proxy" [label="docker-socket-proxy", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:docker-socket-proxy" [style=dashed, color="#6b7280"]; + "svc:docker-update-exporter" [label="docker-update-exporter", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:docker-update-exporter" [style=dashed, color="#6b7280"]; + "svc:error-pages" [label="error-pages", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:error-pages" [style=dashed, color="#6b7280"]; + "svc:gitea" [label="gitea", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:gitea" [style=dashed, color="#6b7280"]; + "svc:gitea-runner" [label="gitea-runner", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:gitea-runner" [style=dashed, color="#6b7280"]; + "svc:gotify" [label="gotify", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:gotify" [style=dashed, color="#6b7280"]; + "svc:grafana" [label="grafana", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:grafana" [style=dashed, color="#6b7280"]; + "svc:gramps-redis" [label="gramps-redis", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:gramps-redis" [style=dashed, color="#6b7280"]; + "svc:grampsweb" [label="grampsweb", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:grampsweb" [style=dashed, color="#6b7280"]; + "svc:grampsweb_celery" [label="grampsweb_celery", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:grampsweb_celery" [style=dashed, color="#6b7280"]; + "svc:influxdb" [label="influxdb", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:influxdb" [style=dashed, color="#6b7280"]; + "svc:monitor-kuma" [label="monitor-kuma", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:monitor-kuma" [style=dashed, color="#6b7280"]; + "svc:mtls-bridge" [label="mtls-bridge", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:mtls-bridge" [style=dashed, color="#6b7280"]; + "svc:nextcloud-db" [label="nextcloud-db", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:nextcloud-db" [style=dashed, color="#6b7280"]; + "svc:nextcloud-redis" [label="nextcloud-redis", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:nextcloud-redis" [style=dashed, color="#6b7280"]; + "svc:nextcloud-webapp" [label="nextcloud-webapp", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:nextcloud-webapp" [style=dashed, color="#6b7280"]; + "svc:node-exporter" [label="node-exporter", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:node-exporter" [style=dashed, color="#6b7280"]; + "svc:node-red" [label="node-red", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:node-red" [style=dashed, color="#6b7280"]; + "svc:passbolt-db" [label="passbolt-db", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:passbolt-db" [style=dashed, color="#6b7280"]; + "svc:passbolt-webapp" [label="passbolt-webapp", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:passbolt-webapp" [style=dashed, color="#6b7280"]; + "svc:portainer" [label="portainer", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:portainer" [style=dashed, color="#6b7280"]; + "svc:prometheus" [label="prometheus", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:prometheus" [style=dashed, color="#6b7280"]; + "svc:searxng-webapp" [label="searxng-webapp", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:searxng-webapp" [style=dashed, color="#6b7280"]; + "svc:shift-recorder-web" [label="shift-recorder-web", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:shift-recorder-web" [style=dashed, color="#6b7280"]; + "svc:stockfill" [label="stockfill", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:stockfill" [style=dashed, color="#6b7280"]; + "svc:telegraf" [label="telegraf", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:telegraf" [style=dashed, color="#6b7280"]; + "svc:traefik" [label="traefik", shape=box, fillcolor="#dff2e1"]; + "host:docker" -> "svc:traefik" [style=dashed, color="#6b7280"]; + } + subgraph "cluster_raspberrypi" { + label="raspberrypi"; + style="rounded,filled"; + color="#c7d6f5"; + fillcolor="#eef3ff"; + "host:raspberrypi" [label="raspberrypi", shape=box3d, fillcolor="#d4e3ff"]; + "svc:pihole-exporter" [label="pihole-exporter", shape=box, fillcolor="#dff2e1"]; + "host:raspberrypi" -> "svc:pihole-exporter" [style=dashed, color="#6b7280"]; + } +} diff --git a/docs/diagrams/physical-topology.svg b/docs/diagrams/physical-topology.svg new file mode 100644 index 0000000..77daceb --- /dev/null +++ b/docs/diagrams/physical-topology.svg @@ -0,0 +1,401 @@ + + + + + + +PhysicalTopology + + +cluster_docker + +docker + + +cluster_raspberrypi + +raspberrypi + + + +host:docker + + + + +docker + + + +svc:authelia + +authelia + + + +host:docker->svc:authelia + + + + + +svc:crowdsec + +crowdsec + + + +host:docker->svc:crowdsec + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +host:docker->svc:docker-socket-proxy + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +host:docker->svc:docker-update-exporter + + + + + +svc:error-pages + +error-pages + + + +host:docker->svc:error-pages + + + + + +svc:gitea + +gitea + + + +host:docker->svc:gitea + + + + + +svc:gitea-runner + +gitea-runner + + + +host:docker->svc:gitea-runner + + + + + +svc:gotify + +gotify + + + +host:docker->svc:gotify + + + + + +svc:grafana + +grafana + + + +host:docker->svc:grafana + + + + + +svc:gramps-redis + +gramps-redis + + + +host:docker->svc:gramps-redis + + + + + +svc:grampsweb + +grampsweb + + + +host:docker->svc:grampsweb + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +host:docker->svc:grampsweb_celery + + + + + +svc:influxdb + +influxdb + + + +host:docker->svc:influxdb + + + + + +svc:monitor-kuma + +monitor-kuma + + + +host:docker->svc:monitor-kuma + + + + + +svc:mtls-bridge + +mtls-bridge + + + +host:docker->svc:mtls-bridge + + + + + +svc:nextcloud-db + +nextcloud-db + + + +host:docker->svc:nextcloud-db + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +host:docker->svc:nextcloud-redis + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +host:docker->svc:nextcloud-webapp + + + + + +svc:node-exporter + +node-exporter + + + +host:docker->svc:node-exporter + + + + + +svc:node-red + +node-red + + + +host:docker->svc:node-red + + + + + +svc:passbolt-db + +passbolt-db + + + +host:docker->svc:passbolt-db + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +host:docker->svc:passbolt-webapp + + + + + +svc:portainer + +portainer + + + +host:docker->svc:portainer + + + + + +svc:prometheus + +prometheus + + + +host:docker->svc:prometheus + + + + + +svc:searxng-webapp + +searxng-webapp + + + +host:docker->svc:searxng-webapp + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +host:docker->svc:shift-recorder-web + + + + + +svc:stockfill + +stockfill + + + +host:docker->svc:stockfill + + + + + +svc:telegraf + +telegraf + + + +host:docker->svc:telegraf + + + + + +svc:traefik + +traefik + + + +host:docker->svc:traefik + + + + + +host:raspberrypi + + + + +raspberrypi + + + +svc:pihole-exporter + +pihole-exporter + + + +host:raspberrypi->svc:pihole-exporter + + + + + diff --git a/docs/public/diagrams.md b/docs/public/diagrams.md new file mode 100644 index 0000000..334e03b --- /dev/null +++ b/docs/public/diagrams.md @@ -0,0 +1,9 @@ +# Infrastructure diagrams + +## Physical / virtual topology + +![Physical topology](physical-topology.svg) + +## Docker, Traefik and Dynu routing + +![Docker Traefik Dynu](docker-traefik-dynu.svg) diff --git a/docs/public/docker-compose.svg b/docs/public/docker-compose.svg index cd8a7c6..1991277 100644 --- a/docs/public/docker-compose.svg +++ b/docs/public/docker-compose.svg @@ -1 +1,463 @@ -Graphviz dot not found in environment. + + + + + + +Compose + + + +svc:authelia + +authelia + + + +net:traefik + +traefik + + + +svc:authelia->net:traefik + + + + + +svc:crowdsec + +crowdsec + + + +svc:crowdsec->net:traefik + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +net:monitor + +monitor + + + +svc:docker-socket-proxy->net:monitor + + + + + +svc:docker-socket-proxy->net:traefik + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +svc:docker-update-exporter->net:monitor + + + + + +svc:error-pages + +error-pages + + + +svc:error-pages->net:traefik + + + + + +svc:gitea + +gitea + + + +svc:gitea->net:traefik + + + + + +svc:gitea-runner + +gitea-runner + + + +svc:gitea-runner->net:traefik + + + + + +svc:gotify + +gotify + + + +svc:gotify->net:traefik + + + + + +svc:grafana + +grafana + + + +svc:grafana->net:monitor + + + + + +svc:grafana->net:traefik + + + + + +svc:gramps-redis + +gramps-redis + + + +net:gramps + +gramps + + + +svc:gramps-redis->net:gramps + + + + + +svc:grampsweb + +grampsweb + + + +svc:grampsweb->net:gramps + + + + + +svc:grampsweb->net:traefik + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +svc:grampsweb_celery->net:gramps + + + + + +svc:influxdb + +influxdb + + + +svc:influxdb->net:monitor + + + + + +svc:influxdb->net:traefik + + + + + +svc:monitor-kuma + +monitor-kuma + + + +svc:monitor-kuma->net:monitor + + + + + +svc:monitor-kuma->net:traefik + + + + + +svc:mtls-bridge + +mtls-bridge + + + +svc:mtls-bridge->net:monitor + + + + + +svc:mtls-bridge->net:traefik + + + + + +svc:nextcloud-db + +nextcloud-db + + + +net:nextcloud + +nextcloud + + + +svc:nextcloud-db->net:nextcloud + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +svc:nextcloud-redis->net:nextcloud + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +svc:nextcloud-webapp->net:nextcloud + + + + + +svc:nextcloud-webapp->net:traefik + + + + + +svc:node-exporter + +node-exporter + + + +svc:node-exporter->net:monitor + + + + + +svc:node-red + +node-red + + + +svc:node-red->net:monitor + + + + + +svc:node-red->net:traefik + + + + + +svc:passbolt-db + +passbolt-db + + + +net:passbolt + +passbolt + + + +svc:passbolt-db->net:passbolt + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +svc:passbolt-webapp->net:passbolt + + + + + +svc:passbolt-webapp->net:traefik + + + + + +svc:pihole-exporter + +pihole-exporter + + + +svc:pihole-exporter->net:monitor + + + + + +svc:portainer + +portainer + + + +svc:portainer->net:traefik + + + + + +svc:prometheus + +prometheus + + + +svc:prometheus->net:monitor + + + + + +svc:prometheus->net:traefik + + + + + +svc:searxng-webapp + +searxng-webapp + + + +svc:searxng-webapp->net:traefik + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +svc:shift-recorder-web->net:traefik + + + + + +svc:stockfill + +stockfill + + + +svc:stockfill->net:traefik + + + + + +svc:telegraf + +telegraf + + + +svc:telegraf->net:monitor + + + + + +svc:traefik + +traefik + + + +svc:traefik->net:traefik + + + + + diff --git a/docs/public/docker-traefik-dynu.svg b/docs/public/docker-traefik-dynu.svg new file mode 100644 index 0000000..3011e6a --- /dev/null +++ b/docs/public/docker-traefik-dynu.svg @@ -0,0 +1,1560 @@ + + + + + + +DockerTraefikDynu + + + +ext:dynu + +Dynu / Public DNS + + + +dns:service-1.<internal-domain> + + + +service-1.<internal-domain> + + + +ext:dynu->dns:service-1.<internal-domain> + + + + + +dns:service-2.<internal-domain> + + + +service-2.<internal-domain> + + + +ext:dynu->dns:service-2.<internal-domain> + + + + + +dns:service-3.<internal-domain> + + + +service-3.<internal-domain> + + + +ext:dynu->dns:service-3.<internal-domain> + + + + + +dns:service-4.<internal-domain> + + + +service-4.<internal-domain> + + + +ext:dynu->dns:service-4.<internal-domain> + + + + + +dns:service-5.<internal-domain> + + + +service-5.<internal-domain> + + + +ext:dynu->dns:service-5.<internal-domain> + + + + + +dns:service-6.<internal-domain> + + + +service-6.<internal-domain> + + + +ext:dynu->dns:service-6.<internal-domain> + + + + + +dns:service-7.<internal-domain> + + + +service-7.<internal-domain> + + + +ext:dynu->dns:service-7.<internal-domain> + + + + + +dns:service-8.<internal-domain> + + + +service-8.<internal-domain> + + + +ext:dynu->dns:service-8.<internal-domain> + + + + + +ext:dynu->dns:service-8.<internal-domain> + + + + + +dns:service-9.<internal-domain> + + + +service-9.<internal-domain> + + + +ext:dynu->dns:service-9.<internal-domain> + + + + + +dns:service-10.<internal-domain> + + + +service-10.<internal-domain> + + + +ext:dynu->dns:service-10.<internal-domain> + + + + + +dns:service-11.<internal-domain> + + + +service-11.<internal-domain> + + + +ext:dynu->dns:service-11.<internal-domain> + + + + + +dns:service-12.<internal-domain> + + + +service-12.<internal-domain> + + + +ext:dynu->dns:service-12.<internal-domain> + + + + + +dns:service-13.<internal-domain> + + + +service-13.<internal-domain> + + + +ext:dynu->dns:service-13.<internal-domain> + + + + + +dns:service-14.<internal-domain> + + + +service-14.<internal-domain> + + + +ext:dynu->dns:service-14.<internal-domain> + + + + + +dns:service-15.<internal-domain> + + + +service-15.<internal-domain> + + + +ext:dynu->dns:service-15.<internal-domain> + + + + + +dns:service-16.<internal-domain> + + + +service-16.<internal-domain> + + + +ext:dynu->dns:service-16.<internal-domain> + + + + + +dns:service-17.<internal-domain> + + + +service-17.<internal-domain> + + + +ext:dynu->dns:service-17.<internal-domain> + + + + + +svc:traefik + +traefik + + + +net:traefik + +traefik + + + +svc:traefik->net:traefik + + + + + +router:authelia + +router:authelia +entry:websecure tls:true + + + +svc:traefik->router:authelia + + + + + +router:error-pages-router + +router:error-pages-router +entry:web tls:false + + + +svc:traefik->router:error-pages-router + + + + + +router:gitea + +router:gitea +entry:websecure tls:true + + + +svc:traefik->router:gitea + + + + + +router:gotify + +router:gotify +entry:websecure tls:false + + + +svc:traefik->router:gotify + + + + + +router:grafana + +router:grafana +entry:websecure tls:false + + + +svc:traefik->router:grafana + + + + + +router:gramps + +router:gramps +entry:websecure tls:false + + + +svc:traefik->router:gramps + + + + + +router:influxdb + +router:influxdb +entry:websecure tls:false + + + +svc:traefik->router:influxdb + + + + + +router:monitor + +router:monitor +entry:websecure tls:true + + + +svc:traefik->router:monitor + + + + + +router:mtls-bridge + +router:mtls-bridge +entry:websecure tls:false + + + +svc:traefik->router:mtls-bridge + + + + + +router:mtls-bridge-preflight + +router:mtls-bridge-preflight +entry:websecure tls:false + + + +svc:traefik->router:mtls-bridge-preflight + + + + + +router:nextcloud + +router:nextcloud +entry:websecure tls:false + + + +svc:traefik->router:nextcloud + + + + + +router:node-red + +router:node-red +entry:websecure tls:false + + + +svc:traefik->router:node-red + + + + + +router:passbolt + +router:passbolt +entry:websecure tls:false + + + +svc:traefik->router:passbolt + + + + + +router:portainer + +router:portainer +entry:websecure tls:true + + + +svc:traefik->router:portainer + + + + + +router:prometheus + +router:prometheus +entry:websecure tls:false + + + +svc:traefik->router:prometheus + + + + + +router:searxng + +router:searxng +entry:websecure tls:false + + + +svc:traefik->router:searxng + + + + + +router:shifts + +router:shifts +entry:websecure tls:true + + + +svc:traefik->router:shifts + + + + + +router:stockfill + +router:stockfill +entry:websecure tls:true + + + +svc:traefik->router:stockfill + + + + + +router:traefik + +router:traefik +entry:websecure tls:false + + + +svc:traefik->router:traefik + + + + + +net:gramps + +gramps + + + +net:monitor + +monitor + + + +net:nextcloud + +nextcloud + + + +net:passbolt + +passbolt + + + +svc:authelia + +authelia + + + +svc:authelia->net:traefik + + + + + +traefik-service:authelia + + + +service:authelia + + + +router:authelia->traefik-service:authelia + + + + + +dns:service-1.<internal-domain>->router:authelia + + + + + +svc:crowdsec + +crowdsec + + + +svc:crowdsec->net:traefik + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +svc:docker-socket-proxy->net:monitor + + + + + +svc:docker-socket-proxy->net:traefik + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +svc:docker-update-exporter->net:monitor + + + + + +svc:error-pages + +error-pages + + + +svc:error-pages->net:traefik + + + + + +traefik-service:error-pages + + + +service:error-pages + + + +router:error-pages-router->traefik-service:error-pages + + + + + +mw:error-pages-middleware + +error-pages-middleware + + + +router:error-pages-router->mw:error-pages-middleware + + + + + +traefik-service:error-pages-service + + + +service:error-pages-service +port:8080 + + + +traefik-service:error-pages-service->svc:error-pages + + + + + +svc:gitea + +gitea + + + +svc:gitea->net:traefik + + + + + +traefik-service:gitea + + + +service:gitea +port:3000 + + + +router:gitea->traefik-service:gitea + + + + + +traefik-service:gitea->svc:gitea + + + + + +dns:service-2.<internal-domain>->router:gitea + + + + + +svc:gitea-runner + +gitea-runner + + + +svc:gitea-runner->net:traefik + + + + + +svc:gotify + +gotify + + + +svc:gotify->net:traefik + + + + + +traefik-service:gotify + + + +service:gotify +port:80 + + + +router:gotify->traefik-service:gotify + + + + + +traefik-service:gotify->svc:gotify + + + + + +dns:service-3.<internal-domain>->router:gotify + + + + + +svc:grafana + +grafana + + + +svc:grafana->net:monitor + + + + + +svc:grafana->net:traefik + + + + + +traefik-service:grafana + + + +service:grafana +port:3000 + + + +router:grafana->traefik-service:grafana + + + + + +traefik-service:grafana->svc:grafana + + + + + +dns:service-4.<internal-domain>->router:grafana + + + + + +svc:gramps-redis + +gramps-redis + + + +svc:gramps-redis->net:gramps + + + + + +svc:grampsweb + +grampsweb + + + +svc:grampsweb->net:gramps + + + + + +svc:grampsweb->net:traefik + + + + + +traefik-service:grampsweb + + + +service:grampsweb + + + +router:gramps->traefik-service:grampsweb + + + + + +dns:service-5.<internal-domain>->router:gramps + + + + + +traefik-service:gramps + + + +service:gramps +port:5000 + + + +traefik-service:gramps->svc:grampsweb + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +svc:grampsweb_celery->net:gramps + + + + + +svc:influxdb + +influxdb + + + +svc:influxdb->net:monitor + + + + + +svc:influxdb->net:traefik + + + + + +traefik-service:influxdb + + + +service:influxdb +port:8086 + + + +router:influxdb->traefik-service:influxdb + + + + + +mw:authelia + +authelia + + + +router:influxdb->mw:authelia + + + + + +traefik-service:influxdb->svc:influxdb + + + + + +dns:service-6.<internal-domain>->router:influxdb + + + + + +svc:monitor-kuma + +monitor-kuma + + + +svc:monitor-kuma->net:monitor + + + + + +svc:monitor-kuma->net:traefik + + + + + +traefik-service:monitor-kuma + + + +service:monitor-kuma + + + +router:monitor->traefik-service:monitor-kuma + + + + + +dns:service-7.<internal-domain>->router:monitor + + + + + +traefik-service:monitor + + + +service:monitor +port:3001 + + + +traefik-service:monitor->svc:monitor-kuma + + + + + +svc:mtls-bridge + +mtls-bridge + + + +svc:mtls-bridge->net:monitor + + + + + +svc:mtls-bridge->net:traefik + + + + + +traefik-service:mtls-bridge + + + +service:mtls-bridge +port:8080 + + + +router:mtls-bridge->traefik-service:mtls-bridge + + + + + +mw:mtls-bridge-auth + +mtls-bridge-auth + + + +router:mtls-bridge->mw:mtls-bridge-auth + + + + + +mw:mtls-bridge-cors + +mtls-bridge-cors + + + +router:mtls-bridge->mw:mtls-bridge-cors + + + + + +traefik-service:mtls-bridge->svc:mtls-bridge + + + + + +dns:service-8.<internal-domain>->router:mtls-bridge + + + + + +dns:service-8.<internal-domain>->router:mtls-bridge-preflight + + + + + +router:mtls-bridge-preflight->traefik-service:mtls-bridge + + + + + +router:mtls-bridge-preflight->mw:mtls-bridge-cors + + + + + +svc:nextcloud-db + +nextcloud-db + + + +svc:nextcloud-db->net:nextcloud + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +svc:nextcloud-redis->net:nextcloud + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +svc:nextcloud-webapp->net:nextcloud + + + + + +svc:nextcloud-webapp->net:traefik + + + + + +traefik-service:nextcloud-webapp + + + +service:nextcloud-webapp + + + +router:nextcloud->traefik-service:nextcloud-webapp + + + + + +mw:nextcloud-dav + +nextcloud-dav + + + +router:nextcloud->mw:nextcloud-dav + + + + + +mw:nextcloud-webfinger + +nextcloud-webfinger + + + +router:nextcloud->mw:nextcloud-webfinger + + + + + +dns:service-9.<internal-domain>->router:nextcloud + + + + + +svc:node-exporter + +node-exporter + + + +svc:node-exporter->net:monitor + + + + + +svc:node-red + +node-red + + + +svc:node-red->net:monitor + + + + + +svc:node-red->net:traefik + + + + + +router:node-red->mw:authelia + + + + + +traefik-service:node-red + + + +service:node-red +port:1880 + + + +router:node-red->traefik-service:node-red + + + + + +traefik-service:node-red->svc:node-red + + + + + +dns:service-10.<internal-domain>->router:node-red + + + + + +svc:passbolt-db + +passbolt-db + + + +svc:passbolt-db->net:passbolt + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +svc:passbolt-webapp->net:passbolt + + + + + +svc:passbolt-webapp->net:traefik + + + + + +traefik-service:passbolt-webapp + + + +service:passbolt-webapp + + + +router:passbolt->traefik-service:passbolt-webapp + + + + + +dns:service-11.<internal-domain>->router:passbolt + + + + + +svc:pihole-exporter + +pihole-exporter + + + +svc:pihole-exporter->net:monitor + + + + + +svc:portainer + +portainer + + + +svc:portainer->net:traefik + + + + + +traefik-service:portainer + + + +service:portainer +port:9000 + + + +router:portainer->traefik-service:portainer + + + + + +traefik-service:portainer->svc:portainer + + + + + +dns:service-12.<internal-domain>->router:portainer + + + + + +svc:prometheus + +prometheus + + + +svc:prometheus->net:monitor + + + + + +svc:prometheus->net:traefik + + + + + +router:prometheus->mw:authelia + + + + + +traefik-service:prometheus + + + +service:prometheus +port:9090 + + + +router:prometheus->traefik-service:prometheus + + + + + +traefik-service:prometheus->svc:prometheus + + + + + +dns:service-13.<internal-domain>->router:prometheus + + + + + +svc:searxng-webapp + +searxng-webapp + + + +svc:searxng-webapp->net:traefik + + + + + +traefik-service:searxng-webapp + + + +service:searxng-webapp + + + +router:searxng->traefik-service:searxng-webapp + + + + + +dns:service-14.<internal-domain>->router:searxng + + + + + +traefik-service:searxng + + + +service:searxng +port:8080 + + + +traefik-service:searxng->svc:searxng-webapp + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +svc:shift-recorder-web->net:traefik + + + + + +traefik-service:shift-recorder-web + + + +service:shift-recorder-web + + + +router:shifts->traefik-service:shift-recorder-web + + + + + +dns:service-15.<internal-domain>->router:shifts + + + + + +traefik-service:shifts + + + +service:shifts +port:80 + + + +traefik-service:shifts->svc:shift-recorder-web + + + + + +svc:stockfill + +stockfill + + + +svc:stockfill->net:traefik + + + + + +traefik-service:stockfill + + + +service:stockfill +port:80 + + + +router:stockfill->traefik-service:stockfill + + + + + +traefik-service:stockfill->svc:stockfill + + + + + +dns:service-16.<internal-domain>->router:stockfill + + + + + +svc:telegraf + +telegraf + + + +svc:telegraf->net:monitor + + + + + +router:traefik->mw:authelia + + + + + +traefik-service:api@internal + + + +service:api@internal + + + +router:traefik->traefik-service:api@internal + + + + + +dns:service-17.<internal-domain>->router:traefik + + + + + diff --git a/docs/public/index.md b/docs/public/index.md index f600c19..9d57d8e 100644 --- a/docs/public/index.md +++ b/docs/public/index.md @@ -1,12 +1,20 @@ # Public Infrastructure Summary -This folder contains sanitized documentation generated from the infrastructure repository. +This documentation is generated from the infrastructure repository. Sensitive values are redacted. -Sensitive values such as internal domain names, private IP addresses, tokens, passwords, and secrets are redacted. +## Infrastructure diagrams + +### Physical / virtual topology + +![Physical topology](physical-topology.svg) + +### Docker, Traefik and Dynu routing + +![Docker Traefik Dynu](docker-traefik-dynu.svg) ## Documents +- [Diagrams](diagrams.md) - [Compose Inventory](compose-inventory.md) - [Traefik Routes](traefik-routes.md) - [Prometheus Rules](prometheus-rules.md) -- [Docker Compose Diagram](docker-compose.svg) diff --git a/docs/public/physical-topology.svg b/docs/public/physical-topology.svg new file mode 100644 index 0000000..77daceb --- /dev/null +++ b/docs/public/physical-topology.svg @@ -0,0 +1,401 @@ + + + + + + +PhysicalTopology + + +cluster_docker + +docker + + +cluster_raspberrypi + +raspberrypi + + + +host:docker + + + + +docker + + + +svc:authelia + +authelia + + + +host:docker->svc:authelia + + + + + +svc:crowdsec + +crowdsec + + + +host:docker->svc:crowdsec + + + + + +svc:docker-socket-proxy + +docker-socket-proxy + + + +host:docker->svc:docker-socket-proxy + + + + + +svc:docker-update-exporter + +docker-update-exporter + + + +host:docker->svc:docker-update-exporter + + + + + +svc:error-pages + +error-pages + + + +host:docker->svc:error-pages + + + + + +svc:gitea + +gitea + + + +host:docker->svc:gitea + + + + + +svc:gitea-runner + +gitea-runner + + + +host:docker->svc:gitea-runner + + + + + +svc:gotify + +gotify + + + +host:docker->svc:gotify + + + + + +svc:grafana + +grafana + + + +host:docker->svc:grafana + + + + + +svc:gramps-redis + +gramps-redis + + + +host:docker->svc:gramps-redis + + + + + +svc:grampsweb + +grampsweb + + + +host:docker->svc:grampsweb + + + + + +svc:grampsweb_celery + +grampsweb_celery + + + +host:docker->svc:grampsweb_celery + + + + + +svc:influxdb + +influxdb + + + +host:docker->svc:influxdb + + + + + +svc:monitor-kuma + +monitor-kuma + + + +host:docker->svc:monitor-kuma + + + + + +svc:mtls-bridge + +mtls-bridge + + + +host:docker->svc:mtls-bridge + + + + + +svc:nextcloud-db + +nextcloud-db + + + +host:docker->svc:nextcloud-db + + + + + +svc:nextcloud-redis + +nextcloud-redis + + + +host:docker->svc:nextcloud-redis + + + + + +svc:nextcloud-webapp + +nextcloud-webapp + + + +host:docker->svc:nextcloud-webapp + + + + + +svc:node-exporter + +node-exporter + + + +host:docker->svc:node-exporter + + + + + +svc:node-red + +node-red + + + +host:docker->svc:node-red + + + + + +svc:passbolt-db + +passbolt-db + + + +host:docker->svc:passbolt-db + + + + + +svc:passbolt-webapp + +passbolt-webapp + + + +host:docker->svc:passbolt-webapp + + + + + +svc:portainer + +portainer + + + +host:docker->svc:portainer + + + + + +svc:prometheus + +prometheus + + + +host:docker->svc:prometheus + + + + + +svc:searxng-webapp + +searxng-webapp + + + +host:docker->svc:searxng-webapp + + + + + +svc:shift-recorder-web + +shift-recorder-web + + + +host:docker->svc:shift-recorder-web + + + + + +svc:stockfill + +stockfill + + + +host:docker->svc:stockfill + + + + + +svc:telegraf + +telegraf + + + +host:docker->svc:telegraf + + + + + +svc:traefik + +traefik + + + +host:docker->svc:traefik + + + + + +host:raspberrypi + + + + +raspberrypi + + + +svc:pihole-exporter + +pihole-exporter + + + +host:raspberrypi->svc:pihole-exporter + + + + + diff --git a/mkdocs-public.yml b/mkdocs-public.yml index 9315745..77a2e2e 100644 --- a/mkdocs-public.yml +++ b/mkdocs-public.yml @@ -7,6 +7,7 @@ site_dir: site-public nav: - Home: index.md + - Diagrams: diagrams.md - Compose Inventory: compose-inventory.md - Traefik Routes: traefik-routes.md - Prometheus Rules: prometheus-rules.md diff --git a/scripts/docs/generate-all.sh b/scripts/docs/generate-all.sh index 7690e59..65806ee 100755 --- a/scripts/docs/generate-all.sh +++ b/scripts/docs/generate-all.sh @@ -8,5 +8,5 @@ python3 scripts/docs/generate-compose-inventory.py docs/generated/docker-compose python3 scripts/docs/generate-traefik-routes.py docs/generated/docker-compose.resolved.yml docs/generated/traefik-routes.md python3 scripts/docs/generate-prometheus-rules.py docs/generated/prometheus-rules.md python3 scripts/docs/generate-docs-index.py docs/generated/index.md -python3 scripts/docs/generate-diagrams.py docs/generated/docker-compose.resolved.yml docs/diagrams/docker-compose.dot docs/diagrams/docker-compose.svg +python3 scripts/docs/generate-diagrams.py --compose docs/generated/docker-compose.resolved.yml --out-dir docs/diagrams python3 scripts/docs/sanitize-public-docs.py docs/generated docs/diagrams docs/public diff --git a/scripts/docs/generate-diagrams.py b/scripts/docs/generate-diagrams.py index d1690d9..7945c71 100644 --- a/scripts/docs/generate-diagrams.py +++ b/scripts/docs/generate-diagrams.py @@ -1,18 +1,231 @@ #!/usr/bin/env python3 -import sys,yaml,subprocess,shutil -inp,dotf,svgf=sys.argv[1],sys.argv[2],sys.argv[3] -with open(inp) as f:c=yaml.safe_load(f) or {} -svcs=c.get('services') or {} -lines=["digraph Compose {"," rankdir=LR;"," node [fontname=Helvetica];"] -for s in svcs: lines.append(f' "svc:{s}" [label="{s}", shape=box, style=filled, fillcolor="#dfefff"];') -for n in (c.get('networks') or {}).keys(): lines.append(f' "net:{n}" [label="{n}", shape=ellipse, style=filled, fillcolor="#f4f4f4"];') -for s,sv in svcs.items(): - ns=sv.get('networks') or [] - if isinstance(ns,dict): ns=ns.keys() - for n in ns: lines.append(f' "svc:{s}" -> "net:{n}";') -lines.append("}") -open(dotf,'w').write('\n'.join(lines)+'\n') -if shutil.which('dot'): - subprocess.run(['dot','-Tsvg',dotf,'-o',svgf],check=True) -else: - open(svgf,'w').write('Graphviz dot not found in environment.\n') +import argparse +import re +import subprocess +import shutil +from pathlib import Path +import yaml + +INTERNAL_DOMAIN_RE = re.compile(r"\b[a-zA-Z0-9.-]+\.lan\.ddnsgeek\.com\b") +HOST_MATCH_RE = re.compile(r"Host\(([^)]*)\)") +TICKED_HOST_RE = re.compile(r"`([^`]+)`") + + +def require_dot() -> None: + if not shutil.which("dot"): + raise SystemExit( + "Graphviz 'dot' not found in environment. Install graphviz before running docs generation." + ) + + +def load_compose(path: Path) -> dict: + with path.open() as handle: + return yaml.safe_load(handle) or {} + + +def sanitize_domain(value: str, known: dict[str, str]) -> str: + if value in known: + return known[value] + if INTERNAL_DOMAIN_RE.search(value): + mapped = f"service-{len(known)+1}." + known[value] = mapped + return mapped + return value + + +def parse_labels(service: dict) -> dict[str, str]: + labels = service.get("labels") or {} + if isinstance(labels, list): + mapped = {} + for item in labels: + if "=" in str(item): + k, v = str(item).split("=", 1) + mapped[k] = v + return mapped + if isinstance(labels, dict): + return {str(k): str(v) for k, v in labels.items()} + return {} + + +def extract_hosts(rule: str) -> list[str]: + hosts: list[str] = [] + for m in HOST_MATCH_RE.findall(rule or ""): + for host in TICKED_HOST_RE.findall(m): + hosts.append(host.strip()) + return hosts + + +def render_svg(dot_path: Path, svg_path: Path) -> None: + subprocess.run(["dot", "-Tsvg", str(dot_path), "-o", str(svg_path)], check=True) + + +def write_dot(path: Path, lines: list[str]) -> None: + path.write_text("\n".join(lines) + "\n") + + +def infer_host(service_name: str, service: dict) -> str: + labels = parse_labels(service) + for key in ("com.docker.compose.project", "infra.host", "host"): + value = labels.get(key) + if value: + return value.lower() + s = service_name.lower() + if "raspi" in s or "pi" in s: + return "raspberrypi" + if "proxmox" in s: + return "proxmox" + return "docker" + + +def generate_physical_topology(compose: dict, out_dot: Path, out_svg: Path) -> None: + services = compose.get("services") or {} + hosts: dict[str, list[str]] = {} + for name, svc in services.items(): + hosts.setdefault(infer_host(name, svc), []).append(name) + + lines = [ + "digraph PhysicalTopology {", + " graph [rankdir=LR, compound=true, splines=ortho, nodesep=0.45, ranksep=0.75, fontname=\"Helvetica\"];", + " node [fontname=\"Helvetica\", fontsize=10, style=\"rounded,filled\", fillcolor=\"#ffffff\"];", + " edge [fontname=\"Helvetica\", fontsize=9];", + ] + + for host, host_services in sorted(hosts.items()): + lines.extend( + [ + f' subgraph "cluster_{host}" {{', + f' label="{host}";', + ' style="rounded,filled";', + ' color="#c7d6f5";', + ' fillcolor="#eef3ff";', + f' "host:{host}" [label="{host}", shape=box3d, fillcolor="#d4e3ff"];', + ] + ) + for service in sorted(host_services): + lines.append( + f' "svc:{service}" [label="{service}", shape=box, fillcolor="#dff2e1"];' + ) + lines.append(f' "host:{host}" -> "svc:{service}" [style=dashed, color="#6b7280"];') + lines.append(" }") + + lines.append("}") + write_dot(out_dot, lines) + render_svg(out_dot, out_svg) + + +def generate_docker_traefik_dynu(compose: dict, out_dot: Path, out_svg: Path) -> None: + services = compose.get("services") or {} + networks = compose.get("networks") or {} + known_domains: dict[str, str] = {} + + lines = [ + "digraph DockerTraefikDynu {", + " graph [rankdir=LR, compound=true, splines=true, nodesep=0.5, ranksep=1.0, fontname=\"Helvetica\"];", + " node [fontname=\"Helvetica\", fontsize=10, style=\"rounded,filled\"];", + " edge [fontname=\"Helvetica\", fontsize=9];", + ' "ext:dynu" [label="Dynu / Public DNS", shape=oval, fillcolor="#fde68a"];', + ' "svc:traefik" [label="traefik", shape=box, fillcolor="#bfdbfe"];', + ] + + for net in sorted(networks.keys()): + lines.append(f' "net:{net}" [label="{net}", shape=ellipse, fillcolor="#f3f4f6"];') + + for svc_name, svc in sorted(services.items()): + lines.append(f' "svc:{svc_name}" [label="{svc_name}", shape=box, fillcolor="#dcfce7"];') + svc_nets = svc.get("networks") or [] + if isinstance(svc_nets, dict): + svc_nets = svc_nets.keys() + for net in svc_nets: + lines.append(f' "svc:{svc_name}" -> "net:{net}" [color="#6b7280"];') + + labels = parse_labels(svc) + router_prefix = "traefik.http.routers." + service_prefix = "traefik.http.services." + + routers = sorted({k[len(router_prefix):].split(".", 1)[0] for k in labels if k.startswith(router_prefix)}) + for router in routers: + rule = labels.get(f"{router_prefix}{router}.rule", "") + router_service = labels.get(f"{router_prefix}{router}.service", svc_name) + middlewares = labels.get(f"{router_prefix}{router}.middlewares", "") + entrypoints = labels.get(f"{router_prefix}{router}.entrypoints", "") + tls = labels.get(f"{router_prefix}{router}.tls", "false") + lines.append(f' "router:{router}" [label="router:{router}\\nentry:{entrypoints} tls:{tls}", shape=diamond, fillcolor="#fbcfe8"];') + lines.append(f' "svc:traefik" -> "router:{router}";') + target_node = f"traefik-service:{router_service}" + lines.append(f' "{target_node}" [label="service:{router_service}", shape=component, fillcolor="#fecaca"];') + lines.append(f' "router:{router}" -> "{target_node}";') + + for host in extract_hosts(rule): + clean = sanitize_domain(host, known_domains) + lines.append(f' "dns:{clean}" [label="{clean}", shape=note, fillcolor="#fde68a"];') + lines.append(f' "ext:dynu" -> "dns:{clean}";') + lines.append(f' "dns:{clean}" -> "router:{router}";') + + for middleware in [m.strip() for m in middlewares.split(",") if m.strip()]: + lines.append(f' "mw:{middleware}" [label="{middleware}", shape=hexagon, fillcolor="#ddd6fe"];') + lines.append(f' "router:{router}" -> "mw:{middleware}" [style=dashed];') + + lb_services = sorted({k[len(service_prefix):].split(".", 1)[0] for k in labels if k.startswith(service_prefix)}) + for lb in lb_services: + port = labels.get(f"{service_prefix}{lb}.loadbalancer.server.port", "") + lines.append(f' "traefik-service:{lb}" [label="service:{lb}\\nport:{port}", shape=component, fillcolor="#fecaca"];') + lines.append(f' "traefik-service:{lb}" -> "svc:{svc_name}";') + + lines.append("}") + write_dot(out_dot, lines) + render_svg(out_dot, out_svg) + + +def generate_compose_topology(compose: dict, out_dot: Path, out_svg: Path) -> None: + services = compose.get("services") or {} + networks = compose.get("networks") or {} + lines = [ + "digraph Compose {", + " rankdir=LR;", + ' node [fontname="Helvetica"];', + ] + for service in sorted(services): + lines.append(f' "svc:{service}" [label="{service}", shape=box, style=filled, fillcolor="#dfefff"];') + for net in sorted(networks): + lines.append(f' "net:{net}" [label="{net}", shape=ellipse, style=filled, fillcolor="#f4f4f4"];') + + for service, svc in sorted(services.items()): + svc_nets = svc.get("networks") or [] + if isinstance(svc_nets, dict): + svc_nets = svc_nets.keys() + for net in svc_nets: + lines.append(f' "svc:{service}" -> "net:{net}";') + + lines.append("}") + write_dot(out_dot, lines) + render_svg(out_dot, out_svg) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("legacy", nargs="*") + parser.add_argument("--compose") + parser.add_argument("--out-dir") + args = parser.parse_args() + + require_dot() + + if args.compose and args.out_dir: + compose_path = Path(args.compose) + out_dir = Path(args.out_dir) + elif len(args.legacy) == 3: + compose_path = Path(args.legacy[0]) + out_dir = Path(args.legacy[1]).parent + else: + raise SystemExit("Usage: generate-diagrams.py --compose --out-dir ") + + out_dir.mkdir(parents=True, exist_ok=True) + compose = load_compose(compose_path) + + generate_docker_traefik_dynu(compose, out_dir / "docker-traefik-dynu.dot", out_dir / "docker-traefik-dynu.svg") + generate_physical_topology(compose, out_dir / "physical-topology.dot", out_dir / "physical-topology.svg") + generate_compose_topology(compose, out_dir / "docker-compose.dot", out_dir / "docker-compose.svg") + + +if __name__ == "__main__": + main() diff --git a/scripts/docs/sanitize-public-docs.py b/scripts/docs/sanitize-public-docs.py index 78012cb..4a1a6e2 100644 --- a/scripts/docs/sanitize-public-docs.py +++ b/scripts/docs/sanitize-public-docs.py @@ -20,27 +20,50 @@ def sanitize_text(content: str) -> str: content = re.sub(r'(?m)^([A-Z0-9_]*(?:PASSWORD|TOKEN|API_KEY|SECRET)[A-Z0-9_]*)\s*[:=]\s*.*$', r'\1=', content) return content + for name in ['compose-inventory.md', 'traefik-routes.md', 'prometheus-rules.md']: src = src_generated / name if src.exists(): (out_dir / name).write_text(sanitize_text(src.read_text(errors='ignore'))) -svg_src = src_diagrams / 'docker-compose.svg' -if svg_src.exists(): - (out_dir / 'docker-compose.svg').write_text(sanitize_text(svg_src.read_text(errors='ignore'))) +for svg_name in ['docker-compose.svg', 'physical-topology.svg', 'docker-traefik-dynu.svg']: + src = src_diagrams / svg_name + if src.exists(): + (out_dir / svg_name).write_text(sanitize_text(src.read_text(errors='ignore'))) (out_dir / 'index.md').write_text( """# Public Infrastructure Summary -This folder contains sanitized documentation generated from the infrastructure repository. +This documentation is generated from the infrastructure repository. Sensitive values are redacted. -Sensitive values such as internal domain names, private IP addresses, tokens, passwords, and secrets are redacted. +## Infrastructure diagrams + +### Physical / virtual topology + +![Physical topology](physical-topology.svg) + +### Docker, Traefik and Dynu routing + +![Docker Traefik Dynu](docker-traefik-dynu.svg) ## Documents +- [Diagrams](diagrams.md) - [Compose Inventory](compose-inventory.md) - [Traefik Routes](traefik-routes.md) - [Prometheus Rules](prometheus-rules.md) -- [Docker Compose Diagram](docker-compose.svg) +""" +) + +(out_dir / 'diagrams.md').write_text( + """# Infrastructure diagrams + +## Physical / virtual topology + +![Physical topology](physical-topology.svg) + +## Docker, Traefik and Dynu routing + +![Docker Traefik Dynu](docker-traefik-dynu.svg) """ )