Compare commits
76 Commits
bd23339edd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c89b8129ec | |||
| c98b2d8232 | |||
| 3a9b3786c5 | |||
| 1131eceb94 | |||
| 586be50567 | |||
| d0e08b8fc1 | |||
| 487117b31a | |||
| 82fa90d843 | |||
| ef1e7432ee | |||
| 427ea20e43 | |||
| 3298219ccf | |||
| b30c7f3a8a | |||
| 374511c123 | |||
| 313f7f1c21 | |||
| 6aa78525c2 | |||
| 5e0de23ff7 | |||
| 3c655dabcf | |||
| 60e59f95a8 | |||
| cdf37fb2c9 | |||
| f56b734cb4 | |||
| 10c4373c0e | |||
| 2619d86dc1 | |||
| 1b679a4f09 | |||
| 02033cd3f9 | |||
| d932bc57d0 | |||
| c4cfa8081f | |||
| 90c9094a6f | |||
| 36c5f2b1e3 | |||
| 7bc2729ef6 | |||
| 9d79f828e4 | |||
| 22b3659cdf | |||
| 4440fddb2b | |||
| d74000fbd0 | |||
| 9efdb5c781 | |||
| e7fd52616d | |||
| b7b4b4d36d | |||
| 40f5a3ce0d | |||
| 8e43118661 | |||
| 0e76f3cef1 | |||
| 8d18ab7059 | |||
| 6a959d85c3 | |||
| 79c583eca3 | |||
| 7fcafed3f9 | |||
| 0b67830d7f | |||
| d878a0f9b8 | |||
| 9c38910a67 | |||
| 4a38a9421d | |||
| 5d32693925 | |||
| 696cecfecb | |||
| c0360a14b9 | |||
| 5589594d2c | |||
| 0bd41b2fb1 | |||
| 5f10d0366e | |||
| 9f98101c5d | |||
| 0c20676590 | |||
| 59e2c2b9a3 | |||
| 61d49e85a3 | |||
| 8f84ed6d83 | |||
| 24cbb02bff | |||
| 685a472572 | |||
| 9de1bee542 | |||
| 306e2c14db | |||
| 63b47b59b5 | |||
| 52bd2d9fa2 | |||
| 034ad17cf9 | |||
| ef2846562b | |||
| 52e2102f93 | |||
| a9b21912db | |||
| c9e4aeb8d6 | |||
| 96a44d5da6 | |||
| 0d936677e5 | |||
| 5c38b92bc8 | |||
| fc5c882193 | |||
| a4501d4034 | |||
| c0958d8f02 | |||
| 2a97864a06 |
@@ -0,0 +1,71 @@
|
|||||||
|
name: Generate Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 */6 * * *"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: tcp://docker-socket-proxy:2375
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install docker CLI
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y docker.io docker-compose
|
||||||
|
|
||||||
|
- name: Generate docs
|
||||||
|
run: |
|
||||||
|
scripts/docs/generate-all.sh
|
||||||
|
|
||||||
|
- name: Validate generated docs
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
test -s docs/generated/docker-compose.resolved.yml
|
||||||
|
test -s docs/generated/host-topology.md
|
||||||
|
test -s docs/public/physical-topology.svg
|
||||||
|
test -s docs/public/docker-traefik-dynu.svg
|
||||||
|
|
||||||
|
! grep -R "Host inventory JSON not found" docs/public docs/diagrams
|
||||||
|
! grep -R "Generate terraform inventory" docs/public docs/diagrams
|
||||||
|
|
||||||
|
# Ensure no obvious secrets leaked
|
||||||
|
! grep -R -E -i "password|token|api[_-]?key|secret" docs/public \
|
||||||
|
|| (echo "Secret-like string detected"; exit 1)
|
||||||
|
|
||||||
|
- name: Commit changes
|
||||||
|
run: |
|
||||||
|
git config user.name "docs-bot"
|
||||||
|
git config user.email "docs-bot@local"
|
||||||
|
|
||||||
|
git add docs/generated docs/diagrams docs/public data/terraform/proxmox-inventory.json || true
|
||||||
|
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "No changes to commit"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git commit -m "docs: regenerate documentation artifacts"
|
||||||
|
|
||||||
|
- name: Push to Gitea
|
||||||
|
run: |
|
||||||
|
git push origin HEAD:main
|
||||||
|
|
||||||
|
- name: Push to GitHub mirror
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_PUSH_TOKEN }}
|
||||||
|
GITHUB_MIRROR_REPO: ${{ vars.GITHUB_MIRROR_REPO }}
|
||||||
|
run: |
|
||||||
|
test -n "$GITHUB_TOKEN"
|
||||||
|
test -n "$GITHUB_MIRROR_REPO"
|
||||||
|
git remote add github "https://$GITHUB_TOKEN@github.com/$GITHUB_MIRROR_REPO.git" || true
|
||||||
|
git push github HEAD:main
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
name: Validate Docs (Gitea)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- "docs/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate docs
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
test -d docs/public
|
||||||
|
test -s docs/public/physical-topology.svg
|
||||||
|
|
||||||
|
! grep -R "Host inventory JSON not found" docs/public
|
||||||
|
! grep -R "Generate terraform inventory" docs/public
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: Validate committed public docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-public-docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Ensure committed docs/public exists
|
||||||
|
run: |
|
||||||
|
test -d docs/public
|
||||||
|
test -n "$(find docs/public -mindepth 1 -print -quit)"
|
||||||
|
- name: Install MkDocs
|
||||||
|
run: |
|
||||||
|
python3 -m pip install --user mkdocs
|
||||||
|
- name: Validate docs content
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
test -s docs/public/physical-topology.svg
|
||||||
|
test -s docs/public/docker-traefik-dynu.svg
|
||||||
|
! grep -R "Host inventory JSON not found" docs/public
|
||||||
|
! grep -R "Generate terraform inventory" docs/public
|
||||||
|
! rg -n -i "password|token|api[_-]?key|secret" docs/public
|
||||||
|
- name: Build MkDocs site
|
||||||
|
run: |
|
||||||
|
python3 -m mkdocs build -f mkdocs-public.yml --strict
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
name: Publish documentation site
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: github-pages
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Ensure committed docs/public exists
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
run: |
|
||||||
|
test -d site-public
|
||||||
|
test ! -e site-public/generated
|
||||||
|
test ! -e site-public/docker
|
||||||
|
|
||||||
|
- name: Verify expected 404-only paths are not generated
|
||||||
|
run: |
|
||||||
|
test ! -e site-public/generated/compose-inventory/index.html
|
||||||
|
test ! -e site-public/generated/prometheus-rules/index.html
|
||||||
|
test ! -e site-public/docker/index.html
|
||||||
|
|
||||||
|
- name: Configure GitHub Pages
|
||||||
|
uses: actions/configure-pages@v5
|
||||||
|
|
||||||
|
- name: Upload GitHub Pages artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: site-public
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
+23
@@ -4,6 +4,7 @@
|
|||||||
#!**/Dockerfile
|
#!**/Dockerfile
|
||||||
#!docker-compose.yml
|
#!docker-compose.yml
|
||||||
**/data/
|
**/data/
|
||||||
|
apps/gitea/runner-data/
|
||||||
**/db/
|
**/db/
|
||||||
**/database/
|
**/database/
|
||||||
apps/nextcloud/config/
|
apps/nextcloud/config/
|
||||||
@@ -28,3 +29,25 @@ secrets/*
|
|||||||
!.env.example
|
!.env.example
|
||||||
core/traefik/certs/*
|
core/traefik/certs/*
|
||||||
!core/traefik/certs/.gitkeep
|
!core/traefik/certs/.gitkeep
|
||||||
|
site/
|
||||||
|
|
||||||
|
# Docs generation artifacts intentionally tracked
|
||||||
|
!data/terraform/proxmox-inventory.json
|
||||||
|
!infrastructure/terraform/dynu/generated/
|
||||||
|
!infrastructure/terraform/dynu/generated/dynu_dns_records_inventory.json
|
||||||
|
!docs/generated/
|
||||||
|
!docs/generated/docker-compose.resolved.yml
|
||||||
|
!docs/generated/host-topology.md
|
||||||
|
!docs/diagrams/
|
||||||
|
!docs/diagrams/*.svg
|
||||||
|
!docs/public/
|
||||||
|
!docs/public/*.md
|
||||||
|
!docs/public/*.svg
|
||||||
|
|
||||||
|
# Terraform local/state artifacts
|
||||||
|
**/.terraform/
|
||||||
|
**/.terraform.lock.hcl
|
||||||
|
*.tfstate
|
||||||
|
*.tfstate.*
|
||||||
|
*.tfvars
|
||||||
|
*.tfvars.json
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ If you only read one section, read **[Source-of-truth boundaries](docs/source-of
|
|||||||
- Terraform workflows (brownfield import/reconciliation): [docs/terraform-workflows.md](docs/terraform-workflows.md)
|
- Terraform workflows (brownfield import/reconciliation): [docs/terraform-workflows.md](docs/terraform-workflows.md)
|
||||||
- Infrastructure inventory intent and outputs: [docs/infrastructure-inventory.md](docs/infrastructure-inventory.md)
|
- Infrastructure inventory intent and outputs: [docs/infrastructure-inventory.md](docs/infrastructure-inventory.md)
|
||||||
- Dynu DNS read-only inventory workflow: [docs/dynu-dns-inventory.md](docs/dynu-dns-inventory.md)
|
- Dynu DNS read-only inventory workflow: [docs/dynu-dns-inventory.md](docs/dynu-dns-inventory.md)
|
||||||
|
- Generated host topology doc: [docs/generated/host-topology.md](docs/generated/host-topology.md)
|
||||||
- Ansible bootstrap workflows: [docs/ansible-workflows.md](docs/ansible-workflows.md)
|
- Ansible bootstrap workflows: [docs/ansible-workflows.md](docs/ansible-workflows.md)
|
||||||
- Deployment prerequisites and secrets setup: [docs/deployment-prerequisites.md](docs/deployment-prerequisites.md)
|
- Deployment prerequisites and secrets setup: [docs/deployment-prerequisites.md](docs/deployment-prerequisites.md)
|
||||||
- Secrets inventory: [docs/security-secrets.md](docs/security-secrets.md)
|
- Secrets inventory: [docs/security-secrets.md](docs/security-secrets.md)
|
||||||
@@ -119,6 +120,52 @@ flowchart TB
|
|||||||
|
|
||||||
For request-flow and network detail, see [docs/architecture.md](docs/architecture.md).
|
For request-flow and network detail, see [docs/architecture.md](docs/architecture.md).
|
||||||
|
|
||||||
|
## Public docs publication workflow
|
||||||
|
|
||||||
|
Public docs are generated on the Docker host and committed to this repository. GitHub Actions only publishes committed content from `docs/public`.
|
||||||
|
|
||||||
|
1. Generate public docs locally from the repository root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/generate-public-docs.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Inspect the generated changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff -- docs/public docs/generated docs/diagrams
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Commit the generated public docs (and any supporting generated files you intend to version):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add docs/public docs/generated docs/diagrams
|
||||||
|
git commit -m "docs: regenerate public docs"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Push your branch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
Only files under `docs/public` are published by GitHub Pages. Internal/generated documentation is not published unless it is deliberately copied/sanitized into `docs/public`.
|
||||||
|
|
||||||
|
### Regenerating architecture docs (Prometheus + Dynu DNS)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Refresh Dynu live inventory and generated resources/import helpers
|
||||||
|
cd infrastructure/terraform/dynu
|
||||||
|
terraform apply -refresh-only
|
||||||
|
python3 scripts/generate-brownfield-records.py --overwrite
|
||||||
|
|
||||||
|
# Regenerate architecture docs from Prometheus + Dynu inventory
|
||||||
|
cd ../../..
|
||||||
|
python3 scripts/render_prometheus_docs.py \
|
||||||
|
--inventory-file docs/runtime/prometheus-inventory.json \
|
||||||
|
--dynu-dns-inventory-file infrastructure/terraform/dynu/generated/dynu_dns_records_inventory.json
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Codex setup and maintenance scripts
|
## Codex setup and maintenance scripts
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ GITEA_DB_TYPE=sqlite3
|
|||||||
GITEA_ROOT_URL=https://gitea.lan.ddnsgeek.com/
|
GITEA_ROOT_URL=https://gitea.lan.ddnsgeek.com/
|
||||||
# Generate a token in Gitea: Site Administration → Actions → Runners
|
# Generate a token in Gitea: Site Administration → Actions → Runners
|
||||||
# or Repo → Settings → Actions → Runners
|
# or Repo → Settings → Actions → Runners
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN=
|
GITEA_RUNNER_REGISTRATION_TOKEN=vYDNxzMvayREkXoaAR3x3UREkxQB2PU4eORzmkZ9
|
||||||
GITEA_RUNNER_NAME=docker-runner-01
|
GITEA_RUNNER_NAME=docker-runner-01
|
||||||
GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://node:20-bookworm,linux:docker://node:20-bookworm,docker:docker://docker:cli
|
GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://node:20-bookworm,linux:docker://node:20-bookworm,docker:docker://docker:cli
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Generated Documentation
|
||||||
|
|
||||||
|
## 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` validates committed public docs and diagrams and runs a strict public MkDocs build.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
- `docs/generated`: resolved compose config and markdown inventories
|
||||||
|
- `docs/diagrams`: generated DOT and SVG diagrams
|
||||||
|
- `docs/public`: sanitized copy for public sharing
|
||||||
|
|
||||||
|
## Publication safety
|
||||||
|
|
||||||
|
- `docs/public` is intended for public sharing after sanitization.
|
||||||
|
- `docs/generated` and `docs/diagrams` may include internal details and should be treated as internal by default.
|
||||||
@@ -88,6 +88,7 @@ Use architecture docs together with:
|
|||||||
- [docs/source-of-truth.md](source-of-truth.md)
|
- [docs/source-of-truth.md](source-of-truth.md)
|
||||||
- [docs/terraform-workflows.md](terraform-workflows.md)
|
- [docs/terraform-workflows.md](terraform-workflows.md)
|
||||||
- [docs/infrastructure-inventory.md](infrastructure-inventory.md)
|
- [docs/infrastructure-inventory.md](infrastructure-inventory.md)
|
||||||
|
- [docs/generated/host-topology.md](generated/host-topology.md)
|
||||||
|
|
||||||
## Notes on runtime vs declared state
|
## Notes on runtime vs declared state
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Automation
|
||||||
|
|
||||||
|
This section describes automation systems associated with this environment.
|
||||||
|
|
||||||
|
Current state:
|
||||||
|
|
||||||
|
- CI documentation generation in GitHub Actions.
|
||||||
|
- Static parsing and rendering from repository configuration.
|
||||||
|
- No live service interaction during documentation generation.
|
||||||
|
|
||||||
|
Future content can document:
|
||||||
|
|
||||||
|
- Docker update automation.
|
||||||
|
- Node-RED automation flows and operational patterns.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
digraph Compose {
|
||||||
|
rankdir=LR;
|
||||||
|
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"];
|
||||||
|
"svc:docker-update-exporter" [label="docker-update-exporter", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:error-pages" [label="error-pages", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:gitea" [label="gitea", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:gitea-runner" [label="gitea-runner", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:gotify" [label="gotify", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:grafana" [label="grafana", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:gramps-redis" [label="gramps-redis", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:grampsweb" [label="grampsweb", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:grampsweb_celery" [label="grampsweb_celery", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:influxdb" [label="influxdb", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:monitor-kuma" [label="monitor-kuma", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:mtls-bridge" [label="mtls-bridge", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:nextcloud-db" [label="nextcloud-db", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:nextcloud-redis" [label="nextcloud-redis", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:nextcloud-webapp" [label="nextcloud-webapp", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:node-exporter" [label="node-exporter", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:node-red" [label="node-red", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:passbolt-db" [label="passbolt-db", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:passbolt-webapp" [label="passbolt-webapp", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:pihole-exporter" [label="pihole-exporter", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:portainer" [label="portainer", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:prometheus" [label="prometheus", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:searxng-webapp" [label="searxng-webapp", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:telegraf" [label="telegraf", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"svc:traefik" [label="traefik", shape=box, style=filled, fillcolor="#dfefff"];
|
||||||
|
"net:gramps" [label="gramps", shape=ellipse, style=filled, fillcolor="#f4f4f4"];
|
||||||
|
"net:monitor" [label="monitor", shape=ellipse, style=filled, fillcolor="#f4f4f4"];
|
||||||
|
"net:nextcloud" [label="nextcloud", shape=ellipse, style=filled, fillcolor="#f4f4f4"];
|
||||||
|
"net:passbolt" [label="passbolt", shape=ellipse, style=filled, fillcolor="#f4f4f4"];
|
||||||
|
"net:traefik" [label="traefik", shape=ellipse, style=filled, fillcolor="#f4f4f4"];
|
||||||
|
"svc:authelia" -> "net:traefik";
|
||||||
|
"svc:crowdsec" -> "net:traefik";
|
||||||
|
"svc:docker-socket-proxy" -> "net:monitor";
|
||||||
|
"svc:docker-socket-proxy" -> "net:traefik";
|
||||||
|
"svc:docker-update-exporter" -> "net:monitor";
|
||||||
|
"svc:error-pages" -> "net:traefik";
|
||||||
|
"svc:gitea" -> "net:traefik";
|
||||||
|
"svc:gitea-runner" -> "net:traefik";
|
||||||
|
"svc:gotify" -> "net:traefik";
|
||||||
|
"svc:grafana" -> "net:monitor";
|
||||||
|
"svc:grafana" -> "net:traefik";
|
||||||
|
"svc:gramps-redis" -> "net:gramps";
|
||||||
|
"svc:grampsweb" -> "net:gramps";
|
||||||
|
"svc:grampsweb" -> "net:traefik";
|
||||||
|
"svc:grampsweb_celery" -> "net:gramps";
|
||||||
|
"svc:influxdb" -> "net:monitor";
|
||||||
|
"svc:influxdb" -> "net:traefik";
|
||||||
|
"svc:monitor-kuma" -> "net:monitor";
|
||||||
|
"svc:monitor-kuma" -> "net:traefik";
|
||||||
|
"svc:mtls-bridge" -> "net:monitor";
|
||||||
|
"svc:mtls-bridge" -> "net:traefik";
|
||||||
|
"svc:nextcloud-db" -> "net:nextcloud";
|
||||||
|
"svc:nextcloud-redis" -> "net:nextcloud";
|
||||||
|
"svc:nextcloud-webapp" -> "net:nextcloud";
|
||||||
|
"svc:nextcloud-webapp" -> "net:traefik";
|
||||||
|
"svc:node-exporter" -> "net:monitor";
|
||||||
|
"svc:node-red" -> "net:monitor";
|
||||||
|
"svc:node-red" -> "net:traefik";
|
||||||
|
"svc:passbolt-db" -> "net:passbolt";
|
||||||
|
"svc:passbolt-webapp" -> "net:passbolt";
|
||||||
|
"svc:passbolt-webapp" -> "net:traefik";
|
||||||
|
"svc:pihole-exporter" -> "net:monitor";
|
||||||
|
"svc:portainer" -> "net:traefik";
|
||||||
|
"svc:prometheus" -> "net:monitor";
|
||||||
|
"svc:prometheus" -> "net:traefik";
|
||||||
|
"svc:searxng-webapp" -> "net:traefik";
|
||||||
|
"svc:telegraf" -> "net:monitor";
|
||||||
|
"svc:traefik" -> "net:traefik";
|
||||||
|
}
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: Compose Pages: 1 -->
|
||||||
|
<svg width="334pt" height="1502pt"
|
||||||
|
viewBox="0.00 0.00 334.49 1502.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1498)">
|
||||||
|
<title>Compose</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1498 330.49,-1498 330.49,4 -4,4"/>
|
||||||
|
<!-- svc:authelia -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>svc:authelia</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="126,-738 54,-738 54,-702 126,-702 126,-738"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-716.3" font-family="Helvetica,sans-Serif" font-size="14.00">authelia</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:traefik -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>net:traefik</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-774" rx="40.09" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-770.3" font-family="Helvetica,sans-Serif" font-size="14.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia->net:traefik -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>svc:authelia->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M126.41,-730.67C155.5,-739.43 196.8,-751.87 227.69,-761.18"/>
|
||||||
|
<polygon fill="black" stroke="black" points="226.74,-764.55 237.32,-764.08 228.76,-757.85 226.74,-764.55"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:crowdsec -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>svc:crowdsec</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="130.5,-684 49.5,-684 49.5,-648 130.5,-648 130.5,-684"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-662.3" font-family="Helvetica,sans-Serif" font-size="14.00">crowdsec</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:crowdsec->net:traefik -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>svc:crowdsec->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M130.61,-674.06C146.59,-678.3 164.81,-684.44 180,-693 206.25,-707.78 231.35,-731.35 248.38,-749.26"/>
|
||||||
|
<polygon fill="black" stroke="black" points="246.24,-752.1 255.62,-757.03 251.37,-747.33 246.24,-752.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>svc:docker-socket-proxy</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="167.5,-954 12.5,-954 12.5,-918 167.5,-918 167.5,-954"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-932.3" font-family="Helvetica,sans-Serif" font-size="14.00">docker-socket-proxy</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:monitor -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>net:monitor</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-1206" rx="46.29" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-1202.3" font-family="Helvetica,sans-Serif" font-size="14.00">monitor</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy->net:monitor -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>svc:docker-socket-proxy->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M167.53,-953.71C172.02,-956.38 176.24,-959.46 180,-963 242.3,-1021.6 261.83,-1127.12 267.77,-1177.6"/>
|
||||||
|
<polygon fill="black" stroke="black" points="264.31,-1178.21 268.86,-1187.78 271.27,-1177.46 264.31,-1178.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy->net:traefik -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>svc:docker-socket-proxy->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M165.31,-917.9C170.5,-915.32 175.46,-912.37 180,-909 218.01,-880.82 244.97,-831.56 259.03,-800.98"/>
|
||||||
|
<polygon fill="black" stroke="black" points="262.27,-802.31 263.14,-791.76 255.87,-799.46 262.27,-802.31"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-update-exporter -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>svc:docker-update-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="180,-1494 0,-1494 0,-1458 180,-1458 180,-1494"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1472.3" font-family="Helvetica,sans-Serif" font-size="14.00">docker-update-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-update-exporter->net:monitor -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>svc:docker-update-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M168.37,-1457.79C172.55,-1455.23 176.47,-1452.32 180,-1449 242.3,-1390.4 261.83,-1284.88 267.77,-1234.4"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.27,-1234.54 268.86,-1224.22 264.31,-1233.79 271.27,-1234.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:error-pages -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>svc:error-pages</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="137.5,-630 42.5,-630 42.5,-594 137.5,-594 137.5,-630"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-608.3" font-family="Helvetica,sans-Serif" font-size="14.00">error-pages</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:error-pages->net:traefik -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>svc:error-pages->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M137.71,-619.76C152.25,-623.79 167.68,-629.86 180,-639 218.01,-667.18 244.97,-716.44 259.03,-747.02"/>
|
||||||
|
<polygon fill="black" stroke="black" points="255.87,-748.54 263.14,-756.24 262.27,-745.69 255.87,-748.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>svc:gitea</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="117,-576 63,-576 63,-540 117,-540 117,-576"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-554.3" font-family="Helvetica,sans-Serif" font-size="14.00">gitea</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea->net:traefik -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>svc:gitea->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M117.07,-560.28C136.41,-563.2 162.37,-569.85 180,-585 229.98,-627.95 254.42,-704.8 264.44,-746.04"/>
|
||||||
|
<polygon fill="black" stroke="black" points="261.07,-747 266.73,-755.95 267.88,-745.42 261.07,-747"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea-runner -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>svc:gitea-runner</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="142,-522 38,-522 38,-486 142,-486 142,-522"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-500.3" font-family="Helvetica,sans-Serif" font-size="14.00">gitea-runner</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea-runner->net:traefik -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>svc:gitea-runner->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M142.31,-511.04C155.9,-515.03 169.65,-521.26 180,-531 242.3,-589.6 261.83,-695.12 267.77,-745.6"/>
|
||||||
|
<polygon fill="black" stroke="black" points="264.31,-746.21 268.86,-755.78 271.27,-745.46 264.31,-746.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>svc:gotify</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="118,-468 62,-468 62,-432 118,-432 118,-468"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-446.3" font-family="Helvetica,sans-Serif" font-size="14.00">gotify</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify->net:traefik -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>svc:gotify->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M118.17,-451.6C137.81,-454.16 163.67,-460.68 180,-477 254.99,-551.96 268.02,-687.13 270.03,-745.69"/>
|
||||||
|
<polygon fill="black" stroke="black" points="266.53,-745.79 270.29,-755.69 273.53,-745.61 266.53,-745.79"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>svc:grafana</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="125.5,-1278 54.5,-1278 54.5,-1242 125.5,-1242 125.5,-1278"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1256.3" font-family="Helvetica,sans-Serif" font-size="14.00">grafana</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:monitor -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>svc:grafana->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.56,-1249.59C153.74,-1241.1 193.78,-1229.04 224.6,-1219.75"/>
|
||||||
|
<polygon fill="black" stroke="black" points="225.69,-1223.08 234.26,-1216.84 223.67,-1216.38 225.69,-1223.08"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:traefik -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>svc:grafana->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.54,-1257.93C144.23,-1254.97 166.25,-1248.21 180,-1233 238.17,-1168.67 262.1,-892.17 268.43,-802.32"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.93,-802.3 269.13,-792.08 264.95,-801.82 271.93,-802.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gramps-redis -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>svc:gramps-redis</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="144.5,-360 35.5,-360 35.5,-324 144.5,-324 144.5,-360"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-338.3" font-family="Helvetica,sans-Serif" font-size="14.00">gramps-redis</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:gramps -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>net:gramps</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-342" rx="45.49" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-338.3" font-family="Helvetica,sans-Serif" font-size="14.00">gramps</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gramps-redis->net:gramps -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>svc:gramps-redis->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M144.78,-342C167.14,-342 193.05,-342 215.51,-342"/>
|
||||||
|
<polygon fill="black" stroke="black" points="215.56,-345.5 225.56,-342 215.56,-338.5 215.56,-345.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>svc:grampsweb</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="139,-414 41,-414 41,-378 139,-378 139,-414"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-392.3" font-family="Helvetica,sans-Serif" font-size="14.00">grampsweb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:gramps -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>svc:grampsweb->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.03,-381.53C165.7,-373.5 198.68,-363.56 224.9,-355.66"/>
|
||||||
|
<polygon fill="black" stroke="black" points="226.03,-358.98 234.59,-352.74 224.01,-352.27 226.03,-358.98"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:traefik -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>svc:grampsweb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.27,-401.34C154.08,-405.21 169.28,-411.81 180,-423 225.12,-470.09 256.34,-671.08 266.59,-745.84"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.14,-746.48 267.95,-755.92 270.08,-745.55 263.14,-746.48"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb_celery -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>svc:grampsweb_celery</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="163.5,-306 16.5,-306 16.5,-270 163.5,-270 163.5,-306"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-284.3" font-family="Helvetica,sans-Serif" font-size="14.00">grampsweb_celery</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb_celery->net:gramps -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>svc:grampsweb_celery->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-306.13C175.28,-313.39 202.57,-321.61 224.94,-328.35"/>
|
||||||
|
<polygon fill="black" stroke="black" points="223.94,-331.71 234.52,-331.24 225.96,-325 223.94,-331.71"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>svc:influxdb</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="127,-1224 53,-1224 53,-1188 127,-1188 127,-1224"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1202.3" font-family="Helvetica,sans-Serif" font-size="14.00">influxdb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:monitor -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>svc:influxdb->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M127.27,-1206C152.33,-1206 186.13,-1206 214.57,-1206"/>
|
||||||
|
<polygon fill="black" stroke="black" points="214.79,-1209.5 224.79,-1206 214.79,-1202.5 214.79,-1209.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:traefik -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>svc:influxdb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M127.17,-1203.5C145.42,-1200.36 166.5,-1193.56 180,-1179 231.57,-1123.4 259.36,-885.3 267.6,-802.51"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.1,-802.62 268.59,-792.33 264.14,-801.94 271.1,-802.62"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>svc:monitor-kuma</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="146.5,-1170 33.5,-1170 33.5,-1134 146.5,-1134 146.5,-1170"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1148.3" font-family="Helvetica,sans-Serif" font-size="14.00">monitor-kuma</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:monitor -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M146.73,-1168.79C171.73,-1176.32 200.85,-1185.1 224.54,-1192.23"/>
|
||||||
|
<polygon fill="black" stroke="black" points="223.75,-1195.65 234.33,-1195.18 225.77,-1188.94 223.75,-1195.65"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:traefik -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M146.69,-1144.49C159.02,-1140.46 171.06,-1134.33 180,-1125 225.12,-1077.91 256.34,-876.92 266.59,-802.16"/>
|
||||||
|
<polygon fill="black" stroke="black" points="270.08,-802.45 267.95,-792.08 263.14,-801.52 270.08,-802.45"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>svc:mtls-bridge</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="138.5,-1116 41.5,-1116 41.5,-1080 138.5,-1080 138.5,-1116"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1094.3" font-family="Helvetica,sans-Serif" font-size="14.00">mtls-bridge</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:monitor -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M138.76,-1108.34C152.58,-1112.41 167.34,-1117.87 180,-1125 206.25,-1139.78 231.35,-1163.35 248.38,-1181.26"/>
|
||||||
|
<polygon fill="black" stroke="black" points="246.24,-1184.1 255.62,-1189.03 251.37,-1179.33 246.24,-1184.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:traefik -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M138.53,-1092.51C153.46,-1088.63 168.92,-1082.07 180,-1071 254.99,-996.04 268.02,-860.87 270.03,-802.31"/>
|
||||||
|
<polygon fill="black" stroke="black" points="273.53,-802.39 270.29,-792.31 266.53,-802.21 273.53,-802.39"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-db -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>svc:nextcloud-db</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="144,-90 36,-90 36,-54 144,-54 144,-90"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-68.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-db</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:nextcloud -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>net:nextcloud</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-180" rx="55.49" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-176.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-db->net:nextcloud -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>svc:nextcloud-db->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M144.33,-84.04C156.48,-87.9 169.03,-92.82 180,-99 206.09,-113.7 231.04,-137.06 248.07,-154.93"/>
|
||||||
|
<polygon fill="black" stroke="black" points="245.93,-157.77 255.31,-162.7 251.06,-153 245.93,-157.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-redis -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>svc:nextcloud-redis</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="152,-198 28,-198 28,-162 152,-162 152,-198"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-176.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-redis</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-redis->net:nextcloud -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>svc:nextcloud-redis->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M152.18,-180C169.48,-180 188.35,-180 205.83,-180"/>
|
||||||
|
<polygon fill="black" stroke="black" points="205.94,-183.5 215.94,-180 205.94,-176.5 205.94,-183.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>svc:nextcloud-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="162.5,-252 17.5,-252 17.5,-216 162.5,-216 162.5,-252"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-230.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:nextcloud -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-215.87C173.57,-209.12 198.72,-201.55 220.11,-195.1"/>
|
||||||
|
<polygon fill="black" stroke="black" points="221.4,-198.37 229.97,-192.13 219.38,-191.67 221.4,-198.37"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:traefik -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M162.89,-247.71C169.31,-251.2 175.18,-255.56 180,-261 212.66,-297.85 255.07,-643.36 267,-745.62"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.55,-746.27 268.18,-755.8 270.51,-745.47 263.55,-746.27"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-exporter -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>svc:node-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="148,-1440 32,-1440 32,-1404 148,-1404 148,-1440"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1418.3" font-family="Helvetica,sans-Serif" font-size="14.00">node-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-exporter->net:monitor -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>svc:node-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M148.25,-1412.27C159.68,-1408.33 170.94,-1402.79 180,-1395 229.98,-1352.05 254.42,-1275.2 264.44,-1233.96"/>
|
||||||
|
<polygon fill="black" stroke="black" points="267.88,-1234.58 266.73,-1224.05 261.07,-1233 267.88,-1234.58"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>svc:node-red</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="129.5,-1062 50.5,-1062 50.5,-1026 129.5,-1026 129.5,-1062"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1040.3" font-family="Helvetica,sans-Serif" font-size="14.00">node-red</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:monitor -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>svc:node-red->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M129.57,-1049.69C146.29,-1053.6 165.34,-1060.13 180,-1071 218.01,-1099.18 244.97,-1148.44 259.03,-1179.02"/>
|
||||||
|
<polygon fill="black" stroke="black" points="255.87,-1180.54 263.14,-1188.24 262.27,-1177.69 255.87,-1180.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:traefik -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>svc:node-red->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M129.95,-1040.03C147.14,-1036.46 166.48,-1029.72 180,-1017 242.3,-958.4 261.83,-852.88 267.77,-802.4"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.27,-802.54 268.86,-792.22 264.31,-801.79 271.27,-802.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-db -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>svc:passbolt-db</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="139,-36 41,-36 41,0 139,0 139,-36"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-14.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt-db</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:passbolt -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>net:passbolt</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-72" rx="48.99" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-68.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-db->net:passbolt -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>svc:passbolt-db->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.03,-32.47C165.15,-40.34 197.32,-50.03 223.27,-57.85"/>
|
||||||
|
<polygon fill="black" stroke="black" points="222.3,-61.21 232.88,-60.74 224.32,-54.51 222.3,-61.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>svc:passbolt-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="157.5,-144 22.5,-144 22.5,-108 157.5,-108 157.5,-144"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-122.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:passbolt -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-107.87C174.64,-100.8 201.13,-92.82 223.16,-86.19"/>
|
||||||
|
<polygon fill="black" stroke="black" points="224.37,-89.48 232.94,-83.24 222.35,-82.77 224.37,-89.48"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:traefik -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M157.85,-136.93C166.26,-140.81 174,-146.02 180,-153 189.88,-164.49 250.79,-625.33 266.53,-745.56"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.1,-746.33 267.87,-755.8 270.04,-745.43 263.1,-746.33"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:pihole-exporter -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>svc:pihole-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="151.5,-1386 28.5,-1386 28.5,-1350 151.5,-1350 151.5,-1386"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1364.3" font-family="Helvetica,sans-Serif" font-size="14.00">pihole-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:pihole-exporter->net:monitor -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>svc:pihole-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.62,-1355.78C161.68,-1352.07 171.57,-1347.25 180,-1341 218.01,-1312.82 244.97,-1263.56 259.03,-1232.98"/>
|
||||||
|
<polygon fill="black" stroke="black" points="262.27,-1234.31 263.14,-1223.76 255.87,-1231.46 262.27,-1234.31"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>svc:portainer</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="130,-900 50,-900 50,-864 130,-864 130,-900"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-878.3" font-family="Helvetica,sans-Serif" font-size="14.00">portainer</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer->net:traefik -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>svc:portainer->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M130.17,-874.06C146.25,-869.82 164.67,-863.64 180,-855 206.25,-840.22 231.35,-816.65 248.38,-798.74"/>
|
||||||
|
<polygon fill="black" stroke="black" points="251.37,-800.67 255.62,-790.97 246.24,-795.9 251.37,-800.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>svc:prometheus</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="140,-1008 40,-1008 40,-972 140,-972 140,-1008"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-986.3" font-family="Helvetica,sans-Serif" font-size="14.00">prometheus</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:monitor -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>svc:prometheus->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M140.37,-997.26C154.39,-1001.24 168.86,-1007.42 180,-1017 229.98,-1059.95 254.42,-1136.8 264.44,-1178.04"/>
|
||||||
|
<polygon fill="black" stroke="black" points="261.07,-1179 266.73,-1187.95 267.88,-1177.42 261.07,-1179"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:traefik -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>svc:prometheus->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M140.37,-982.74C154.39,-978.76 168.86,-972.58 180,-963 229.98,-920.05 254.42,-843.2 264.44,-801.96"/>
|
||||||
|
<polygon fill="black" stroke="black" points="267.88,-802.58 266.73,-792.05 261.07,-801 267.88,-802.58"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>svc:searxng-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="156,-846 24,-846 24,-810 156,-810 156,-846"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-824.3" font-family="Helvetica,sans-Serif" font-size="14.00">searxng-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp->net:traefik -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>svc:searxng-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-809.87C176.26,-802.32 204.79,-793.72 227.63,-786.84"/>
|
||||||
|
<polygon fill="black" stroke="black" points="228.81,-790.14 237.37,-783.9 226.79,-783.44 228.81,-790.14"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:telegraf -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>svc:telegraf</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="125.5,-1332 54.5,-1332 54.5,-1296 125.5,-1296 125.5,-1332"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1310.3" font-family="Helvetica,sans-Serif" font-size="14.00">telegraf</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:telegraf->net:monitor -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>svc:telegraf->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.8,-1307.18C142.85,-1302.93 163.26,-1296.43 180,-1287 206.25,-1272.22 231.35,-1248.65 248.38,-1230.74"/>
|
||||||
|
<polygon fill="black" stroke="black" points="251.37,-1232.67 255.62,-1222.97 246.24,-1227.9 251.37,-1232.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>svc:traefik</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="121,-792 59,-792 59,-756 121,-756 121,-792"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-770.3" font-family="Helvetica,sans-Serif" font-size="14.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->net:traefik -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>svc:traefik->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M121,-774C148.16,-774 188.69,-774 220.66,-774"/>
|
||||||
|
<polygon fill="black" stroke="black" points="220.71,-777.5 230.71,-774 220.71,-770.5 220.71,-777.5"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,118 @@
|
|||||||
|
digraph DockerTraefikDynu {
|
||||||
|
graph [rankdir=LR, compound=true, splines=polyline, nodesep=0.9, ranksep=1.6, fontname="Helvetica", concentrate=true, newrank=true];
|
||||||
|
node [fontname="Helvetica", fontsize=11, style="rounded,filled"];
|
||||||
|
edge [fontname="Helvetica", fontsize=9, color="#334155"];
|
||||||
|
"dynu" [label="Dynu / Public DNS", shape=box, fillcolor="#fde68a"];
|
||||||
|
"svc:traefik" [label="Traefik", shape=box, fillcolor="#bfdbfe"];
|
||||||
|
"dynu" -> "svc:traefik" [penwidth=1.6];
|
||||||
|
"svc:authelia" [label="authelia
|
||||||
|
[TLS]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:authelia" [penwidth=1.4];
|
||||||
|
"dns:auth.<domain>" [label="auth.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:auth.<domain>" -> "dynu";
|
||||||
|
"svc:gitea" [label="gitea
|
||||||
|
:3000
|
||||||
|
[TLS]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:gitea" [penwidth=1.4];
|
||||||
|
"dns:gitea.<domain>" [label="gitea.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:gitea.<domain>" -> "dynu";
|
||||||
|
"svc:gotify" [label="gotify
|
||||||
|
:80", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:gotify" [penwidth=1.4];
|
||||||
|
"dns:gotify.<domain>" [label="gotify.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:gotify.<domain>" -> "dynu";
|
||||||
|
"svc:grafana" [label="grafana
|
||||||
|
:3000", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:grafana" [penwidth=1.4];
|
||||||
|
"dns:grafana.<domain>" [label="grafana.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:grafana.<domain>" -> "dynu";
|
||||||
|
"svc:grampsweb" [label="grampsweb", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:grampsweb" [penwidth=1.4];
|
||||||
|
"dns:familytree.<domain>" [label="familytree.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:familytree.<domain>" -> "dynu";
|
||||||
|
"svc:influxdb" [label="influxdb
|
||||||
|
:8086
|
||||||
|
[authelia]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:influxdb" [penwidth=1.4];
|
||||||
|
"dns:influxdb.<domain>" [label="influxdb.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:influxdb.<domain>" -> "dynu";
|
||||||
|
"svc:monitor-kuma" [label="monitor-kuma
|
||||||
|
[TLS]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:monitor-kuma" [penwidth=1.4];
|
||||||
|
"dns:monitor-kuma.<domain>" [label="monitor-kuma.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:monitor-kuma.<domain>" -> "dynu";
|
||||||
|
"svc:mtls-bridge" [label="mtls-bridge
|
||||||
|
:8080
|
||||||
|
[mTLS]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:mtls-bridge" [penwidth=1.4];
|
||||||
|
"dns:mtls-bridge.<domain>" [label="mtls-bridge.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:mtls-bridge.<domain>" -> "dynu";
|
||||||
|
"svc:nextcloud-webapp" [label="nextcloud-webapp", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:nextcloud-webapp" [penwidth=1.4];
|
||||||
|
"dns:nextcloud.<domain>" [label="nextcloud.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:nextcloud.<domain>" -> "dynu";
|
||||||
|
"svc:node-red" [label="node-red
|
||||||
|
:1880
|
||||||
|
[authelia]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:node-red" [penwidth=1.4];
|
||||||
|
"dns:node-red.<domain>" [label="node-red.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:node-red.<domain>" -> "dynu";
|
||||||
|
"svc:passbolt-webapp" [label="passbolt-webapp", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:passbolt-webapp" [penwidth=1.4];
|
||||||
|
"dns:passbolt.<domain>" [label="passbolt.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:passbolt.<domain>" -> "dynu";
|
||||||
|
"svc:portainer" [label="portainer
|
||||||
|
:9000
|
||||||
|
[TLS]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:portainer" [penwidth=1.4];
|
||||||
|
"dns:portainer.<domain>" [label="portainer.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:portainer.<domain>" -> "dynu";
|
||||||
|
"svc:prometheus" [label="prometheus
|
||||||
|
:9090
|
||||||
|
[authelia]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:prometheus" [penwidth=1.4];
|
||||||
|
"dns:prometheus.<domain>" [label="prometheus.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:prometheus.<domain>" -> "dynu";
|
||||||
|
"svc:searxng-webapp" [label="searxng-webapp", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:searxng-webapp" [penwidth=1.4];
|
||||||
|
"dns:searxng.<domain>" [label="searxng.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:searxng.<domain>" -> "dynu";
|
||||||
|
"svc:traefik" [label="traefik
|
||||||
|
[authelia]", shape=box, fillcolor="#dcfce7"];
|
||||||
|
"svc:traefik" -> "svc:traefik" [penwidth=1.4];
|
||||||
|
"dns:traefik.<domain>" [label="traefik.<domain>", shape=note, fillcolor="#fef3c7"];
|
||||||
|
"dns:traefik.<domain>" -> "dynu";
|
||||||
|
{ rank=same; "dns:auth.<domain>"; "dns:familytree.<domain>"; "dns:gitea.<domain>"; "dns:gotify.<domain>"; "dns:grafana.<domain>"; "dns:influxdb.<domain>"; "dns:monitor-kuma.<domain>"; "dns:mtls-bridge.<domain>"; "dns:nextcloud.<domain>"; "dns:node-red.<domain>"; "dns:passbolt.<domain>"; "dns:portainer.<domain>"; "dns:prometheus.<domain>"; "dns:searxng.<domain>"; "dns:traefik.<domain>"; }
|
||||||
|
subgraph "cluster_networks" {
|
||||||
|
label="Docker backend networks"; style="rounded,dashed"; color="#d1d5db";
|
||||||
|
"net:gramps" [label="gramps", shape=ellipse, fillcolor="#f8fafc"];
|
||||||
|
"net:monitor" [label="monitor", shape=ellipse, fillcolor="#f8fafc"];
|
||||||
|
"net:nextcloud" [label="nextcloud", shape=ellipse, fillcolor="#f8fafc"];
|
||||||
|
"net:passbolt" [label="passbolt", shape=ellipse, fillcolor="#f8fafc"];
|
||||||
|
"net:traefik" [label="traefik", shape=ellipse, fillcolor="#f8fafc"];
|
||||||
|
}
|
||||||
|
"svc:authelia" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:gitea" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:gotify" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:grafana" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:grafana" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:grampsweb" -> "net:gramps" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:grampsweb" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:influxdb" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:influxdb" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:monitor-kuma" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:monitor-kuma" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:mtls-bridge" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:mtls-bridge" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:nextcloud-webapp" -> "net:nextcloud" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:nextcloud-webapp" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:node-red" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:node-red" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:passbolt-webapp" -> "net:passbolt" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:passbolt-webapp" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:portainer" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:prometheus" -> "net:monitor" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:prometheus" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:searxng-webapp" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
"svc:traefik" -> "net:traefik" [style=dashed, color="#94a3b8", arrowsize=0.7];
|
||||||
|
}
|
||||||
@@ -0,0 +1,611 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: DockerTraefikDynu Pages: 1 -->
|
||||||
|
<svg width="1113pt" height="1536pt"
|
||||||
|
viewBox="0.00 0.00 1113.39 1536.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1532)">
|
||||||
|
<title>DockerTraefikDynu</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1532 1109.39,-1532 1109.39,4 -4,4"/>
|
||||||
|
<g id="clust2" class="cluster">
|
||||||
|
<title>cluster_networks</title>
|
||||||
|
<path fill="none" stroke="#d1d5db" stroke-dasharray="5,2" d="M922,-650C922,-650 1093.39,-650 1093.39,-650 1099.39,-650 1105.39,-656 1105.39,-662 1105.39,-662 1105.39,-1117 1105.39,-1117 1105.39,-1123 1099.39,-1129 1093.39,-1129 1093.39,-1129 922,-1129 922,-1129 916,-1129 910,-1123 910,-1117 910,-1117 910,-662 910,-662 910,-656 916,-650 922,-650"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-1113.8" font-family="Helvetica,sans-Serif" font-size="14.00">Docker backend networks</text>
|
||||||
|
</g>
|
||||||
|
<!-- dynu -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>dynu</title>
|
||||||
|
<path fill="#fde68a" stroke="black" d="M374,-789C374,-789 282,-789 282,-789 276,-789 270,-783 270,-777 270,-777 270,-765 270,-765 270,-759 276,-753 282,-753 282,-753 374,-753 374,-753 380,-753 386,-759 386,-765 386,-765 386,-777 386,-777 386,-783 380,-789 374,-789"/>
|
||||||
|
<text text-anchor="middle" x="328" y="-768.2" font-family="Helvetica,sans-Serif" font-size="11.00">Dynu / Public DNS</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>svc:traefik</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M559,-789C559,-789 513,-789 513,-789 507,-789 501,-783 501,-777 501,-777 501,-765 501,-765 501,-759 507,-753 513,-753 513,-753 559,-753 559,-753 565,-753 571,-759 571,-765 571,-765 571,-777 571,-777 571,-783 565,-789 559,-789"/>
|
||||||
|
<text text-anchor="middle" x="536" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik</text>
|
||||||
|
<text text-anchor="middle" x="536" y="-762.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- dynu->svc:traefik -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>dynu->svc:traefik</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.6" d="M386.11,-771C419.13,-771 460.06,-771 490.64,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.6" points="491,-774.5 501,-771 491,-767.5 491,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:traefik -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>svc:traefik->svc:traefik</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M511.86,-789.35C485.91,-817.82 493.95,-854 536,-854 574.1,-854 584.29,-824.29 566.55,-797.52"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="569.07,-795.06 560.14,-789.35 563.55,-799.38 569.07,-795.06"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>svc:authelia</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M763,-789C763,-789 726,-789 726,-789 720,-789 714,-783 714,-777 714,-777 714,-765 714,-765 714,-759 720,-753 726,-753 726,-753 763,-753 763,-753 769,-753 775,-759 775,-765 775,-765 775,-777 775,-777 775,-783 769,-789 763,-789"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">authelia</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-762.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:authelia -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>svc:traefik->svc:authelia</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-771C607.43,-771 664.91,-771 703.39,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="703.71,-774.5 713.71,-771 703.71,-767.5 703.71,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>svc:gitea</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M759.5,-688C759.5,-688 729.5,-688 729.5,-688 723.5,-688 717.5,-682 717.5,-676 717.5,-676 717.5,-656 717.5,-656 717.5,-650 723.5,-644 729.5,-644 729.5,-644 759.5,-644 759.5,-644 765.5,-644 771.5,-650 771.5,-656 771.5,-656 771.5,-676 771.5,-676 771.5,-682 765.5,-688 759.5,-688"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-675.2" font-family="Helvetica,sans-Serif" font-size="11.00">gitea</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-663.2" font-family="Helvetica,sans-Serif" font-size="11.00">:3000</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-651.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:gitea -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>svc:traefik->svc:gitea</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-753.66C608.91,-734.44 669.61,-703.57 707.98,-684.06"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="709.89,-687.01 717.22,-679.36 706.72,-680.77 709.89,-687.01"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>svc:gotify</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M759.5,-579C759.5,-579 729.5,-579 729.5,-579 723.5,-579 717.5,-573 717.5,-567 717.5,-567 717.5,-555 717.5,-555 717.5,-549 723.5,-543 729.5,-543 729.5,-543 759.5,-543 759.5,-543 765.5,-543 771.5,-549 771.5,-555 771.5,-555 771.5,-567 771.5,-567 771.5,-573 765.5,-579 759.5,-579"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-564.2" font-family="Helvetica,sans-Serif" font-size="11.00">gotify</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-552.2" font-family="Helvetica,sans-Serif" font-size="11.00">:80</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:gotify -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>svc:traefik->svc:gotify</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M553.8,-752.96C592.77,-711.11 686,-611 686,-611 686,-611 700.43,-598.45 714.83,-585.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-588.25 722.74,-579.05 712.9,-582.97 717.49,-588.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>svc:grafana</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M762,-999C762,-999 727,-999 727,-999 721,-999 715,-993 715,-987 715,-987 715,-975 715,-975 715,-969 721,-963 727,-963 727,-963 762,-963 762,-963 768,-963 774,-969 774,-975 774,-975 774,-987 774,-987 774,-993 768,-999 762,-999"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-984.2" font-family="Helvetica,sans-Serif" font-size="11.00">grafana</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-972.2" font-family="Helvetica,sans-Serif" font-size="11.00">:3000</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:grafana -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>svc:traefik->svc:grafana</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M553.8,-789.04C592.77,-830.89 686,-931 686,-931 686,-931 700.43,-943.55 714.83,-956.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-959.03 722.74,-962.95 717.49,-953.75 712.9,-959.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>svc:grampsweb</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M772.5,-1528C772.5,-1528 716.5,-1528 716.5,-1528 710.5,-1528 704.5,-1522 704.5,-1516 704.5,-1516 704.5,-1504 704.5,-1504 704.5,-1498 710.5,-1492 716.5,-1492 716.5,-1492 772.5,-1492 772.5,-1492 778.5,-1492 784.5,-1498 784.5,-1504 784.5,-1504 784.5,-1516 784.5,-1516 784.5,-1522 778.5,-1528 772.5,-1528"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1507.2" font-family="Helvetica,sans-Serif" font-size="11.00">grampsweb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:grampsweb -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>svc:traefik->svc:grampsweb</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M540.91,-789.07C564.42,-897.78 686,-1460 686,-1460 686,-1460 700.43,-1472.55 714.83,-1485.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-1488.03 722.74,-1491.95 717.49,-1482.75 712.9,-1488.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>svc:influxdb</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M767.5,-898C767.5,-898 721.5,-898 721.5,-898 715.5,-898 709.5,-892 709.5,-886 709.5,-886 709.5,-866 709.5,-866 709.5,-860 715.5,-854 721.5,-854 721.5,-854 767.5,-854 767.5,-854 773.5,-854 779.5,-860 779.5,-866 779.5,-866 779.5,-886 779.5,-886 779.5,-892 773.5,-898 767.5,-898"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-885.2" font-family="Helvetica,sans-Serif" font-size="11.00">influxdb</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-873.2" font-family="Helvetica,sans-Serif" font-size="11.00">:8086</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-861.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:influxdb -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>svc:traefik->svc:influxdb</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-788.34C606.37,-806.27 661.57,-834.34 699.97,-853.87"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="698.85,-857.22 709.35,-858.64 702.02,-850.98 698.85,-857.22"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>svc:monitor-kuma</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M778.5,-1427C778.5,-1427 710.5,-1427 710.5,-1427 704.5,-1427 698.5,-1421 698.5,-1415 698.5,-1415 698.5,-1403 698.5,-1403 698.5,-1397 704.5,-1391 710.5,-1391 710.5,-1391 778.5,-1391 778.5,-1391 784.5,-1391 790.5,-1397 790.5,-1403 790.5,-1403 790.5,-1415 790.5,-1415 790.5,-1421 784.5,-1427 778.5,-1427"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1412.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor-kuma</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1400.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:monitor-kuma -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>svc:traefik->svc:monitor-kuma</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M541.62,-789.24C566.77,-888.49 686,-1359 686,-1359 686,-1359 700.43,-1371.55 714.83,-1384.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-1387.03 722.74,-1390.95 717.49,-1381.75 712.9,-1387.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>svc:mtls-bridge</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M772,-1326C772,-1326 717,-1326 717,-1326 711,-1326 705,-1320 705,-1314 705,-1314 705,-1294 705,-1294 705,-1288 711,-1282 717,-1282 717,-1282 772,-1282 772,-1282 778,-1282 784,-1288 784,-1294 784,-1294 784,-1314 784,-1314 784,-1320 778,-1326 772,-1326"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1313.2" font-family="Helvetica,sans-Serif" font-size="11.00">mtls-bridge</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1301.2" font-family="Helvetica,sans-Serif" font-size="11.00">:8080</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1289.2" font-family="Helvetica,sans-Serif" font-size="11.00">[mTLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:mtls-bridge -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>svc:traefik->svc:mtls-bridge</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M542.66,-789.19C569.88,-876.69 686,-1250 686,-1250 686,-1250 698.77,-1262 712.28,-1274.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1277.43 719.78,-1281.72 714.89,-1272.33 710.1,-1277.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>svc:nextcloud-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M791,-137C791,-137 698,-137 698,-137 692,-137 686,-131 686,-125 686,-125 686,-113 686,-113 686,-107 692,-101 698,-101 698,-101 791,-101 791,-101 797,-101 803,-107 803,-113 803,-113 803,-125 803,-125 803,-131 797,-137 791,-137"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-116.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:nextcloud-webapp -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>svc:traefik->svc:nextcloud-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M541.62,-752.85C566.77,-654.11 686,-186 686,-186 686,-186 704.96,-163.91 721.1,-145.1"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="723.93,-147.18 727.79,-137.31 718.62,-142.62 723.93,-147.18"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>svc:node-red</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M767.5,-1217C767.5,-1217 721.5,-1217 721.5,-1217 715.5,-1217 709.5,-1211 709.5,-1205 709.5,-1205 709.5,-1185 709.5,-1185 709.5,-1179 715.5,-1173 721.5,-1173 721.5,-1173 767.5,-1173 767.5,-1173 773.5,-1173 779.5,-1179 779.5,-1185 779.5,-1185 779.5,-1205 779.5,-1205 779.5,-1211 773.5,-1217 767.5,-1217"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1204.2" font-family="Helvetica,sans-Serif" font-size="11.00">node-red</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1192.2" font-family="Helvetica,sans-Serif" font-size="11.00">:1880</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1180.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:node-red -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>svc:traefik->svc:node-red</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M544.29,-789.1C574.2,-863.38 686,-1141 686,-1141 686,-1141 698.77,-1153 712.28,-1165.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1168.43 719.78,-1172.72 714.89,-1163.33 710.1,-1168.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>svc:passbolt-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M787.5,-36C787.5,-36 701.5,-36 701.5,-36 695.5,-36 689.5,-30 689.5,-24 689.5,-24 689.5,-12 689.5,-12 689.5,-6 695.5,0 701.5,0 701.5,0 787.5,0 787.5,0 793.5,0 799.5,-6 799.5,-12 799.5,-12 799.5,-24 799.5,-24 799.5,-30 793.5,-36 787.5,-36"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-15.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:passbolt-webapp -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>svc:traefik->svc:passbolt-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M540.83,-752.92C564.15,-642.88 686,-68 686,-68 686,-68 700.43,-55.45 714.83,-42.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-45.25 722.74,-36.05 712.9,-39.97 717.49,-45.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>svc:portainer</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M766,-478C766,-478 723,-478 723,-478 717,-478 711,-472 711,-466 711,-466 711,-446 711,-446 711,-440 717,-434 723,-434 723,-434 766,-434 766,-434 772,-434 778,-440 778,-446 778,-446 778,-466 778,-466 778,-472 772,-478 766,-478"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-465.2" font-family="Helvetica,sans-Serif" font-size="11.00">portainer</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-453.2" font-family="Helvetica,sans-Serif" font-size="11.00">:9000</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-441.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:portainer -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>svc:traefik->svc:portainer</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M547.48,-752.65C581.39,-693.24 686,-510 686,-510 686,-510 698.77,-498 712.28,-485.32"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="714.89,-487.67 719.78,-478.28 710.1,-482.57 714.89,-487.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>svc:prometheus</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M774,-1108C774,-1108 715,-1108 715,-1108 709,-1108 703,-1102 703,-1096 703,-1096 703,-1076 703,-1076 703,-1070 709,-1064 715,-1064 715,-1064 774,-1064 774,-1064 780,-1064 786,-1070 786,-1076 786,-1076 786,-1096 786,-1096 786,-1102 780,-1108 774,-1108"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1095.2" font-family="Helvetica,sans-Serif" font-size="11.00">prometheus</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1083.2" font-family="Helvetica,sans-Serif" font-size="11.00">:9090</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1071.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:prometheus -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>svc:traefik->svc:prometheus</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M547.48,-789.35C581.39,-848.76 686,-1032 686,-1032 686,-1032 698.77,-1044 712.28,-1056.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1059.43 719.78,-1063.72 714.89,-1054.33 710.1,-1059.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>svc:searxng-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M786,-369C786,-369 703,-369 703,-369 697,-369 691,-363 691,-357 691,-357 691,-345 691,-345 691,-339 697,-333 703,-333 703,-333 786,-333 786,-333 792,-333 798,-339 798,-345 798,-345 798,-357 798,-357 798,-363 792,-369 786,-369"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-348.2" font-family="Helvetica,sans-Serif" font-size="11.00">searxng-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:searxng-webapp -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>svc:traefik->svc:searxng-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M544.29,-752.9C574.2,-678.62 686,-401 686,-401 686,-401 700.43,-388.45 714.83,-375.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-378.25 722.74,-369.05 712.9,-372.97 717.49,-378.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:traefik -->
|
||||||
|
<g id="node36" class="node">
|
||||||
|
<title>net:traefik</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-878" rx="31.04" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-875.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->net:traefik -->
|
||||||
|
<g id="edge55" class="edge">
|
||||||
|
<title>svc:traefik->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M542.75,-752.82C570.13,-666.27 686,-300 686,-300 686,-300 803,-300 803,-300 803,-300 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia->net:traefik -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>svc:authelia->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M775.21,-783.17C824.86,-803.51 924.25,-844.23 975.12,-865.06"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="974.26,-867.36 981.67,-867.75 976.12,-862.83 974.26,-867.36"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:auth.<domain> -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>dns:auth.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="123.5,-1496 25.5,-1496 25.5,-1460 129.5,-1460 129.5,-1490 123.5,-1496"/>
|
||||||
|
<polyline fill="none" stroke="black" points="123.5,-1496 123.5,-1490 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="129.5,-1490 123.5,-1490 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1475.2" font-family="Helvetica,sans-Serif" font-size="11.00">auth.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:auth.<domain>->dynu -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>dns:auth.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1459.95C128.03,-1445.63 155,-1428 155,-1428 155,-1428 286.65,-925.11 319.6,-799.28"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="323.07,-799.82 322.22,-789.26 316.3,-798.05 323.07,-799.82"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea->net:traefik -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>svc:gitea->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M768.56,-688.05C784.55,-703.36 803,-721 803,-721 803,-721 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gitea.<domain> -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>dns:gitea.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="125,-1395 24,-1395 24,-1359 131,-1359 131,-1389 125,-1395"/>
|
||||||
|
<polyline fill="none" stroke="black" points="125,-1395 125,-1389 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="131,-1389 125,-1389 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1374.2" font-family="Helvetica,sans-Serif" font-size="11.00">gitea.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gitea.<domain>->dynu -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>dns:gitea.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1358.95C128.03,-1344.63 155,-1327 155,-1327 155,-1327 283.58,-911.36 318.4,-798.82"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="321.76,-799.77 321.38,-789.18 315.08,-797.7 321.76,-799.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify->net:traefik -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>svc:gotify->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-579.05C782.73,-593.37 803,-611 803,-611 803,-611 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gotify.<domain> -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>dns:gotify.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="126,-1294 23,-1294 23,-1258 132,-1258 132,-1288 126,-1294"/>
|
||||||
|
<polyline fill="none" stroke="black" points="126,-1294 126,-1288 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="132,-1288 126,-1288 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1273.2" font-family="Helvetica,sans-Serif" font-size="11.00">gotify.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gotify.<domain>->dynu -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>dns:gotify.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1257.95C128.03,-1243.63 155,-1226 155,-1226 155,-1226 279.21,-897.41 316.53,-798.71"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="319.89,-799.71 320.15,-789.12 313.34,-797.23 319.89,-799.71"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:monitor -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>net:monitor</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-979" rx="35.46" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-976.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:monitor -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>svc:grafana->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M774.2,-980.78C820.4,-980.43 911.47,-979.73 964.89,-979.32"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="965.19,-981.77 972.17,-979.26 965.15,-976.87 965.19,-981.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:traefik -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>svc:grafana->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M774.2,-969.68C823.41,-950.28 923.53,-910.8 974.83,-890.57"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="975.82,-892.81 981.44,-887.96 974.03,-888.25 975.82,-892.81"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:grafana.<domain> -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>dns:grafana.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="132,-1193 17,-1193 17,-1157 138,-1157 138,-1187 132,-1193"/>
|
||||||
|
<polyline fill="none" stroke="black" points="132,-1193 132,-1187 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="138,-1187 132,-1187 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1172.2" font-family="Helvetica,sans-Serif" font-size="11.00">grafana.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:grafana.<domain>->dynu -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>dns:grafana.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1156.95C128.03,-1142.63 155,-1125 155,-1125 155,-1125 273.61,-880.89 313.84,-798.09"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="317.01,-799.57 318.23,-789.04 310.72,-796.51 317.01,-799.57"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:gramps -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>net:gramps</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-1080" rx="34.76" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-1077.2" font-family="Helvetica,sans-Serif" font-size="11.00">gramps</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:gramps -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>svc:grampsweb->net:gramps</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1491.95C782.73,-1477.63 803,-1460 803,-1460 803,-1460 949.23,-1187.21 993.89,-1103.88"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="996.27,-1104.64 997.41,-1097.32 991.95,-1102.33 996.27,-1104.64"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:traefik -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>svc:grampsweb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1491.95C782.73,-1477.63 803,-1460 803,-1460 803,-1460 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:familytree.<domain> -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>dns:familytree.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="139,-1092 10,-1092 10,-1056 145,-1056 145,-1086 139,-1092"/>
|
||||||
|
<polyline fill="none" stroke="black" points="139,-1092 139,-1086 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="145,-1086 139,-1086 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1071.2" font-family="Helvetica,sans-Serif" font-size="11.00">familytree.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:familytree.<domain>->dynu -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>dns:familytree.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1055.95C128.03,-1041.63 155,-1024 155,-1024 155,-1024 264.64,-862.73 308.84,-797.71"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="311.9,-799.43 314.63,-789.2 306.11,-795.5 311.9,-799.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:monitor -->
|
||||||
|
<g id="edge39" class="edge">
|
||||||
|
<title>svc:influxdb->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M779.65,-889.47C829.7,-909.2 922.46,-945.78 972.53,-965.53"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="971.89,-967.91 979.3,-968.2 973.69,-963.35 971.89,-967.91"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:traefik -->
|
||||||
|
<g id="edge40" class="edge">
|
||||||
|
<title>svc:influxdb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M779.65,-876.26C828.54,-876.64 918.2,-877.32 968.99,-877.71"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="969.17,-880.16 976.19,-877.77 969.21,-875.26 969.17,-880.16"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:influxdb.<domain> -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>dns:influxdb.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="132.5,-991 16.5,-991 16.5,-955 138.5,-955 138.5,-985 132.5,-991"/>
|
||||||
|
<polyline fill="none" stroke="black" points="132.5,-991 132.5,-985 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="138.5,-985 132.5,-985 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-970.2" font-family="Helvetica,sans-Serif" font-size="11.00">influxdb.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:influxdb.<domain>->dynu -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>dns:influxdb.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-954.95C128.03,-940.63 155,-923 155,-923 155,-923 250.14,-838.92 298.91,-795.83"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="301.42,-798.28 306.59,-789.03 296.78,-793.03 301.42,-798.28"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:monitor -->
|
||||||
|
<g id="edge41" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1390.95C782.73,-1376.63 803,-1359 803,-1359 803,-1359 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:traefik -->
|
||||||
|
<g id="edge42" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1390.95C782.73,-1376.63 803,-1359 803,-1359 803,-1359 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:monitor-kuma.<domain> -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>dns:monitor-kuma.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="149,-890 0,-890 0,-854 155,-854 155,-884 149,-890"/>
|
||||||
|
<polyline fill="none" stroke="black" points="149,-890 149,-884 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="155,-884 149,-884 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-869.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor-kuma.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:monitor-kuma.<domain>->dynu -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>dns:monitor-kuma.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M122.93,-853.94C165.02,-836.83 228.32,-811.11 273.25,-792.85"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="274.59,-796.08 282.54,-789.07 271.96,-789.59 274.59,-796.08"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:monitor -->
|
||||||
|
<g id="edge43" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1281.72C785.06,-1266.85 803,-1250 803,-1250 803,-1250 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:traefik -->
|
||||||
|
<g id="edge44" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1281.72C785.06,-1266.85 803,-1250 803,-1250 803,-1250 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:mtls-bridge.<domain> -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>dns:mtls-bridge.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="142,-789 7,-789 7,-753 148,-753 148,-783 142,-789"/>
|
||||||
|
<polyline fill="none" stroke="black" points="142,-789 142,-783 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="148,-783 142,-783 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-768.2" font-family="Helvetica,sans-Serif" font-size="11.00">mtls-bridge.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:mtls-bridge.<domain>->dynu -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>dns:mtls-bridge.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M148.05,-771C182.94,-771 225.03,-771 259.61,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="259.62,-774.5 269.62,-771 259.62,-767.5 259.62,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:nextcloud -->
|
||||||
|
<g id="node34" class="node">
|
||||||
|
<title>net:nextcloud</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-777" rx="42.89" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:nextcloud -->
|
||||||
|
<g id="edge45" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M761.21,-137.31C778.24,-157.15 803,-186 803,-186 803,-186 910,-727 910,-727 910,-727 945.48,-745.35 973.46,-759.81"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="972.67,-762.17 980.02,-763.2 974.92,-757.81 972.67,-762.17"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:traefik -->
|
||||||
|
<g id="edge46" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M761.21,-137.31C778.24,-157.15 803,-186 803,-186 803,-186 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:nextcloud.<domain> -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>dns:nextcloud.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="138,-688 11,-688 11,-652 144,-652 144,-682 138,-688"/>
|
||||||
|
<polyline fill="none" stroke="black" points="138,-688 138,-682 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="144,-682 138,-682 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-667.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:nextcloud.<domain>->dynu -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>dns:nextcloud.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M122.93,-688.06C165.02,-705.17 228.32,-730.89 273.25,-749.15"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="271.96,-752.41 282.54,-752.93 274.59,-745.92 271.96,-752.41"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:monitor -->
|
||||||
|
<g id="edge47" class="edge">
|
||||||
|
<title>svc:node-red->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1172.72C785.06,-1157.85 803,-1141 803,-1141 803,-1141 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:traefik -->
|
||||||
|
<g id="edge48" class="edge">
|
||||||
|
<title>svc:node-red->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1172.72C785.06,-1157.85 803,-1141 803,-1141 803,-1141 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:node-red.<domain> -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>dns:node-red.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="135.5,-587 13.5,-587 13.5,-551 141.5,-551 141.5,-581 135.5,-587"/>
|
||||||
|
<polyline fill="none" stroke="black" points="135.5,-587 135.5,-581 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="141.5,-581 135.5,-581 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-566.2" font-family="Helvetica,sans-Serif" font-size="11.00">node-red.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:node-red.<domain>->dynu -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>dns:node-red.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-587.05C128.03,-601.37 155,-619 155,-619 155,-619 250.14,-703.08 298.91,-746.17"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="296.78,-748.97 306.59,-752.97 301.42,-743.72 296.78,-748.97"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:passbolt -->
|
||||||
|
<g id="node35" class="node">
|
||||||
|
<title>net:passbolt</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-676" rx="37.77" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-673.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:passbolt -->
|
||||||
|
<g id="edge49" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-36.05C782.73,-50.37 803,-68 803,-68 803,-68 960.4,-537.83 998.48,-651.47"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="996.16,-652.27 1000.71,-658.13 1000.81,-650.72 996.16,-652.27"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:traefik -->
|
||||||
|
<g id="edge50" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-36.05C782.73,-50.37 803,-68 803,-68 803,-68 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:passbolt.<domain> -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>dns:passbolt.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="134,-486 15,-486 15,-450 140,-450 140,-480 134,-486"/>
|
||||||
|
<polyline fill="none" stroke="black" points="134,-486 134,-480 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="140,-480 134,-480 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-465.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:passbolt.<domain>->dynu -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>dns:passbolt.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-486.05C128.03,-500.37 155,-518 155,-518 155,-518 264.64,-679.27 308.84,-744.29"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="306.11,-746.5 314.63,-752.8 311.9,-742.57 306.11,-746.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer->net:traefik -->
|
||||||
|
<g id="edge51" class="edge">
|
||||||
|
<title>svc:portainer->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-478.28C785.06,-493.15 803,-510 803,-510 803,-510 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:portainer.<domain> -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>dns:portainer.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="135.5,-385 13.5,-385 13.5,-349 141.5,-349 141.5,-379 135.5,-385"/>
|
||||||
|
<polyline fill="none" stroke="black" points="135.5,-385 135.5,-379 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="141.5,-379 135.5,-379 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-364.2" font-family="Helvetica,sans-Serif" font-size="11.00">portainer.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:portainer.<domain>->dynu -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>dns:portainer.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-385.05C128.03,-399.37 155,-417 155,-417 155,-417 273.61,-661.11 313.84,-743.91"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="310.72,-745.49 318.23,-752.96 317.01,-742.43 310.72,-745.49"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:monitor -->
|
||||||
|
<g id="edge52" class="edge">
|
||||||
|
<title>svc:prometheus->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M786.03,-1069.4C837.48,-1048.32 925.31,-1012.34 973.18,-992.73"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="974.11,-995 979.66,-990.07 972.26,-990.46 974.11,-995"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:traefik -->
|
||||||
|
<g id="edge53" class="edge">
|
||||||
|
<title>svc:prometheus->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1063.72C785.06,-1048.85 803,-1032 803,-1032 803,-1032 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:prometheus.<domain> -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>dns:prometheus.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="144,-284 5,-284 5,-248 150,-248 150,-278 144,-284"/>
|
||||||
|
<polyline fill="none" stroke="black" points="144,-284 144,-278 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="150,-278 144,-278 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-263.2" font-family="Helvetica,sans-Serif" font-size="11.00">prometheus.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:prometheus.<domain>->dynu -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>dns:prometheus.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-284.05C128.03,-298.37 155,-316 155,-316 155,-316 279.21,-644.59 316.53,-743.29"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="313.34,-744.77 320.15,-752.88 319.89,-742.29 313.34,-744.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp->net:traefik -->
|
||||||
|
<g id="edge54" class="edge">
|
||||||
|
<title>svc:searxng-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-369.05C782.73,-383.37 803,-401 803,-401 803,-401 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:searxng.<domain> -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>dns:searxng.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="133,-183 16,-183 16,-147 139,-147 139,-177 133,-183"/>
|
||||||
|
<polyline fill="none" stroke="black" points="133,-183 133,-177 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="139,-177 133,-177 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-162.2" font-family="Helvetica,sans-Serif" font-size="11.00">searxng.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:searxng.<domain>->dynu -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>dns:searxng.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-183.05C128.03,-197.37 155,-215 155,-215 155,-215 283.58,-630.64 318.4,-743.18"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="315.08,-744.3 321.38,-752.82 321.76,-742.23 315.08,-744.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:traefik.<domain> -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>dns:traefik.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="128.5,-82 20.5,-82 20.5,-46 134.5,-46 134.5,-76 128.5,-82"/>
|
||||||
|
<polyline fill="none" stroke="black" points="128.5,-82 128.5,-76 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="134.5,-76 128.5,-76 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-61.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:traefik.<domain>->dynu -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>dns:traefik.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-82.05C128.03,-96.37 155,-114 155,-114 155,-114 286.65,-616.89 319.6,-742.72"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="316.3,-743.95 322.22,-752.74 323.07,-742.18 316.3,-743.95"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
digraph PhysicalTopology {
|
||||||
|
graph [rankdir=LR, fontname="Helvetica", nodesep=1.0, ranksep=1.5];
|
||||||
|
"placeholder:inventory" [shape=note, style="filled", fillcolor="#fef3c7", label="Host inventory JSON not found.\nGenerate terraform inventory and rerun scripts/docs/generate-all.sh\n(--host-inventory <path>)."];
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: PhysicalTopology Pages: 1 -->
|
||||||
|
<svg width="514pt" height="61pt"
|
||||||
|
viewBox="0.00 0.00 514.00 61.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 57)">
|
||||||
|
<title>PhysicalTopology</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-57 510,-57 510,4 -4,4"/>
|
||||||
|
<!-- placeholder:inventory -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>placeholder:inventory</title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="500,-53 0,-53 0,0 506,0 506,-47 500,-53"/>
|
||||||
|
<polyline fill="none" stroke="black" points="500,-53 500,-47 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="506,-47 500,-47 "/>
|
||||||
|
<text text-anchor="middle" x="253" y="-37.8" font-family="Times,serif" font-size="14.00">Host inventory JSON not found.</text>
|
||||||
|
<text text-anchor="middle" x="253" y="-22.8" font-family="Times,serif" font-size="14.00">Generate terraform inventory and rerun scripts/docs/generate-all.sh</text>
|
||||||
|
<text text-anchor="middle" x="253" y="-7.8" font-family="Times,serif" font-size="14.00">(--host-inventory <path>).</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
# Docker Environment
|
||||||
|
|
||||||
|
This environment is orchestrated from central Docker Compose definitions committed in this repository.
|
||||||
|
|
||||||
|
Compose source files are rendered into a resolved configuration during docs generation, then summarized into generated markdown and diagrams.
|
||||||
|
|
||||||
|
Generated outputs:
|
||||||
|
|
||||||
|
- [Compose Inventory](generated/compose-inventory.md)
|
||||||
|
- [Resolved Compose Config](generated/docker-compose.resolved.yml)
|
||||||
|
- [Docker Compose Diagram](diagrams/docker-compose.svg)
|
||||||
|
|
||||||
|
Generated documentation is produced by CI from repository files only. Documentation generation does not start containers.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
default-network.yml
|
||||||
|
apps/gitea/docker-compose.yml
|
||||||
|
apps/gramps/docker-compose.yml
|
||||||
|
apps/nextcloud/docker-compose.yml
|
||||||
|
apps/passbolt/docker-compose.yml
|
||||||
|
apps/searxng/docker-compose.yml
|
||||||
|
apps/shift-recorder/docker-compose.yml
|
||||||
|
apps/stockfill/docker-compose.yml
|
||||||
|
core/authelia/docker-compose.yml
|
||||||
|
core/crowdsec/docker-compose.yml
|
||||||
|
core/error-pages/docker-compose.yml
|
||||||
|
core/test/docker-compose.yml
|
||||||
|
core/traefik/docker-compose.yml
|
||||||
|
monitoring/docker-exporter/docker-compose.yml
|
||||||
|
monitoring/docker-socket-proxy/docker-compose.yml
|
||||||
|
monitoring/gotify/docker-compose.yml
|
||||||
|
monitoring/grafana/docker-compose.yml
|
||||||
|
monitoring/influxdb/docker-compose.yml
|
||||||
|
monitoring/mtls-bridge/docker-compose.yml
|
||||||
|
monitoring/node-exporter/docker-compose.yml
|
||||||
|
monitoring/node-red/docker-compose.yml
|
||||||
|
monitoring/pihole-exporter/docker-compose.yml
|
||||||
|
monitoring/portainer/docker-compose.yml
|
||||||
|
monitoring/prometheus/docker-compose.yml
|
||||||
|
monitoring/telegraf/docker-compose.yml
|
||||||
|
monitoring/uptime-kuma/docker-compose.yml
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Docker Compose Inventory
|
||||||
|
|
||||||
|
Source fingerprint: `0fad36c3fed6`
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Item | Count |
|
||||||
|
|---|---:|
|
||||||
|
| Services | 30 |
|
||||||
|
| Networks | 5 |
|
||||||
|
| Volumes | 0 |
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
| Service | Container | Image | Build | Profiles | Networks | Ports | Restart |
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| authelia | authelia | authelia/authelia | /home/nixos/docker/core/authelia | core, all, authelia, traefik | traefik | | always |
|
||||||
|
| crowdsec | crowdsec | | /home/nixos/docker/core/crowdsec | core, all, crowdsec, traefik | traefik | | always |
|
||||||
|
| docker-socket-proxy | docker-socket-proxy | tecnativa/docker-socket-proxy:latest | | monitoring, all, docker-socket-proxy, core, traefik, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| docker-update-exporter | docker-update-exporter | | /home/nixos/docker/monitoring/docker-exporter | monitoring, all, docker-exporter, prometheus | monitor | | unless-stopped |
|
||||||
|
| error-pages | error-pages | tarampampam/error-pages:3 | | core, all, error-pages, traefik | traefik | | always |
|
||||||
|
| gitea | gitea | gitea/gitea:latest | | apps, all, gitea | traefik | | always |
|
||||||
|
| gitea-runner | gitea-runner | gitea/act_runner:latest | | apps, all, gitea, ci | traefik | | always |
|
||||||
|
| gotify | gotify | gotify/server:latest | | monitoring, all, gotify | traefik | | always |
|
||||||
|
| grafana | grafana | grafana/grafana:latest | | monitoring, all, grafana | monitor, traefik | | unless-stopped |
|
||||||
|
| gramps-redis | gramps-redis | valkey/valkey:8-alpine | | apps, all, gramps | gramps | | always |
|
||||||
|
| grampsweb | gramps-web | ghcr.io/gramps-project/grampsweb:latest | | apps, all, gramps | gramps, traefik | | always |
|
||||||
|
| grampsweb_celery | gramps-web-celery | ghcr.io/gramps-project/grampsweb:latest | | apps, all, gramps | gramps | | always |
|
||||||
|
| influxdb | influxdb | influxdb:2.7 | | monitoring, all, influxdb, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| monitor-kuma | monitor-kuma | louislam/uptime-kuma:2.1.1 | | monitoring, all, uptime-kuma | monitor, traefik | | always |
|
||||||
|
| mtls-bridge | mtls-bridge | | /home/nixos/docker/monitoring/mtls-bridge | monitoring, all, mtls-bridge | monitor, traefik | | unless-stopped |
|
||||||
|
| nextcloud-db | nextcloud-db | mariadb:11.4 | | apps, all, nextcloud | nextcloud | | always |
|
||||||
|
| nextcloud-redis | nextcloud-redis | redis | | apps, all, nextcloud | nextcloud | | always |
|
||||||
|
| nextcloud-webapp | nextcloud-webapp | | /home/nixos/docker/apps/nextcloud | apps, all, nextcloud | nextcloud, traefik | | always |
|
||||||
|
| node-exporter | node-exporter | prom/node-exporter:latest | | monitoring, all, node-exporter, prometheus | monitor | | unless-stopped |
|
||||||
|
| node-red | node-red | | /home/nixos/docker/monitoring/node-red | monitoring, all, node-red | monitor, traefik | | unless-stopped |
|
||||||
|
| passbolt-db | passbolt-db | mariadb:12 | | apps, all, passbolt | passbolt | | always |
|
||||||
|
| passbolt-webapp | passbolt-webapp | passbolt/passbolt:latest-ce | | apps, all, passbolt | passbolt, traefik | | always |
|
||||||
|
| pihole-exporter | pihole-exporter | ekofr/pihole-exporter:latest | | monitoring, all, pihole-exporter, prometheus | monitor | {'mode': 'ingress', 'target': 9617, 'published': '9617', 'protocol': 'tcp'} | unless-stopped |
|
||||||
|
| portainer | portainer | portainer/portainer-ce:latest | | monitoring, all, portainer | traefik | | unless-stopped |
|
||||||
|
| prometheus | prometheus | prom/prometheus:latest | | monitoring, all, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| searxng-webapp | searxng-webapp | searxng/searxng | | apps, all, searxng | traefik | | always |
|
||||||
|
| shift-recorder-web | shift-recorder | | /home/nixos/docker/apps/shift-recorder | apps, all, shift-recorder | traefik | | unless-stopped |
|
||||||
|
| stockfill | stockfill | | /home/nixos/docker/apps/stockfill | apps, all, stockfill | traefik | | unless-stopped |
|
||||||
|
| telegraf | telegraf | telegraf:latest | | monitoring, all, telegraf, prometheus | monitor | | unless-stopped |
|
||||||
|
| traefik | traefik | traefik:3 | /home/nixos/docker/core | core, all, traefik | traefik | {'mode': 'ingress', 'target': 80, 'published': '80', 'protocol': 'tcp'}, {'mode': 'ingress', 'target': 443, 'published': '443', 'protocol': 'tcp'} | always |
|
||||||
|
|
||||||
|
## Networks
|
||||||
|
|
||||||
|
| Network | Driver | External |
|
||||||
|
|---|---|---|
|
||||||
|
| gramps | | False |
|
||||||
|
| monitor | | False |
|
||||||
|
| nextcloud | | False |
|
||||||
|
| passbolt | | False |
|
||||||
|
| traefik | bridge | False |
|
||||||
|
|
||||||
|
## Volumes
|
||||||
|
|
||||||
|
| Volume | External |
|
||||||
|
|---|---|
|
||||||
@@ -3,15 +3,15 @@
|
|||||||
> This integration is intentionally read-only. No Dynu mutations are permitted in this repo at this stage.
|
> This integration is intentionally read-only. No Dynu mutations are permitted in this repo at this stage.
|
||||||
|
|
||||||
- Base domain: `lan.ddnsgeek.com`
|
- Base domain: `lan.ddnsgeek.com`
|
||||||
- Dynu fetched at: `2026-04-21T03:55:09+00:00`
|
- Dynu fetched at: `2026-04-21T04:18:38+00:00`
|
||||||
- Inventory generated at: `2026-04-21T04:08:43+00:00`
|
- Inventory generated at: `2026-04-21T04:18:39+00:00`
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- Traefik hostnames discovered: **15**
|
- Traefik hostnames discovered: **17**
|
||||||
- Dynu hostnames discovered: **20**
|
- Dynu hostnames discovered: **20**
|
||||||
- Mapped hostnames: **15**
|
- Mapped hostnames: **17**
|
||||||
- DNS-only hostnames: **5**
|
- DNS-only hostnames: **3**
|
||||||
- Traefik-only hostnames: **0**
|
- Traefik-only hostnames: **0**
|
||||||
- Ambiguous hostnames: **0**
|
- Ambiguous hostnames: **0**
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
- Validation ok: **false**
|
- Validation ok: **false**
|
||||||
- Allowed unmapped hostnames: `edge.lan.ddnsgeek.com`
|
- Allowed unmapped hostnames: `edge.lan.ddnsgeek.com`
|
||||||
- Unexpected unmapped hostnames: **3**
|
- Unexpected unmapped hostnames: **1**
|
||||||
- Duplicate hostnames: **1**
|
- Duplicate hostnames: **1**
|
||||||
- Ambiguous hostnames: **0**
|
- Ambiguous hostnames: **0**
|
||||||
|
|
||||||
@@ -30,8 +30,6 @@
|
|||||||
### Unexpected unmapped hostnames
|
### Unexpected unmapped hostnames
|
||||||
|
|
||||||
- `kuma.lan.ddnsgeek.com`
|
- `kuma.lan.ddnsgeek.com`
|
||||||
- `shifts.lan.ddnsgeek.com`
|
|
||||||
- `stockfill.lan.ddnsgeek.com`
|
|
||||||
|
|
||||||
### Duplicate hostnames
|
### Duplicate hostnames
|
||||||
|
|
||||||
@@ -62,6 +60,6 @@ _None._
|
|||||||
| `portainer.lan.ddnsgeek.com` | `mapped` | `mapped` | monitoring/portainer | portainer [tls=true, mtls=true, authelia=false, tls_options=mtls-private-admin@file, middlewares=-] | A: |
|
| `portainer.lan.ddnsgeek.com` | `mapped` | `mapped` | monitoring/portainer | portainer [tls=true, mtls=true, authelia=false, tls_options=mtls-private-admin@file, middlewares=-] | A: |
|
||||||
| `prometheus.lan.ddnsgeek.com` | `mapped` | `mapped` | monitoring/prometheus | prometheus [tls=true, mtls=true, authelia=true, tls_options=mtls-private-admin@file, middlewares=authelia] | A: |
|
| `prometheus.lan.ddnsgeek.com` | `mapped` | `mapped` | monitoring/prometheus | prometheus [tls=true, mtls=true, authelia=true, tls_options=mtls-private-admin@file, middlewares=authelia] | A: |
|
||||||
| `searxng.lan.ddnsgeek.com` | `mapped` | `mapped` | apps/searxng-webapp | searxng [tls=true, mtls=false, authelia=false, tls_options=-, middlewares=-] | A: |
|
| `searxng.lan.ddnsgeek.com` | `mapped` | `mapped` | apps/searxng-webapp | searxng [tls=true, mtls=false, authelia=false, tls_options=-, middlewares=-] | A: |
|
||||||
| `shifts.lan.ddnsgeek.com` | `unexpected_unmapped` | `unexpected_unmapped, dns_only` | - | - | A: |
|
| `shifts.lan.ddnsgeek.com` | `mapped` | `mapped` | apps/shift-recorder-web | shifts [tls=true, mtls=false, authelia=false, tls_options=-, middlewares=-] | A: |
|
||||||
| `stockfill.lan.ddnsgeek.com` | `unexpected_unmapped` | `unexpected_unmapped, dns_only` | - | - | A: |
|
| `stockfill.lan.ddnsgeek.com` | `mapped` | `mapped` | apps/stockfill | stockfill [tls=true, mtls=false, authelia=false, tls_options=-, middlewares=-] | A: |
|
||||||
| `traefik.lan.ddnsgeek.com` | `mapped` | `mapped` | core/traefik | traefik [tls=true, mtls=true, authelia=true, tls_options=mtls-private-admin@file, middlewares=authelia] | A: |
|
| `traefik.lan.ddnsgeek.com` | `mapped` | `mapped` | core/traefik | traefik [tls=true, mtls=true, authelia=true, tls_options=mtls-private-admin@file, middlewares=authelia] | A: |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
|||||||
|
# Host Topology
|
||||||
|
|
||||||
|
> Generated by `scripts/docs/generate_host_topology.py` on 2026-05-12T18:32:09+00:00.
|
||||||
|
|
||||||
|
## Topology Diagram
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
phys_pve["pve\nphysical"]
|
||||||
|
phys_raspberrypi["raspberrypi\nphysical"]
|
||||||
|
virt_docker["docker\nvirtual"]
|
||||||
|
phys_pve --> virt_docker
|
||||||
|
virt_nix_cache["nix-cache\nvirtual"]
|
||||||
|
phys_pve --> virt_nix_cache
|
||||||
|
virt_pbs["pbs\nvirtual"]
|
||||||
|
phys_pve --> virt_pbs
|
||||||
|
virt_pihole["pihole\nvirtual"]
|
||||||
|
phys_pve --> virt_pihole
|
||||||
|
virt_server_nixos["server-nixos\nvirtual"]
|
||||||
|
phys_pve --> virt_server_nixos
|
||||||
|
```
|
||||||
|
|
||||||
|
## Physical Hosts
|
||||||
|
|
||||||
|
| Name | Type | Role | Management | OS | Hypervisor | Location | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| pve | physical | proxmox | pve.sweet.home | debian | proxmox | home | Primary Proxmox VE host |
|
||||||
|
| raspberrypi | physical | edge | raspberrypi.tail13f623.ts.net | debian | | riverglades | Raspberry Pi host |
|
||||||
|
|
||||||
|
## Virtual Hosts
|
||||||
|
|
||||||
|
| Name | Type | Role | Parent/Node | Management | OS | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| docker | virtual | docker-host | pve | | linux | Primary Docker VM |
|
||||||
|
| nix-cache | virtual | cache | pve | | linux | Nix binary cache VM |
|
||||||
|
| pbs | virtual | backup | pve | | linux | Proxmox Backup Server VM |
|
||||||
|
| pihole | virtual | dns | pve | | linux | DNS filtering VM |
|
||||||
|
| server-nixos | virtual | nixos-server | pve | | nixos | General-purpose NixOS VM |
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Generated Documentation
|
||||||
|
|
||||||
|
This directory contains documentation generated automatically from repository configuration.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- [Compose file list](compose-files.txt)
|
||||||
|
- [Resolved Docker Compose config](docker-compose.resolved.yml)
|
||||||
|
- [Compose inventory](compose-inventory.md)
|
||||||
|
- [Traefik routes](traefik-routes.md)
|
||||||
|
- [Docker Compose diagram](../diagrams/docker-compose.svg)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Traefik Routes
|
||||||
|
|
||||||
|
| Service | Router | Rule | Entrypoints | TLS | Middlewares | Target Port |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| authelia | authelia | Host(`auth.lan.ddnsgeek.com`) | websecure | true | | |
|
||||||
|
| error-pages | error-pages-router | HostRegexp(`{host:.+}`) | web | | error-pages-middleware | |
|
||||||
|
| gitea | gitea | Host(`gitea.lan.ddnsgeek.com`) | websecure | true | | 3000 |
|
||||||
|
| gotify | gotify | Host(`gotify.lan.ddnsgeek.com`) | websecure | | | 80 |
|
||||||
|
| grafana | grafana | Host(`grafana.lan.ddnsgeek.com`) | websecure | | | 3000 |
|
||||||
|
| grampsweb | gramps | Host(`familytree.lan.ddnsgeek.com`) | websecure | | | 5000 |
|
||||||
|
| influxdb | influxdb | Host(`influxdb.lan.ddnsgeek.com`) | websecure | | authelia | 8086 |
|
||||||
|
| monitor-kuma | monitor | Host(`monitor-kuma.lan.ddnsgeek.com`) | websecure | true | | 3001 |
|
||||||
|
| mtls-bridge | mtls-bridge | Host(`mtls-bridge.lan.ddnsgeek.com`) | websecure | | mtls-bridge-auth,mtls-bridge-cors | 8080 |
|
||||||
|
| mtls-bridge | mtls-bridge-preflight | Host(`mtls-bridge.lan.ddnsgeek.com`) && Method(`OPTIONS`) | websecure | | mtls-bridge-cors | |
|
||||||
|
| nextcloud-webapp | nextcloud | Host(`nextcloud.lan.ddnsgeek.com`) | websecure | | nextcloud-dav, nextcloud-webfinger | |
|
||||||
|
| node-red | node-red | Host(`node-red.lan.ddnsgeek.com`) | websecure | | authelia | 1880 |
|
||||||
|
| passbolt-webapp | passbolt | Host(`passbolt.lan.ddnsgeek.com`) | websecure | | | |
|
||||||
|
| portainer | portainer | Host(`portainer.lan.ddnsgeek.com`) | websecure | true | | 9000 |
|
||||||
|
| prometheus | prometheus | Host(`prometheus.lan.ddnsgeek.com`) | websecure | | authelia | 9090 |
|
||||||
|
| searxng-webapp | searxng | Host(`searxng.lan.ddnsgeek.com`) | websecure | | | 8080 |
|
||||||
|
| shift-recorder-web | shifts | Host(`shifts.lan.ddnsgeek.com`) | websecure | true | | 80 |
|
||||||
|
| stockfill | stockfill | Host(`stockfill.lan.ddnsgeek.com`) | websecure | true | | 80 |
|
||||||
|
| traefik | traefik | Host(`traefik.lan.ddnsgeek.com`) | websecure | | authelia | |
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Infrastructure Documentation
|
||||||
|
|
||||||
|
This documentation describes the Docker-based infrastructure, reverse proxy configuration, monitoring stack, automation services, and generated inventory for this environment.
|
||||||
|
|
||||||
|
Some sections are manually written. Other sections are generated automatically by GitHub Actions from the repository configuration.
|
||||||
|
|
||||||
|
## Sections
|
||||||
|
|
||||||
|
- [Docker Environment](docker.md)
|
||||||
|
- [Networking and Reverse Proxy](networking.md)
|
||||||
|
- [Monitoring and Alerting](monitoring.md)
|
||||||
|
- [Automation](automation.md)
|
||||||
|
- [Operations](operations.md)
|
||||||
|
- [Public Showcase](showcase.md)
|
||||||
|
|
||||||
|
## Generated Documentation
|
||||||
|
|
||||||
|
- [Compose Inventory](generated/compose-inventory.md)
|
||||||
|
- [Traefik Routes](generated/traefik-routes.md)
|
||||||
|
- [Resolved Compose Config](generated/docker-compose.resolved.yml)
|
||||||
|
- [Docker Compose Diagram](diagrams/docker-compose.svg)
|
||||||
|
|
||||||
|
## Public-safe Output
|
||||||
|
|
||||||
|
Sanitized documentation intended for public sharing is generated under:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/public/
|
||||||
|
```
|
||||||
@@ -50,6 +50,12 @@ Compose files define intended service runtime composition, networking, labels, a
|
|||||||
|
|
||||||
Dynu write operations are intentionally blocked in this repository stage.
|
Dynu write operations are intentionally blocked in this repository stage.
|
||||||
|
|
||||||
|
### 7) Terraform Dynu DNS layer
|
||||||
|
|
||||||
|
`infrastructure/terraform/dynu/` is the brownfield Terraform DNS mirror/reconciliation root for Dynu domain/record inventory outputs.
|
||||||
|
|
||||||
|
At this stage it is primarily documentation-oriented catalog output, ready for one-object-at-a-time imports.
|
||||||
|
|
||||||
## Output shaping expectations
|
## Output shaping expectations
|
||||||
|
|
||||||
When adding Terraform outputs for documentation/tooling:
|
When adding Terraform outputs for documentation/tooling:
|
||||||
@@ -61,6 +67,7 @@ When adding Terraform outputs for documentation/tooling:
|
|||||||
|
|
||||||
## Limitations today
|
## Limitations today
|
||||||
|
|
||||||
|
- Generated host topology document: `docs/generated/host-topology.md` (via `scripts/docs/build_host_topology.sh`).
|
||||||
- No full generated inventory document pipeline is present yet.
|
- No full generated inventory document pipeline is present yet.
|
||||||
- Some Terraform files still include generated boilerplate comments requiring ongoing cleanup.
|
- Some Terraform files still include generated boilerplate comments requiring ongoing cleanup.
|
||||||
- Ansible is currently a bootstrap inventory/configuration layer and is not authoritative for full operations yet.
|
- Ansible is currently a bootstrap inventory/configuration layer and is not authoritative for full operations yet.
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Monitoring and Alerting
|
||||||
|
|
||||||
|
Monitoring documentation is generated from static rule files committed in this repository.
|
||||||
|
|
||||||
|
- Prometheus rule files are parsed statically.
|
||||||
|
- Live Prometheus APIs are not queried.
|
||||||
|
- Future improvements can include Grafana dashboard and alert contact-point summaries.
|
||||||
|
|
||||||
|
Generated asset:
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Networking and Reverse Proxy
|
||||||
|
|
||||||
|
Networking and reverse-proxy documentation is generated from Docker Compose metadata.
|
||||||
|
|
||||||
|
- Traefik labels are parsed statically from Compose definitions.
|
||||||
|
- Service-to-network relationships are represented in generated diagrams.
|
||||||
|
- Sensitive internal values are redacted in public-facing output.
|
||||||
|
|
||||||
|
Related generated assets:
|
||||||
|
|
||||||
|
- [Traefik Routes](generated/traefik-routes.md)
|
||||||
|
- [Docker Compose Diagram](diagrams/docker-compose.svg)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Operations
|
||||||
|
|
||||||
|
## Local docs generation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x scripts/docs/*.sh
|
||||||
|
scripts/docs/generate-all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Inspect generated changes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status -- docs/generated docs/diagrams docs/public
|
||||||
|
```
|
||||||
|
|
||||||
|
## GitHub Actions artifacts
|
||||||
|
|
||||||
|
Use the **Generate documentation** workflow run and download the `generated-documentation` artifact from the run summary.
|
||||||
|
|
||||||
|
## Commit behavior
|
||||||
|
|
||||||
|
- Pull requests generate docs and upload artifacts only.
|
||||||
|
- Pushes to `main` generate docs, upload artifacts, and commit generated docs when changes exist.
|
||||||
|
- Manual workflow runs can commit generated docs when enabled through workflow input.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- Confirm required tooling (`python3`, `jq`, `graphviz`, `docker compose`) is available.
|
||||||
|
- Re-run generation after documentation script changes.
|
||||||
|
- Review `docs/public` output for redaction coverage before sharing.
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Docker Compose Inventory
|
||||||
|
|
||||||
|
Source fingerprint: `232be78ef441`
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Item | Count |
|
||||||
|
|---|---:|
|
||||||
|
| Services | 28 |
|
||||||
|
| Networks | 5 |
|
||||||
|
| Volumes | 0 |
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
| Service | Container | Image | Build | Profiles | Networks | Ports | Restart |
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| authelia | authelia | authelia/authelia | /home/nixos/docker/core/authelia | core, all, authelia, traefik | traefik | | always |
|
||||||
|
| crowdsec | crowdsec | | /home/nixos/docker/core/crowdsec | core, all, crowdsec, traefik | traefik | | always |
|
||||||
|
| docker-socket-proxy | docker-socket-proxy | tecnativa/docker-socket-proxy:latest | | monitoring, all, docker-socket-proxy, core, traefik, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| docker-update-exporter | docker-update-exporter | | /home/nixos/docker/monitoring/docker-exporter | monitoring, all, docker-exporter, prometheus | monitor | | unless-stopped |
|
||||||
|
| error-pages | error-pages | tarampampam/error-pages:3 | | core, all, error-pages, traefik | traefik | | always |
|
||||||
|
| gitea | gitea | gitea/gitea:latest | | apps, all, gitea | traefik | | always |
|
||||||
|
| gitea-runner | gitea-runner | gitea/act_runner:latest | | apps, all, gitea, ci | traefik | | always |
|
||||||
|
| gotify | gotify | gotify/server:latest | | monitoring, all, gotify | traefik | | always |
|
||||||
|
| grafana | grafana | grafana/grafana:latest | | monitoring, all, grafana | monitor, traefik | | unless-stopped |
|
||||||
|
| gramps-redis | gramps-redis | valkey/valkey:8-alpine | | apps, all, gramps | gramps | | always |
|
||||||
|
| grampsweb | gramps-web | ghcr.io/gramps-project/grampsweb:latest | | apps, all, gramps | gramps, traefik | | always |
|
||||||
|
| grampsweb_celery | gramps-web-celery | ghcr.io/gramps-project/grampsweb:latest | | apps, all, gramps | gramps | | always |
|
||||||
|
| influxdb | influxdb | influxdb:2.7 | | monitoring, all, influxdb, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| monitor-kuma | monitor-kuma | louislam/uptime-kuma:2.1.1 | | monitoring, all, uptime-kuma | monitor, traefik | | always |
|
||||||
|
| mtls-bridge | mtls-bridge | | /home/nixos/docker/monitoring/mtls-bridge | monitoring, all, mtls-bridge | monitor, traefik | | unless-stopped |
|
||||||
|
| nextcloud-db | nextcloud-db | mariadb:11.4 | | apps, all, nextcloud | nextcloud | | always |
|
||||||
|
| nextcloud-redis | nextcloud-redis | redis | | apps, all, nextcloud | nextcloud | | always |
|
||||||
|
| nextcloud-webapp | nextcloud-webapp | | /home/nixos/docker/apps/nextcloud | apps, all, nextcloud | nextcloud, traefik | | always |
|
||||||
|
| node-exporter | node-exporter | prom/node-exporter:latest | | monitoring, all, node-exporter, prometheus | monitor | | unless-stopped |
|
||||||
|
| node-red | node-red | | /home/nixos/docker/monitoring/node-red | monitoring, all, node-red | monitor, traefik | | unless-stopped |
|
||||||
|
| passbolt-db | passbolt-db | mariadb:12 | | apps, all, passbolt | passbolt | | always |
|
||||||
|
| passbolt-webapp | passbolt-webapp | passbolt/passbolt:latest-ce | | apps, all, passbolt | passbolt, traefik | | always |
|
||||||
|
| pihole-exporter | pihole-exporter | ekofr/pihole-exporter:latest | | monitoring, all, pihole-exporter, prometheus | monitor | {'mode': 'ingress', 'target': 9617, 'published': '9617', 'protocol': 'tcp'} | unless-stopped |
|
||||||
|
| portainer | portainer | portainer/portainer-ce:latest | | monitoring, all, portainer | traefik | | unless-stopped |
|
||||||
|
| prometheus | prometheus | prom/prometheus:latest | | monitoring, all, prometheus | monitor, traefik | | unless-stopped |
|
||||||
|
| searxng-webapp | searxng-webapp | searxng/searxng | | apps, all, searxng | traefik | | always |
|
||||||
|
| telegraf | telegraf | telegraf:latest | | monitoring, all, telegraf, prometheus | monitor | | unless-stopped |
|
||||||
|
| traefik | traefik | traefik:3 | /home/nixos/docker/core | core, all, traefik | traefik | {'mode': 'ingress', 'target': 80, 'published': '80', 'protocol': 'tcp'}, {'mode': 'ingress', 'target': 443, 'published': '443', 'protocol': 'tcp'} | always |
|
||||||
|
|
||||||
|
## Networks
|
||||||
|
|
||||||
|
| Network | Driver | External |
|
||||||
|
|---|---|---|
|
||||||
|
| gramps | | False |
|
||||||
|
| monitor | | False |
|
||||||
|
| nextcloud | | False |
|
||||||
|
| passbolt | | False |
|
||||||
|
| traefik | bridge | False |
|
||||||
|
|
||||||
|
## Volumes
|
||||||
|
|
||||||
|
| Volume | External |
|
||||||
|
|---|---|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Infrastructure diagrams
|
||||||
|
|
||||||
|
## Physical / virtual topology
|
||||||
|
|
||||||
|
This view groups containers by inferred host and service role (edge/proxy/auth, monitoring, automation, apps, and supporting storage/services).
|
||||||
|
|
||||||
|
<div class="diagram-wrap">
|
||||||
|
<img src="physical-topology.svg" alt="Physical topology">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Docker, Traefik and Dynu routing
|
||||||
|
|
||||||
|
This view shows sanitised public DNS names flowing to Traefik, then to exposed Docker services, with backend Docker network membership shown as secondary context.
|
||||||
|
|
||||||
|
_Diagrams are generated from Compose data and Traefik labels._
|
||||||
|
|
||||||
|
<div class="diagram-wrap">
|
||||||
|
<img src="docker-traefik-dynu.svg" alt="Docker Traefik Dynu">
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: Compose Pages: 1 -->
|
||||||
|
<svg width="334pt" height="1502pt"
|
||||||
|
viewBox="0.00 0.00 334.49 1502.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1498)">
|
||||||
|
<title>Compose</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1498 330.49,-1498 330.49,4 -4,4"/>
|
||||||
|
<!-- svc:authelia -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>svc:authelia</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="126,-738 54,-738 54,-702 126,-702 126,-738"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-716.3" font-family="Helvetica,sans-Serif" font-size="14.00">authelia</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:traefik -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>net:traefik</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-774" rx="40.09" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-770.3" font-family="Helvetica,sans-Serif" font-size="14.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia->net:traefik -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>svc:authelia->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M126.41,-730.67C155.5,-739.43 196.8,-751.87 227.69,-761.18"/>
|
||||||
|
<polygon fill="black" stroke="black" points="226.74,-764.55 237.32,-764.08 228.76,-757.85 226.74,-764.55"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:crowdsec -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>svc:crowdsec</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="130.5,-684 49.5,-684 49.5,-648 130.5,-648 130.5,-684"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-662.3" font-family="Helvetica,sans-Serif" font-size="14.00">crowdsec</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:crowdsec->net:traefik -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>svc:crowdsec->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M130.61,-674.06C146.59,-678.3 164.81,-684.44 180,-693 206.25,-707.78 231.35,-731.35 248.38,-749.26"/>
|
||||||
|
<polygon fill="black" stroke="black" points="246.24,-752.1 255.62,-757.03 251.37,-747.33 246.24,-752.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>svc:docker-socket-proxy</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="167.5,-954 12.5,-954 12.5,-918 167.5,-918 167.5,-954"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-932.3" font-family="Helvetica,sans-Serif" font-size="14.00">docker-socket-proxy</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:monitor -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>net:monitor</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-1206" rx="46.29" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-1202.3" font-family="Helvetica,sans-Serif" font-size="14.00">monitor</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy->net:monitor -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>svc:docker-socket-proxy->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M167.53,-953.71C172.02,-956.38 176.24,-959.46 180,-963 242.3,-1021.6 261.83,-1127.12 267.77,-1177.6"/>
|
||||||
|
<polygon fill="black" stroke="black" points="264.31,-1178.21 268.86,-1187.78 271.27,-1177.46 264.31,-1178.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-socket-proxy->net:traefik -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>svc:docker-socket-proxy->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M165.31,-917.9C170.5,-915.32 175.46,-912.37 180,-909 218.01,-880.82 244.97,-831.56 259.03,-800.98"/>
|
||||||
|
<polygon fill="black" stroke="black" points="262.27,-802.31 263.14,-791.76 255.87,-799.46 262.27,-802.31"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-update-exporter -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>svc:docker-update-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="180,-1494 0,-1494 0,-1458 180,-1458 180,-1494"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1472.3" font-family="Helvetica,sans-Serif" font-size="14.00">docker-update-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:docker-update-exporter->net:monitor -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>svc:docker-update-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M168.37,-1457.79C172.55,-1455.23 176.47,-1452.32 180,-1449 242.3,-1390.4 261.83,-1284.88 267.77,-1234.4"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.27,-1234.54 268.86,-1224.22 264.31,-1233.79 271.27,-1234.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:error-pages -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>svc:error-pages</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="137.5,-630 42.5,-630 42.5,-594 137.5,-594 137.5,-630"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-608.3" font-family="Helvetica,sans-Serif" font-size="14.00">error-pages</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:error-pages->net:traefik -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>svc:error-pages->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M137.71,-619.76C152.25,-623.79 167.68,-629.86 180,-639 218.01,-667.18 244.97,-716.44 259.03,-747.02"/>
|
||||||
|
<polygon fill="black" stroke="black" points="255.87,-748.54 263.14,-756.24 262.27,-745.69 255.87,-748.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>svc:gitea</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="117,-576 63,-576 63,-540 117,-540 117,-576"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-554.3" font-family="Helvetica,sans-Serif" font-size="14.00">gitea</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea->net:traefik -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>svc:gitea->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M117.07,-560.28C136.41,-563.2 162.37,-569.85 180,-585 229.98,-627.95 254.42,-704.8 264.44,-746.04"/>
|
||||||
|
<polygon fill="black" stroke="black" points="261.07,-747 266.73,-755.95 267.88,-745.42 261.07,-747"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea-runner -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>svc:gitea-runner</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="142,-522 38,-522 38,-486 142,-486 142,-522"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-500.3" font-family="Helvetica,sans-Serif" font-size="14.00">gitea-runner</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea-runner->net:traefik -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>svc:gitea-runner->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M142.31,-511.04C155.9,-515.03 169.65,-521.26 180,-531 242.3,-589.6 261.83,-695.12 267.77,-745.6"/>
|
||||||
|
<polygon fill="black" stroke="black" points="264.31,-746.21 268.86,-755.78 271.27,-745.46 264.31,-746.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>svc:gotify</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="118,-468 62,-468 62,-432 118,-432 118,-468"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-446.3" font-family="Helvetica,sans-Serif" font-size="14.00">gotify</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify->net:traefik -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>svc:gotify->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M118.17,-451.6C137.81,-454.16 163.67,-460.68 180,-477 254.99,-551.96 268.02,-687.13 270.03,-745.69"/>
|
||||||
|
<polygon fill="black" stroke="black" points="266.53,-745.79 270.29,-755.69 273.53,-745.61 266.53,-745.79"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>svc:grafana</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="125.5,-1278 54.5,-1278 54.5,-1242 125.5,-1242 125.5,-1278"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1256.3" font-family="Helvetica,sans-Serif" font-size="14.00">grafana</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:monitor -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>svc:grafana->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.56,-1249.59C153.74,-1241.1 193.78,-1229.04 224.6,-1219.75"/>
|
||||||
|
<polygon fill="black" stroke="black" points="225.69,-1223.08 234.26,-1216.84 223.67,-1216.38 225.69,-1223.08"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:traefik -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>svc:grafana->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.54,-1257.93C144.23,-1254.97 166.25,-1248.21 180,-1233 238.17,-1168.67 262.1,-892.17 268.43,-802.32"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.93,-802.3 269.13,-792.08 264.95,-801.82 271.93,-802.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gramps-redis -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>svc:gramps-redis</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="144.5,-360 35.5,-360 35.5,-324 144.5,-324 144.5,-360"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-338.3" font-family="Helvetica,sans-Serif" font-size="14.00">gramps-redis</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:gramps -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>net:gramps</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-342" rx="45.49" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-338.3" font-family="Helvetica,sans-Serif" font-size="14.00">gramps</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gramps-redis->net:gramps -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>svc:gramps-redis->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M144.78,-342C167.14,-342 193.05,-342 215.51,-342"/>
|
||||||
|
<polygon fill="black" stroke="black" points="215.56,-345.5 225.56,-342 215.56,-338.5 215.56,-345.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>svc:grampsweb</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="139,-414 41,-414 41,-378 139,-378 139,-414"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-392.3" font-family="Helvetica,sans-Serif" font-size="14.00">grampsweb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:gramps -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>svc:grampsweb->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.03,-381.53C165.7,-373.5 198.68,-363.56 224.9,-355.66"/>
|
||||||
|
<polygon fill="black" stroke="black" points="226.03,-358.98 234.59,-352.74 224.01,-352.27 226.03,-358.98"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:traefik -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>svc:grampsweb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.27,-401.34C154.08,-405.21 169.28,-411.81 180,-423 225.12,-470.09 256.34,-671.08 266.59,-745.84"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.14,-746.48 267.95,-755.92 270.08,-745.55 263.14,-746.48"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb_celery -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>svc:grampsweb_celery</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="163.5,-306 16.5,-306 16.5,-270 163.5,-270 163.5,-306"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-284.3" font-family="Helvetica,sans-Serif" font-size="14.00">grampsweb_celery</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb_celery->net:gramps -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>svc:grampsweb_celery->net:gramps</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-306.13C175.28,-313.39 202.57,-321.61 224.94,-328.35"/>
|
||||||
|
<polygon fill="black" stroke="black" points="223.94,-331.71 234.52,-331.24 225.96,-325 223.94,-331.71"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>svc:influxdb</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="127,-1224 53,-1224 53,-1188 127,-1188 127,-1224"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1202.3" font-family="Helvetica,sans-Serif" font-size="14.00">influxdb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:monitor -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>svc:influxdb->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M127.27,-1206C152.33,-1206 186.13,-1206 214.57,-1206"/>
|
||||||
|
<polygon fill="black" stroke="black" points="214.79,-1209.5 224.79,-1206 214.79,-1202.5 214.79,-1209.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:traefik -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>svc:influxdb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M127.17,-1203.5C145.42,-1200.36 166.5,-1193.56 180,-1179 231.57,-1123.4 259.36,-885.3 267.6,-802.51"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.1,-802.62 268.59,-792.33 264.14,-801.94 271.1,-802.62"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>svc:monitor-kuma</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="146.5,-1170 33.5,-1170 33.5,-1134 146.5,-1134 146.5,-1170"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1148.3" font-family="Helvetica,sans-Serif" font-size="14.00">monitor-kuma</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:monitor -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M146.73,-1168.79C171.73,-1176.32 200.85,-1185.1 224.54,-1192.23"/>
|
||||||
|
<polygon fill="black" stroke="black" points="223.75,-1195.65 234.33,-1195.18 225.77,-1188.94 223.75,-1195.65"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:traefik -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M146.69,-1144.49C159.02,-1140.46 171.06,-1134.33 180,-1125 225.12,-1077.91 256.34,-876.92 266.59,-802.16"/>
|
||||||
|
<polygon fill="black" stroke="black" points="270.08,-802.45 267.95,-792.08 263.14,-801.52 270.08,-802.45"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>svc:mtls-bridge</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="138.5,-1116 41.5,-1116 41.5,-1080 138.5,-1080 138.5,-1116"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1094.3" font-family="Helvetica,sans-Serif" font-size="14.00">mtls-bridge</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:monitor -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M138.76,-1108.34C152.58,-1112.41 167.34,-1117.87 180,-1125 206.25,-1139.78 231.35,-1163.35 248.38,-1181.26"/>
|
||||||
|
<polygon fill="black" stroke="black" points="246.24,-1184.1 255.62,-1189.03 251.37,-1179.33 246.24,-1184.1"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:traefik -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M138.53,-1092.51C153.46,-1088.63 168.92,-1082.07 180,-1071 254.99,-996.04 268.02,-860.87 270.03,-802.31"/>
|
||||||
|
<polygon fill="black" stroke="black" points="273.53,-802.39 270.29,-792.31 266.53,-802.21 273.53,-802.39"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-db -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>svc:nextcloud-db</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="144,-90 36,-90 36,-54 144,-54 144,-90"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-68.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-db</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:nextcloud -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>net:nextcloud</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-180" rx="55.49" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-176.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-db->net:nextcloud -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>svc:nextcloud-db->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M144.33,-84.04C156.48,-87.9 169.03,-92.82 180,-99 206.09,-113.7 231.04,-137.06 248.07,-154.93"/>
|
||||||
|
<polygon fill="black" stroke="black" points="245.93,-157.77 255.31,-162.7 251.06,-153 245.93,-157.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-redis -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>svc:nextcloud-redis</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="152,-198 28,-198 28,-162 152,-162 152,-198"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-176.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-redis</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-redis->net:nextcloud -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>svc:nextcloud-redis->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M152.18,-180C169.48,-180 188.35,-180 205.83,-180"/>
|
||||||
|
<polygon fill="black" stroke="black" points="205.94,-183.5 215.94,-180 205.94,-176.5 205.94,-183.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>svc:nextcloud-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="162.5,-252 17.5,-252 17.5,-216 162.5,-216 162.5,-252"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-230.3" font-family="Helvetica,sans-Serif" font-size="14.00">nextcloud-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:nextcloud -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-215.87C173.57,-209.12 198.72,-201.55 220.11,-195.1"/>
|
||||||
|
<polygon fill="black" stroke="black" points="221.4,-198.37 229.97,-192.13 219.38,-191.67 221.4,-198.37"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:traefik -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M162.89,-247.71C169.31,-251.2 175.18,-255.56 180,-261 212.66,-297.85 255.07,-643.36 267,-745.62"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.55,-746.27 268.18,-755.8 270.51,-745.47 263.55,-746.27"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-exporter -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>svc:node-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="148,-1440 32,-1440 32,-1404 148,-1404 148,-1440"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1418.3" font-family="Helvetica,sans-Serif" font-size="14.00">node-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-exporter->net:monitor -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>svc:node-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M148.25,-1412.27C159.68,-1408.33 170.94,-1402.79 180,-1395 229.98,-1352.05 254.42,-1275.2 264.44,-1233.96"/>
|
||||||
|
<polygon fill="black" stroke="black" points="267.88,-1234.58 266.73,-1224.05 261.07,-1233 267.88,-1234.58"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>svc:node-red</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="129.5,-1062 50.5,-1062 50.5,-1026 129.5,-1026 129.5,-1062"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1040.3" font-family="Helvetica,sans-Serif" font-size="14.00">node-red</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:monitor -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>svc:node-red->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M129.57,-1049.69C146.29,-1053.6 165.34,-1060.13 180,-1071 218.01,-1099.18 244.97,-1148.44 259.03,-1179.02"/>
|
||||||
|
<polygon fill="black" stroke="black" points="255.87,-1180.54 263.14,-1188.24 262.27,-1177.69 255.87,-1180.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:traefik -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>svc:node-red->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M129.95,-1040.03C147.14,-1036.46 166.48,-1029.72 180,-1017 242.3,-958.4 261.83,-852.88 267.77,-802.4"/>
|
||||||
|
<polygon fill="black" stroke="black" points="271.27,-802.54 268.86,-792.22 264.31,-801.79 271.27,-802.54"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-db -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>svc:passbolt-db</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="139,-36 41,-36 41,0 139,0 139,-36"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-14.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt-db</text>
|
||||||
|
</g>
|
||||||
|
<!-- net:passbolt -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>net:passbolt</title>
|
||||||
|
<ellipse fill="#f4f4f4" stroke="black" cx="271.25" cy="-72" rx="48.99" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="271.25" y="-68.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-db->net:passbolt -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>svc:passbolt-db->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="black" d="M139.03,-32.47C165.15,-40.34 197.32,-50.03 223.27,-57.85"/>
|
||||||
|
<polygon fill="black" stroke="black" points="222.3,-61.21 232.88,-60.74 224.32,-54.51 222.3,-61.21"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>svc:passbolt-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="157.5,-144 22.5,-144 22.5,-108 157.5,-108 157.5,-144"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-122.3" font-family="Helvetica,sans-Serif" font-size="14.00">passbolt-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:passbolt -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-107.87C174.64,-100.8 201.13,-92.82 223.16,-86.19"/>
|
||||||
|
<polygon fill="black" stroke="black" points="224.37,-89.48 232.94,-83.24 222.35,-82.77 224.37,-89.48"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:traefik -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M157.85,-136.93C166.26,-140.81 174,-146.02 180,-153 189.88,-164.49 250.79,-625.33 266.53,-745.56"/>
|
||||||
|
<polygon fill="black" stroke="black" points="263.1,-746.33 267.87,-755.8 270.04,-745.43 263.1,-746.33"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:pihole-exporter -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>svc:pihole-exporter</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="151.5,-1386 28.5,-1386 28.5,-1350 151.5,-1350 151.5,-1386"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1364.3" font-family="Helvetica,sans-Serif" font-size="14.00">pihole-exporter</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:pihole-exporter->net:monitor -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>svc:pihole-exporter->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.62,-1355.78C161.68,-1352.07 171.57,-1347.25 180,-1341 218.01,-1312.82 244.97,-1263.56 259.03,-1232.98"/>
|
||||||
|
<polygon fill="black" stroke="black" points="262.27,-1234.31 263.14,-1223.76 255.87,-1231.46 262.27,-1234.31"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>svc:portainer</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="130,-900 50,-900 50,-864 130,-864 130,-900"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-878.3" font-family="Helvetica,sans-Serif" font-size="14.00">portainer</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer->net:traefik -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>svc:portainer->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M130.17,-874.06C146.25,-869.82 164.67,-863.64 180,-855 206.25,-840.22 231.35,-816.65 248.38,-798.74"/>
|
||||||
|
<polygon fill="black" stroke="black" points="251.37,-800.67 255.62,-790.97 246.24,-795.9 251.37,-800.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>svc:prometheus</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="140,-1008 40,-1008 40,-972 140,-972 140,-1008"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-986.3" font-family="Helvetica,sans-Serif" font-size="14.00">prometheus</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:monitor -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>svc:prometheus->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M140.37,-997.26C154.39,-1001.24 168.86,-1007.42 180,-1017 229.98,-1059.95 254.42,-1136.8 264.44,-1178.04"/>
|
||||||
|
<polygon fill="black" stroke="black" points="261.07,-1179 266.73,-1187.95 267.88,-1177.42 261.07,-1179"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:traefik -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>svc:prometheus->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M140.37,-982.74C154.39,-978.76 168.86,-972.58 180,-963 229.98,-920.05 254.42,-843.2 264.44,-801.96"/>
|
||||||
|
<polygon fill="black" stroke="black" points="267.88,-802.58 266.73,-792.05 261.07,-801 267.88,-802.58"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>svc:searxng-webapp</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="156,-846 24,-846 24,-810 156,-810 156,-846"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-824.3" font-family="Helvetica,sans-Serif" font-size="14.00">searxng-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp->net:traefik -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>svc:searxng-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M151.18,-809.87C176.26,-802.32 204.79,-793.72 227.63,-786.84"/>
|
||||||
|
<polygon fill="black" stroke="black" points="228.81,-790.14 237.37,-783.9 226.79,-783.44 228.81,-790.14"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:telegraf -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>svc:telegraf</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="125.5,-1332 54.5,-1332 54.5,-1296 125.5,-1296 125.5,-1332"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-1310.3" font-family="Helvetica,sans-Serif" font-size="14.00">telegraf</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:telegraf->net:monitor -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>svc:telegraf->net:monitor</title>
|
||||||
|
<path fill="none" stroke="black" d="M125.8,-1307.18C142.85,-1302.93 163.26,-1296.43 180,-1287 206.25,-1272.22 231.35,-1248.65 248.38,-1230.74"/>
|
||||||
|
<polygon fill="black" stroke="black" points="251.37,-1232.67 255.62,-1222.97 246.24,-1227.9 251.37,-1232.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>svc:traefik</title>
|
||||||
|
<polygon fill="#dfefff" stroke="black" points="121,-792 59,-792 59,-756 121,-756 121,-792"/>
|
||||||
|
<text text-anchor="middle" x="90" y="-770.3" font-family="Helvetica,sans-Serif" font-size="14.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->net:traefik -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>svc:traefik->net:traefik</title>
|
||||||
|
<path fill="none" stroke="black" d="M121,-774C148.16,-774 188.69,-774 220.66,-774"/>
|
||||||
|
<polygon fill="black" stroke="black" points="220.71,-777.5 230.71,-774 220.71,-770.5 220.71,-777.5"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,611 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: DockerTraefikDynu Pages: 1 -->
|
||||||
|
<svg width="1113pt" height="1536pt"
|
||||||
|
viewBox="0.00 0.00 1113.39 1536.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1532)">
|
||||||
|
<title>DockerTraefikDynu</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-1532 1109.39,-1532 1109.39,4 -4,4"/>
|
||||||
|
<g id="clust2" class="cluster">
|
||||||
|
<title>cluster_networks</title>
|
||||||
|
<path fill="none" stroke="#d1d5db" stroke-dasharray="5,2" d="M922,-650C922,-650 1093.39,-650 1093.39,-650 1099.39,-650 1105.39,-656 1105.39,-662 1105.39,-662 1105.39,-1117 1105.39,-1117 1105.39,-1123 1099.39,-1129 1093.39,-1129 1093.39,-1129 922,-1129 922,-1129 916,-1129 910,-1123 910,-1117 910,-1117 910,-662 910,-662 910,-656 916,-650 922,-650"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-1113.8" font-family="Helvetica,sans-Serif" font-size="14.00">Docker backend networks</text>
|
||||||
|
</g>
|
||||||
|
<!-- dynu -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>dynu</title>
|
||||||
|
<path fill="#fde68a" stroke="black" d="M374,-789C374,-789 282,-789 282,-789 276,-789 270,-783 270,-777 270,-777 270,-765 270,-765 270,-759 276,-753 282,-753 282,-753 374,-753 374,-753 380,-753 386,-759 386,-765 386,-765 386,-777 386,-777 386,-783 380,-789 374,-789"/>
|
||||||
|
<text text-anchor="middle" x="328" y="-768.2" font-family="Helvetica,sans-Serif" font-size="11.00">Dynu / Public DNS</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik -->
|
||||||
|
<g id="node2" class="node">
|
||||||
|
<title>svc:traefik</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M559,-789C559,-789 513,-789 513,-789 507,-789 501,-783 501,-777 501,-777 501,-765 501,-765 501,-759 507,-753 513,-753 513,-753 559,-753 559,-753 565,-753 571,-759 571,-765 571,-765 571,-777 571,-777 571,-783 565,-789 559,-789"/>
|
||||||
|
<text text-anchor="middle" x="536" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik</text>
|
||||||
|
<text text-anchor="middle" x="536" y="-762.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- dynu->svc:traefik -->
|
||||||
|
<g id="edge1" class="edge">
|
||||||
|
<title>dynu->svc:traefik</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.6" d="M386.11,-771C419.13,-771 460.06,-771 490.64,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.6" points="491,-774.5 501,-771 491,-767.5 491,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:traefik -->
|
||||||
|
<g id="edge30" class="edge">
|
||||||
|
<title>svc:traefik->svc:traefik</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M511.86,-789.35C485.91,-817.82 493.95,-854 536,-854 574.1,-854 584.29,-824.29 566.55,-797.52"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="569.07,-795.06 560.14,-789.35 563.55,-799.38 569.07,-795.06"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia -->
|
||||||
|
<g id="node3" class="node">
|
||||||
|
<title>svc:authelia</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M763,-789C763,-789 726,-789 726,-789 720,-789 714,-783 714,-777 714,-777 714,-765 714,-765 714,-759 720,-753 726,-753 726,-753 763,-753 763,-753 769,-753 775,-759 775,-765 775,-765 775,-777 775,-777 775,-783 769,-789 763,-789"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">authelia</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-762.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:authelia -->
|
||||||
|
<g id="edge2" class="edge">
|
||||||
|
<title>svc:traefik->svc:authelia</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-771C607.43,-771 664.91,-771 703.39,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="703.71,-774.5 713.71,-771 703.71,-767.5 703.71,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea -->
|
||||||
|
<g id="node5" class="node">
|
||||||
|
<title>svc:gitea</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M759.5,-688C759.5,-688 729.5,-688 729.5,-688 723.5,-688 717.5,-682 717.5,-676 717.5,-676 717.5,-656 717.5,-656 717.5,-650 723.5,-644 729.5,-644 729.5,-644 759.5,-644 759.5,-644 765.5,-644 771.5,-650 771.5,-656 771.5,-656 771.5,-676 771.5,-676 771.5,-682 765.5,-688 759.5,-688"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-675.2" font-family="Helvetica,sans-Serif" font-size="11.00">gitea</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-663.2" font-family="Helvetica,sans-Serif" font-size="11.00">:3000</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-651.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:gitea -->
|
||||||
|
<g id="edge4" class="edge">
|
||||||
|
<title>svc:traefik->svc:gitea</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-753.66C608.91,-734.44 669.61,-703.57 707.98,-684.06"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="709.89,-687.01 717.22,-679.36 706.72,-680.77 709.89,-687.01"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify -->
|
||||||
|
<g id="node7" class="node">
|
||||||
|
<title>svc:gotify</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M759.5,-579C759.5,-579 729.5,-579 729.5,-579 723.5,-579 717.5,-573 717.5,-567 717.5,-567 717.5,-555 717.5,-555 717.5,-549 723.5,-543 729.5,-543 729.5,-543 759.5,-543 759.5,-543 765.5,-543 771.5,-549 771.5,-555 771.5,-555 771.5,-567 771.5,-567 771.5,-573 765.5,-579 759.5,-579"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-564.2" font-family="Helvetica,sans-Serif" font-size="11.00">gotify</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-552.2" font-family="Helvetica,sans-Serif" font-size="11.00">:80</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:gotify -->
|
||||||
|
<g id="edge6" class="edge">
|
||||||
|
<title>svc:traefik->svc:gotify</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M553.8,-752.96C592.77,-711.11 686,-611 686,-611 686,-611 700.43,-598.45 714.83,-585.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-588.25 722.74,-579.05 712.9,-582.97 717.49,-588.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana -->
|
||||||
|
<g id="node9" class="node">
|
||||||
|
<title>svc:grafana</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M762,-999C762,-999 727,-999 727,-999 721,-999 715,-993 715,-987 715,-987 715,-975 715,-975 715,-969 721,-963 727,-963 727,-963 762,-963 762,-963 768,-963 774,-969 774,-975 774,-975 774,-987 774,-987 774,-993 768,-999 762,-999"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-984.2" font-family="Helvetica,sans-Serif" font-size="11.00">grafana</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-972.2" font-family="Helvetica,sans-Serif" font-size="11.00">:3000</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:grafana -->
|
||||||
|
<g id="edge8" class="edge">
|
||||||
|
<title>svc:traefik->svc:grafana</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M553.8,-789.04C592.77,-830.89 686,-931 686,-931 686,-931 700.43,-943.55 714.83,-956.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-959.03 722.74,-962.95 717.49,-953.75 712.9,-959.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb -->
|
||||||
|
<g id="node11" class="node">
|
||||||
|
<title>svc:grampsweb</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M772.5,-1528C772.5,-1528 716.5,-1528 716.5,-1528 710.5,-1528 704.5,-1522 704.5,-1516 704.5,-1516 704.5,-1504 704.5,-1504 704.5,-1498 710.5,-1492 716.5,-1492 716.5,-1492 772.5,-1492 772.5,-1492 778.5,-1492 784.5,-1498 784.5,-1504 784.5,-1504 784.5,-1516 784.5,-1516 784.5,-1522 778.5,-1528 772.5,-1528"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1507.2" font-family="Helvetica,sans-Serif" font-size="11.00">grampsweb</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:grampsweb -->
|
||||||
|
<g id="edge10" class="edge">
|
||||||
|
<title>svc:traefik->svc:grampsweb</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M540.91,-789.07C564.42,-897.78 686,-1460 686,-1460 686,-1460 700.43,-1472.55 714.83,-1485.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-1488.03 722.74,-1491.95 717.49,-1482.75 712.9,-1488.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb -->
|
||||||
|
<g id="node13" class="node">
|
||||||
|
<title>svc:influxdb</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M767.5,-898C767.5,-898 721.5,-898 721.5,-898 715.5,-898 709.5,-892 709.5,-886 709.5,-886 709.5,-866 709.5,-866 709.5,-860 715.5,-854 721.5,-854 721.5,-854 767.5,-854 767.5,-854 773.5,-854 779.5,-860 779.5,-866 779.5,-866 779.5,-886 779.5,-886 779.5,-892 773.5,-898 767.5,-898"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-885.2" font-family="Helvetica,sans-Serif" font-size="11.00">influxdb</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-873.2" font-family="Helvetica,sans-Serif" font-size="11.00">:8086</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-861.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:influxdb -->
|
||||||
|
<g id="edge12" class="edge">
|
||||||
|
<title>svc:traefik->svc:influxdb</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M571.1,-788.34C606.37,-806.27 661.57,-834.34 699.97,-853.87"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="698.85,-857.22 709.35,-858.64 702.02,-850.98 698.85,-857.22"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma -->
|
||||||
|
<g id="node15" class="node">
|
||||||
|
<title>svc:monitor-kuma</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M778.5,-1427C778.5,-1427 710.5,-1427 710.5,-1427 704.5,-1427 698.5,-1421 698.5,-1415 698.5,-1415 698.5,-1403 698.5,-1403 698.5,-1397 704.5,-1391 710.5,-1391 710.5,-1391 778.5,-1391 778.5,-1391 784.5,-1391 790.5,-1397 790.5,-1403 790.5,-1403 790.5,-1415 790.5,-1415 790.5,-1421 784.5,-1427 778.5,-1427"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1412.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor-kuma</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1400.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:monitor-kuma -->
|
||||||
|
<g id="edge14" class="edge">
|
||||||
|
<title>svc:traefik->svc:monitor-kuma</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M541.62,-789.24C566.77,-888.49 686,-1359 686,-1359 686,-1359 700.43,-1371.55 714.83,-1384.07"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="712.9,-1387.03 722.74,-1390.95 717.49,-1381.75 712.9,-1387.03"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge -->
|
||||||
|
<g id="node17" class="node">
|
||||||
|
<title>svc:mtls-bridge</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M772,-1326C772,-1326 717,-1326 717,-1326 711,-1326 705,-1320 705,-1314 705,-1314 705,-1294 705,-1294 705,-1288 711,-1282 717,-1282 717,-1282 772,-1282 772,-1282 778,-1282 784,-1288 784,-1294 784,-1294 784,-1314 784,-1314 784,-1320 778,-1326 772,-1326"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1313.2" font-family="Helvetica,sans-Serif" font-size="11.00">mtls-bridge</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1301.2" font-family="Helvetica,sans-Serif" font-size="11.00">:8080</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1289.2" font-family="Helvetica,sans-Serif" font-size="11.00">[mTLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:mtls-bridge -->
|
||||||
|
<g id="edge16" class="edge">
|
||||||
|
<title>svc:traefik->svc:mtls-bridge</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M542.66,-789.19C569.88,-876.69 686,-1250 686,-1250 686,-1250 698.77,-1262 712.28,-1274.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1277.43 719.78,-1281.72 714.89,-1272.33 710.1,-1277.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp -->
|
||||||
|
<g id="node19" class="node">
|
||||||
|
<title>svc:nextcloud-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M791,-137C791,-137 698,-137 698,-137 692,-137 686,-131 686,-125 686,-125 686,-113 686,-113 686,-107 692,-101 698,-101 698,-101 791,-101 791,-101 797,-101 803,-107 803,-113 803,-113 803,-125 803,-125 803,-131 797,-137 791,-137"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-116.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:nextcloud-webapp -->
|
||||||
|
<g id="edge18" class="edge">
|
||||||
|
<title>svc:traefik->svc:nextcloud-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M541.62,-752.85C566.77,-654.11 686,-186 686,-186 686,-186 704.96,-163.91 721.1,-145.1"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="723.93,-147.18 727.79,-137.31 718.62,-142.62 723.93,-147.18"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red -->
|
||||||
|
<g id="node21" class="node">
|
||||||
|
<title>svc:node-red</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M767.5,-1217C767.5,-1217 721.5,-1217 721.5,-1217 715.5,-1217 709.5,-1211 709.5,-1205 709.5,-1205 709.5,-1185 709.5,-1185 709.5,-1179 715.5,-1173 721.5,-1173 721.5,-1173 767.5,-1173 767.5,-1173 773.5,-1173 779.5,-1179 779.5,-1185 779.5,-1185 779.5,-1205 779.5,-1205 779.5,-1211 773.5,-1217 767.5,-1217"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1204.2" font-family="Helvetica,sans-Serif" font-size="11.00">node-red</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1192.2" font-family="Helvetica,sans-Serif" font-size="11.00">:1880</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1180.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:node-red -->
|
||||||
|
<g id="edge20" class="edge">
|
||||||
|
<title>svc:traefik->svc:node-red</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M544.29,-789.1C574.2,-863.38 686,-1141 686,-1141 686,-1141 698.77,-1153 712.28,-1165.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1168.43 719.78,-1172.72 714.89,-1163.33 710.1,-1168.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp -->
|
||||||
|
<g id="node23" class="node">
|
||||||
|
<title>svc:passbolt-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M787.5,-36C787.5,-36 701.5,-36 701.5,-36 695.5,-36 689.5,-30 689.5,-24 689.5,-24 689.5,-12 689.5,-12 689.5,-6 695.5,0 701.5,0 701.5,0 787.5,0 787.5,0 793.5,0 799.5,-6 799.5,-12 799.5,-12 799.5,-24 799.5,-24 799.5,-30 793.5,-36 787.5,-36"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-15.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:passbolt-webapp -->
|
||||||
|
<g id="edge22" class="edge">
|
||||||
|
<title>svc:traefik->svc:passbolt-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M540.83,-752.92C564.15,-642.88 686,-68 686,-68 686,-68 700.43,-55.45 714.83,-42.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-45.25 722.74,-36.05 712.9,-39.97 717.49,-45.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer -->
|
||||||
|
<g id="node25" class="node">
|
||||||
|
<title>svc:portainer</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M766,-478C766,-478 723,-478 723,-478 717,-478 711,-472 711,-466 711,-466 711,-446 711,-446 711,-440 717,-434 723,-434 723,-434 766,-434 766,-434 772,-434 778,-440 778,-446 778,-446 778,-466 778,-466 778,-472 772,-478 766,-478"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-465.2" font-family="Helvetica,sans-Serif" font-size="11.00">portainer</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-453.2" font-family="Helvetica,sans-Serif" font-size="11.00">:9000</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-441.2" font-family="Helvetica,sans-Serif" font-size="11.00">[TLS]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:portainer -->
|
||||||
|
<g id="edge24" class="edge">
|
||||||
|
<title>svc:traefik->svc:portainer</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M547.48,-752.65C581.39,-693.24 686,-510 686,-510 686,-510 698.77,-498 712.28,-485.32"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="714.89,-487.67 719.78,-478.28 710.1,-482.57 714.89,-487.67"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus -->
|
||||||
|
<g id="node27" class="node">
|
||||||
|
<title>svc:prometheus</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M774,-1108C774,-1108 715,-1108 715,-1108 709,-1108 703,-1102 703,-1096 703,-1096 703,-1076 703,-1076 703,-1070 709,-1064 715,-1064 715,-1064 774,-1064 774,-1064 780,-1064 786,-1070 786,-1076 786,-1076 786,-1096 786,-1096 786,-1102 780,-1108 774,-1108"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1095.2" font-family="Helvetica,sans-Serif" font-size="11.00">prometheus</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1083.2" font-family="Helvetica,sans-Serif" font-size="11.00">:9090</text>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-1071.2" font-family="Helvetica,sans-Serif" font-size="11.00">[authelia]</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:prometheus -->
|
||||||
|
<g id="edge26" class="edge">
|
||||||
|
<title>svc:traefik->svc:prometheus</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M547.48,-789.35C581.39,-848.76 686,-1032 686,-1032 686,-1032 698.77,-1044 712.28,-1056.68"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="710.1,-1059.43 719.78,-1063.72 714.89,-1054.33 710.1,-1059.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp -->
|
||||||
|
<g id="node29" class="node">
|
||||||
|
<title>svc:searxng-webapp</title>
|
||||||
|
<path fill="#dcfce7" stroke="black" d="M786,-369C786,-369 703,-369 703,-369 697,-369 691,-363 691,-357 691,-357 691,-345 691,-345 691,-339 697,-333 703,-333 703,-333 786,-333 786,-333 792,-333 798,-339 798,-345 798,-345 798,-357 798,-357 798,-363 792,-369 786,-369"/>
|
||||||
|
<text text-anchor="middle" x="744.5" y="-348.2" font-family="Helvetica,sans-Serif" font-size="11.00">searxng-webapp</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->svc:searxng-webapp -->
|
||||||
|
<g id="edge28" class="edge">
|
||||||
|
<title>svc:traefik->svc:searxng-webapp</title>
|
||||||
|
<path fill="none" stroke="#334155" stroke-width="1.4" d="M544.29,-752.9C574.2,-678.62 686,-401 686,-401 686,-401 700.43,-388.45 714.83,-375.93"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" stroke-width="1.4" points="717.49,-378.25 722.74,-369.05 712.9,-372.97 717.49,-378.25"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:traefik -->
|
||||||
|
<g id="node36" class="node">
|
||||||
|
<title>net:traefik</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-878" rx="31.04" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-875.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:traefik->net:traefik -->
|
||||||
|
<g id="edge55" class="edge">
|
||||||
|
<title>svc:traefik->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M542.75,-752.82C570.13,-666.27 686,-300 686,-300 686,-300 803,-300 803,-300 803,-300 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:authelia->net:traefik -->
|
||||||
|
<g id="edge32" class="edge">
|
||||||
|
<title>svc:authelia->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M775.21,-783.17C824.86,-803.51 924.25,-844.23 975.12,-865.06"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="974.26,-867.36 981.67,-867.75 976.12,-862.83 974.26,-867.36"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:auth.<domain> -->
|
||||||
|
<g id="node4" class="node">
|
||||||
|
<title>dns:auth.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="123.5,-1496 25.5,-1496 25.5,-1460 129.5,-1460 129.5,-1490 123.5,-1496"/>
|
||||||
|
<polyline fill="none" stroke="black" points="123.5,-1496 123.5,-1490 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="129.5,-1490 123.5,-1490 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1475.2" font-family="Helvetica,sans-Serif" font-size="11.00">auth.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:auth.<domain>->dynu -->
|
||||||
|
<g id="edge3" class="edge">
|
||||||
|
<title>dns:auth.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1459.95C128.03,-1445.63 155,-1428 155,-1428 155,-1428 286.65,-925.11 319.6,-799.28"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="323.07,-799.82 322.22,-789.26 316.3,-798.05 323.07,-799.82"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gitea->net:traefik -->
|
||||||
|
<g id="edge33" class="edge">
|
||||||
|
<title>svc:gitea->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M768.56,-688.05C784.55,-703.36 803,-721 803,-721 803,-721 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gitea.<domain> -->
|
||||||
|
<g id="node6" class="node">
|
||||||
|
<title>dns:gitea.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="125,-1395 24,-1395 24,-1359 131,-1359 131,-1389 125,-1395"/>
|
||||||
|
<polyline fill="none" stroke="black" points="125,-1395 125,-1389 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="131,-1389 125,-1389 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1374.2" font-family="Helvetica,sans-Serif" font-size="11.00">gitea.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gitea.<domain>->dynu -->
|
||||||
|
<g id="edge5" class="edge">
|
||||||
|
<title>dns:gitea.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1358.95C128.03,-1344.63 155,-1327 155,-1327 155,-1327 283.58,-911.36 318.4,-798.82"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="321.76,-799.77 321.38,-789.18 315.08,-797.7 321.76,-799.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:gotify->net:traefik -->
|
||||||
|
<g id="edge34" class="edge">
|
||||||
|
<title>svc:gotify->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-579.05C782.73,-593.37 803,-611 803,-611 803,-611 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gotify.<domain> -->
|
||||||
|
<g id="node8" class="node">
|
||||||
|
<title>dns:gotify.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="126,-1294 23,-1294 23,-1258 132,-1258 132,-1288 126,-1294"/>
|
||||||
|
<polyline fill="none" stroke="black" points="126,-1294 126,-1288 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="132,-1288 126,-1288 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1273.2" font-family="Helvetica,sans-Serif" font-size="11.00">gotify.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:gotify.<domain>->dynu -->
|
||||||
|
<g id="edge7" class="edge">
|
||||||
|
<title>dns:gotify.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1257.95C128.03,-1243.63 155,-1226 155,-1226 155,-1226 279.21,-897.41 316.53,-798.71"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="319.89,-799.71 320.15,-789.12 313.34,-797.23 319.89,-799.71"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:monitor -->
|
||||||
|
<g id="node33" class="node">
|
||||||
|
<title>net:monitor</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-979" rx="35.46" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-976.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:monitor -->
|
||||||
|
<g id="edge35" class="edge">
|
||||||
|
<title>svc:grafana->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M774.2,-980.78C820.4,-980.43 911.47,-979.73 964.89,-979.32"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="965.19,-981.77 972.17,-979.26 965.15,-976.87 965.19,-981.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grafana->net:traefik -->
|
||||||
|
<g id="edge36" class="edge">
|
||||||
|
<title>svc:grafana->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M774.2,-969.68C823.41,-950.28 923.53,-910.8 974.83,-890.57"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="975.82,-892.81 981.44,-887.96 974.03,-888.25 975.82,-892.81"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:grafana.<domain> -->
|
||||||
|
<g id="node10" class="node">
|
||||||
|
<title>dns:grafana.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="132,-1193 17,-1193 17,-1157 138,-1157 138,-1187 132,-1193"/>
|
||||||
|
<polyline fill="none" stroke="black" points="132,-1193 132,-1187 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="138,-1187 132,-1187 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1172.2" font-family="Helvetica,sans-Serif" font-size="11.00">grafana.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:grafana.<domain>->dynu -->
|
||||||
|
<g id="edge9" class="edge">
|
||||||
|
<title>dns:grafana.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1156.95C128.03,-1142.63 155,-1125 155,-1125 155,-1125 273.61,-880.89 313.84,-798.09"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="317.01,-799.57 318.23,-789.04 310.72,-796.51 317.01,-799.57"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:gramps -->
|
||||||
|
<g id="node32" class="node">
|
||||||
|
<title>net:gramps</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-1080" rx="34.76" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-1077.2" font-family="Helvetica,sans-Serif" font-size="11.00">gramps</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:gramps -->
|
||||||
|
<g id="edge37" class="edge">
|
||||||
|
<title>svc:grampsweb->net:gramps</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1491.95C782.73,-1477.63 803,-1460 803,-1460 803,-1460 949.23,-1187.21 993.89,-1103.88"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="996.27,-1104.64 997.41,-1097.32 991.95,-1102.33 996.27,-1104.64"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:grampsweb->net:traefik -->
|
||||||
|
<g id="edge38" class="edge">
|
||||||
|
<title>svc:grampsweb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1491.95C782.73,-1477.63 803,-1460 803,-1460 803,-1460 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:familytree.<domain> -->
|
||||||
|
<g id="node12" class="node">
|
||||||
|
<title>dns:familytree.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="139,-1092 10,-1092 10,-1056 145,-1056 145,-1086 139,-1092"/>
|
||||||
|
<polyline fill="none" stroke="black" points="139,-1092 139,-1086 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="145,-1086 139,-1086 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-1071.2" font-family="Helvetica,sans-Serif" font-size="11.00">familytree.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:familytree.<domain>->dynu -->
|
||||||
|
<g id="edge11" class="edge">
|
||||||
|
<title>dns:familytree.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-1055.95C128.03,-1041.63 155,-1024 155,-1024 155,-1024 264.64,-862.73 308.84,-797.71"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="311.9,-799.43 314.63,-789.2 306.11,-795.5 311.9,-799.43"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:monitor -->
|
||||||
|
<g id="edge39" class="edge">
|
||||||
|
<title>svc:influxdb->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M779.65,-889.47C829.7,-909.2 922.46,-945.78 972.53,-965.53"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="971.89,-967.91 979.3,-968.2 973.69,-963.35 971.89,-967.91"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:influxdb->net:traefik -->
|
||||||
|
<g id="edge40" class="edge">
|
||||||
|
<title>svc:influxdb->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M779.65,-876.26C828.54,-876.64 918.2,-877.32 968.99,-877.71"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="969.17,-880.16 976.19,-877.77 969.21,-875.26 969.17,-880.16"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:influxdb.<domain> -->
|
||||||
|
<g id="node14" class="node">
|
||||||
|
<title>dns:influxdb.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="132.5,-991 16.5,-991 16.5,-955 138.5,-955 138.5,-985 132.5,-991"/>
|
||||||
|
<polyline fill="none" stroke="black" points="132.5,-991 132.5,-985 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="138.5,-985 132.5,-985 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-970.2" font-family="Helvetica,sans-Serif" font-size="11.00">influxdb.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:influxdb.<domain>->dynu -->
|
||||||
|
<g id="edge13" class="edge">
|
||||||
|
<title>dns:influxdb.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-954.95C128.03,-940.63 155,-923 155,-923 155,-923 250.14,-838.92 298.91,-795.83"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="301.42,-798.28 306.59,-789.03 296.78,-793.03 301.42,-798.28"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:monitor -->
|
||||||
|
<g id="edge41" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1390.95C782.73,-1376.63 803,-1359 803,-1359 803,-1359 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:monitor-kuma->net:traefik -->
|
||||||
|
<g id="edge42" class="edge">
|
||||||
|
<title>svc:monitor-kuma->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-1390.95C782.73,-1376.63 803,-1359 803,-1359 803,-1359 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:monitor-kuma.<domain> -->
|
||||||
|
<g id="node16" class="node">
|
||||||
|
<title>dns:monitor-kuma.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="149,-890 0,-890 0,-854 155,-854 155,-884 149,-890"/>
|
||||||
|
<polyline fill="none" stroke="black" points="149,-890 149,-884 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="155,-884 149,-884 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-869.2" font-family="Helvetica,sans-Serif" font-size="11.00">monitor-kuma.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:monitor-kuma.<domain>->dynu -->
|
||||||
|
<g id="edge15" class="edge">
|
||||||
|
<title>dns:monitor-kuma.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M122.93,-853.94C165.02,-836.83 228.32,-811.11 273.25,-792.85"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="274.59,-796.08 282.54,-789.07 271.96,-789.59 274.59,-796.08"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:monitor -->
|
||||||
|
<g id="edge43" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1281.72C785.06,-1266.85 803,-1250 803,-1250 803,-1250 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:mtls-bridge->net:traefik -->
|
||||||
|
<g id="edge44" class="edge">
|
||||||
|
<title>svc:mtls-bridge->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1281.72C785.06,-1266.85 803,-1250 803,-1250 803,-1250 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:mtls-bridge.<domain> -->
|
||||||
|
<g id="node18" class="node">
|
||||||
|
<title>dns:mtls-bridge.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="142,-789 7,-789 7,-753 148,-753 148,-783 142,-789"/>
|
||||||
|
<polyline fill="none" stroke="black" points="142,-789 142,-783 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="148,-783 142,-783 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-768.2" font-family="Helvetica,sans-Serif" font-size="11.00">mtls-bridge.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:mtls-bridge.<domain>->dynu -->
|
||||||
|
<g id="edge17" class="edge">
|
||||||
|
<title>dns:mtls-bridge.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M148.05,-771C182.94,-771 225.03,-771 259.61,-771"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="259.62,-774.5 269.62,-771 259.62,-767.5 259.62,-774.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:nextcloud -->
|
||||||
|
<g id="node34" class="node">
|
||||||
|
<title>net:nextcloud</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-777" rx="42.89" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-774.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:nextcloud -->
|
||||||
|
<g id="edge45" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:nextcloud</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M761.21,-137.31C778.24,-157.15 803,-186 803,-186 803,-186 910,-727 910,-727 910,-727 945.48,-745.35 973.46,-759.81"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="972.67,-762.17 980.02,-763.2 974.92,-757.81 972.67,-762.17"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:nextcloud-webapp->net:traefik -->
|
||||||
|
<g id="edge46" class="edge">
|
||||||
|
<title>svc:nextcloud-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M761.21,-137.31C778.24,-157.15 803,-186 803,-186 803,-186 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:nextcloud.<domain> -->
|
||||||
|
<g id="node20" class="node">
|
||||||
|
<title>dns:nextcloud.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="138,-688 11,-688 11,-652 144,-652 144,-682 138,-688"/>
|
||||||
|
<polyline fill="none" stroke="black" points="138,-688 138,-682 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="144,-682 138,-682 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-667.2" font-family="Helvetica,sans-Serif" font-size="11.00">nextcloud.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:nextcloud.<domain>->dynu -->
|
||||||
|
<g id="edge19" class="edge">
|
||||||
|
<title>dns:nextcloud.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M122.93,-688.06C165.02,-705.17 228.32,-730.89 273.25,-749.15"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="271.96,-752.41 282.54,-752.93 274.59,-745.92 271.96,-752.41"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:monitor -->
|
||||||
|
<g id="edge47" class="edge">
|
||||||
|
<title>svc:node-red->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1172.72C785.06,-1157.85 803,-1141 803,-1141 803,-1141 910,-1030 910,-1030 910,-1030 947.73,-1010.1 976.05,-995.16"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="977.25,-997.3 982.29,-991.87 974.96,-992.97 977.25,-997.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:node-red->net:traefik -->
|
||||||
|
<g id="edge48" class="edge">
|
||||||
|
<title>svc:node-red->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1172.72C785.06,-1157.85 803,-1141 803,-1141 803,-1141 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:node-red.<domain> -->
|
||||||
|
<g id="node22" class="node">
|
||||||
|
<title>dns:node-red.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="135.5,-587 13.5,-587 13.5,-551 141.5,-551 141.5,-581 135.5,-587"/>
|
||||||
|
<polyline fill="none" stroke="black" points="135.5,-587 135.5,-581 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="141.5,-581 135.5,-581 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-566.2" font-family="Helvetica,sans-Serif" font-size="11.00">node-red.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:node-red.<domain>->dynu -->
|
||||||
|
<g id="edge21" class="edge">
|
||||||
|
<title>dns:node-red.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-587.05C128.03,-601.37 155,-619 155,-619 155,-619 250.14,-703.08 298.91,-746.17"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="296.78,-748.97 306.59,-752.97 301.42,-743.72 296.78,-748.97"/>
|
||||||
|
</g>
|
||||||
|
<!-- net:passbolt -->
|
||||||
|
<g id="node35" class="node">
|
||||||
|
<title>net:passbolt</title>
|
||||||
|
<ellipse fill="#f8fafc" stroke="black" cx="1007.69" cy="-676" rx="37.77" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="1007.69" y="-673.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt</text>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:passbolt -->
|
||||||
|
<g id="edge49" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:passbolt</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-36.05C782.73,-50.37 803,-68 803,-68 803,-68 960.4,-537.83 998.48,-651.47"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="996.16,-652.27 1000.71,-658.13 1000.81,-650.72 996.16,-652.27"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:passbolt-webapp->net:traefik -->
|
||||||
|
<g id="edge50" class="edge">
|
||||||
|
<title>svc:passbolt-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-36.05C782.73,-50.37 803,-68 803,-68 803,-68 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:passbolt.<domain> -->
|
||||||
|
<g id="node24" class="node">
|
||||||
|
<title>dns:passbolt.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="134,-486 15,-486 15,-450 140,-450 140,-480 134,-486"/>
|
||||||
|
<polyline fill="none" stroke="black" points="134,-486 134,-480 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="140,-480 134,-480 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-465.2" font-family="Helvetica,sans-Serif" font-size="11.00">passbolt.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:passbolt.<domain>->dynu -->
|
||||||
|
<g id="edge23" class="edge">
|
||||||
|
<title>dns:passbolt.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-486.05C128.03,-500.37 155,-518 155,-518 155,-518 264.64,-679.27 308.84,-744.29"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="306.11,-746.5 314.63,-752.8 311.9,-742.57 306.11,-746.5"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:portainer->net:traefik -->
|
||||||
|
<g id="edge51" class="edge">
|
||||||
|
<title>svc:portainer->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-478.28C785.06,-493.15 803,-510 803,-510 803,-510 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:portainer.<domain> -->
|
||||||
|
<g id="node26" class="node">
|
||||||
|
<title>dns:portainer.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="135.5,-385 13.5,-385 13.5,-349 141.5,-349 141.5,-379 135.5,-385"/>
|
||||||
|
<polyline fill="none" stroke="black" points="135.5,-385 135.5,-379 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="141.5,-379 135.5,-379 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-364.2" font-family="Helvetica,sans-Serif" font-size="11.00">portainer.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:portainer.<domain>->dynu -->
|
||||||
|
<g id="edge25" class="edge">
|
||||||
|
<title>dns:portainer.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-385.05C128.03,-399.37 155,-417 155,-417 155,-417 273.61,-661.11 313.84,-743.91"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="310.72,-745.49 318.23,-752.96 317.01,-742.43 310.72,-745.49"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:monitor -->
|
||||||
|
<g id="edge52" class="edge">
|
||||||
|
<title>svc:prometheus->net:monitor</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M786.03,-1069.4C837.48,-1048.32 925.31,-1012.34 973.18,-992.73"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="974.11,-995 979.66,-990.07 972.26,-990.46 974.11,-995"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:prometheus->net:traefik -->
|
||||||
|
<g id="edge53" class="edge">
|
||||||
|
<title>svc:prometheus->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M769.22,-1063.72C785.06,-1048.85 803,-1032 803,-1032 803,-1032 910,-929 910,-929 910,-929 949.05,-908.4 977.52,-893.39"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="978.73,-895.52 983.78,-890.09 976.45,-891.18 978.73,-895.52"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:prometheus.<domain> -->
|
||||||
|
<g id="node28" class="node">
|
||||||
|
<title>dns:prometheus.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="144,-284 5,-284 5,-248 150,-248 150,-278 144,-284"/>
|
||||||
|
<polyline fill="none" stroke="black" points="144,-284 144,-278 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="150,-278 144,-278 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-263.2" font-family="Helvetica,sans-Serif" font-size="11.00">prometheus.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:prometheus.<domain>->dynu -->
|
||||||
|
<g id="edge27" class="edge">
|
||||||
|
<title>dns:prometheus.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-284.05C128.03,-298.37 155,-316 155,-316 155,-316 279.21,-644.59 316.53,-743.29"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="313.34,-744.77 320.15,-752.88 319.89,-742.29 313.34,-744.77"/>
|
||||||
|
</g>
|
||||||
|
<!-- svc:searxng-webapp->net:traefik -->
|
||||||
|
<g id="edge54" class="edge">
|
||||||
|
<title>svc:searxng-webapp->net:traefik</title>
|
||||||
|
<path fill="none" stroke="#94a3b8" stroke-dasharray="5,2" d="M766.26,-369.05C782.73,-383.37 803,-401 803,-401 803,-401 910,-828 910,-828 910,-828 949.05,-848.19 977.52,-862.92"/>
|
||||||
|
<polygon fill="#94a3b8" stroke="#94a3b8" points="976.44,-865.11 983.78,-866.15 978.69,-860.76 976.44,-865.11"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:searxng.<domain> -->
|
||||||
|
<g id="node30" class="node">
|
||||||
|
<title>dns:searxng.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="133,-183 16,-183 16,-147 139,-147 139,-177 133,-183"/>
|
||||||
|
<polyline fill="none" stroke="black" points="133,-183 133,-177 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="139,-177 133,-177 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-162.2" font-family="Helvetica,sans-Serif" font-size="11.00">searxng.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:searxng.<domain>->dynu -->
|
||||||
|
<g id="edge29" class="edge">
|
||||||
|
<title>dns:searxng.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-183.05C128.03,-197.37 155,-215 155,-215 155,-215 283.58,-630.64 318.4,-743.18"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="315.08,-744.3 321.38,-752.82 321.76,-742.23 315.08,-744.3"/>
|
||||||
|
</g>
|
||||||
|
<!-- dns:traefik.<domain> -->
|
||||||
|
<g id="node31" class="node">
|
||||||
|
<title>dns:traefik.<domain></title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="128.5,-82 20.5,-82 20.5,-46 134.5,-46 134.5,-76 128.5,-82"/>
|
||||||
|
<polyline fill="none" stroke="black" points="128.5,-82 128.5,-76 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="134.5,-76 128.5,-76 "/>
|
||||||
|
<text text-anchor="middle" x="77.5" y="-61.2" font-family="Helvetica,sans-Serif" font-size="11.00">traefik.<domain></text>
|
||||||
|
</g>
|
||||||
|
<!-- dns:traefik.<domain>->dynu -->
|
||||||
|
<g id="edge31" class="edge">
|
||||||
|
<title>dns:traefik.<domain>->dynu</title>
|
||||||
|
<path fill="none" stroke="#334155" d="M106.12,-82.05C128.03,-96.37 155,-114 155,-114 155,-114 286.65,-616.89 319.6,-742.72"/>
|
||||||
|
<polygon fill="#334155" stroke="#334155" points="316.3,-743.95 322.22,-752.74 323.07,-742.18 316.3,-743.95"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
# Public Infrastructure Summary
|
||||||
|
|
||||||
|
This documentation is generated from the infrastructure repository. Sensitive values are redacted.
|
||||||
|
|
||||||
|
> Generated docs are sanitised/redacted before publishing to GitHub Pages.
|
||||||
|
|
||||||
|
## Infrastructure diagrams
|
||||||
|
|
||||||
|
### Physical / virtual topology
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Docker, Traefik and Dynu routing
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Documents
|
||||||
|
|
||||||
|
- [Diagrams](diagrams.md)
|
||||||
|
- [Compose Inventory](compose-inventory.md)
|
||||||
|
- [Traefik Routes](traefik-routes.md)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.43.0 (0)
|
||||||
|
-->
|
||||||
|
<!-- Title: PhysicalTopology Pages: 1 -->
|
||||||
|
<svg width="514pt" height="61pt"
|
||||||
|
viewBox="0.00 0.00 514.00 61.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 57)">
|
||||||
|
<title>PhysicalTopology</title>
|
||||||
|
<polygon fill="white" stroke="transparent" points="-4,4 -4,-57 510,-57 510,4 -4,4"/>
|
||||||
|
<!-- placeholder:inventory -->
|
||||||
|
<g id="node1" class="node">
|
||||||
|
<title>placeholder:inventory</title>
|
||||||
|
<polygon fill="#fef3c7" stroke="black" points="500,-53 0,-53 0,0 506,0 506,-47 500,-53"/>
|
||||||
|
<polyline fill="none" stroke="black" points="500,-53 500,-47 "/>
|
||||||
|
<polyline fill="none" stroke="black" points="506,-47 500,-47 "/>
|
||||||
|
<text text-anchor="middle" x="253" y="-37.8" font-family="Times,serif" font-size="14.00">Host inventory JSON not found.</text>
|
||||||
|
<text text-anchor="middle" x="253" y="-22.8" font-family="Times,serif" font-size="14.00">Generate terraform inventory and rerun scripts/docs/generate-all.sh</text>
|
||||||
|
<text text-anchor="middle" x="253" y="-7.8" font-family="Times,serif" font-size="14.00">(--host-inventory <path>).</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
.md-content img, article img {
|
||||||
|
max-width: 100%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagram-wrap {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 1rem 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagram-wrap img {
|
||||||
|
max-width: none;
|
||||||
|
width: 1400px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.diagram-wrap img {
|
||||||
|
width: 1200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Traefik Routes
|
||||||
|
|
||||||
|
| Service | Router | Rule | Entrypoints | TLS | Middlewares | Target Port |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| authelia | authelia | Host(`auth.<domain>`) | websecure | true | | |
|
||||||
|
| error-pages | error-pages-router | HostRegexp(`{host:.+}`) | web | | error-pages-middleware | |
|
||||||
|
| gitea | gitea | Host(`gitea.<domain>`) | websecure | true | | 3000 |
|
||||||
|
| gotify | gotify | Host(`gotify.<domain>`) | websecure | | | 80 |
|
||||||
|
| grafana | grafana | Host(`grafana.<domain>`) | websecure | | | 3000 |
|
||||||
|
| grampsweb | gramps | Host(`familytree.<domain>`) | websecure | | | 5000 |
|
||||||
|
| influxdb | influxdb | Host(`influxdb.<domain>`) | websecure | | authelia | 8086 |
|
||||||
|
| monitor-kuma | monitor | Host(`monitor-kuma.<domain>`) | websecure | true | | 3001 |
|
||||||
|
| mtls-bridge | mtls-bridge | Host(`mtls-bridge.<domain>`) | websecure | | mtls-bridge-auth,mtls-bridge-cors | 8080 |
|
||||||
|
| mtls-bridge | mtls-bridge-preflight | Host(`mtls-bridge.<domain>`) && Method(`OPTIONS`) | websecure | | mtls-bridge-cors | |
|
||||||
|
| nextcloud-webapp | nextcloud | Host(`nextcloud.<domain>`) | websecure | | nextcloud-dav, nextcloud-webfinger | |
|
||||||
|
| node-red | node-red | Host(`node-red.<domain>`) | websecure | | authelia | 1880 |
|
||||||
|
| passbolt-webapp | passbolt | Host(`passbolt.<domain>`) | websecure | | | |
|
||||||
|
| portainer | portainer | Host(`portainer.<domain>`) | websecure | true | | 9000 |
|
||||||
|
| prometheus | prometheus | Host(`prometheus.<domain>`) | websecure | | authelia | 9090 |
|
||||||
|
| searxng-webapp | searxng | Host(`searxng.<domain>`) | websecure | | | 8080 |
|
||||||
|
| traefik | traefik | Host(`traefik.<domain>`) | websecure | | authelia | |
|
||||||
@@ -33,7 +33,7 @@ This page explains where to find authoritative files quickly.
|
|||||||
|
|
||||||
## Fast path for future Codex runs
|
## Fast path for future Codex runs
|
||||||
|
|
||||||
1. Read [README.md](../README.md).
|
1. Read [README.md](https://github.com/beatz174-bit/docker/blob/main/README.md).
|
||||||
2. Read [docs/source-of-truth.md](source-of-truth.md).
|
2. Read [docs/source-of-truth.md](source-of-truth.md).
|
||||||
3. Read [docs/docker-environment.md](docker-environment.md).
|
3. Read [docs/docker-environment.md](docker-environment.md).
|
||||||
4. Read [docs/terraform-workflows.md](terraform-workflows.md).
|
4. Read [docs/terraform-workflows.md](terraform-workflows.md).
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
This page explains how secret material is organized in this repository and where to find both human-readable and machine-readable references.
|
This page explains how secret material is organized in this repository and where to find both human-readable and machine-readable references.
|
||||||
|
|
||||||
For machine-readable inventory metadata, use [`../secrets/inventory.json`](../secrets/inventory.json).
|
For machine-readable inventory metadata, use [`secrets/inventory.json`](https://github.com/beatz174-bit/docker/blob/main/secrets/inventory.json).
|
||||||
|
|
||||||
## Scope and authority
|
## Scope and authority
|
||||||
|
|
||||||
- Canonical example template: [`../secrets/.env.secrets.example`](../secrets/.env.secrets.example)
|
- Canonical example template: [`secrets/.env.secrets.example`](https://github.com/beatz174-bit/docker/blob/main/secrets/.env.secrets.example)
|
||||||
- Runtime-loaded secret env file (local, non-committed): `../secrets/stack-secrets.env`
|
- Runtime-loaded secret env file (local, non-committed): `../secrets/stack-secrets.env`
|
||||||
- Dynu DNS inventory env file (local, non-committed): `../secrets/dynu.env`
|
- Dynu DNS inventory env file (local, non-committed): `../secrets/dynu.env`
|
||||||
- Docker secret files (local, non-committed): `../secrets/*.txt`
|
- Docker secret files (local, non-committed): `../secrets/*.txt`
|
||||||
@@ -30,7 +30,7 @@ Treat the example template as the canonical shape for expected environment varia
|
|||||||
|
|
||||||
## Machine-readable inventory
|
## Machine-readable inventory
|
||||||
|
|
||||||
- Primary automation source: [`../secrets/inventory.json`](../secrets/inventory.json)
|
- Primary automation source: [`secrets/inventory.json`](https://github.com/beatz174-bit/docker/blob/main/secrets/inventory.json)
|
||||||
- Human guidance source: this page
|
- Human guidance source: this page
|
||||||
|
|
||||||
Automation should parse `secrets/inventory.json` directly rather than scraping Markdown tables.
|
Automation should parse `secrets/inventory.json` directly rather than scraping Markdown tables.
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Public Showcase
|
||||||
|
|
||||||
|
This environment showcases practical infrastructure operations with a documentation-first approach.
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
|
||||||
|
- Container orchestration with Docker Compose.
|
||||||
|
- Reverse proxy routing and TLS-focused service exposure patterns.
|
||||||
|
- Monitoring and alerting configuration via version-controlled rules.
|
||||||
|
- Documentation automation through CI.
|
||||||
|
- Generated architecture diagrams to aid operational understanding.
|
||||||
|
- Sanitized public documentation for safe sharing.
|
||||||
|
|
||||||
|
This page intentionally avoids private hostnames, internal-only URLs, credentials, and secret values.
|
||||||
@@ -30,6 +30,10 @@ Use Terraform when documenting/reconciling existing:
|
|||||||
|
|
||||||
Do **not** treat Terraform as a full replacement for Compose operations in this repo.
|
Do **not** treat Terraform as a full replacement for Compose operations in this repo.
|
||||||
|
|
||||||
|
- Dynu public DNS records remain authoritative at Dynu.
|
||||||
|
- Terraform Dynu configuration mirrors/reconciles Dynu DNS state for documentation and controlled drift management.
|
||||||
|
- Imported Dynu Terraform state reflects actual provider-side DNS state at import time.
|
||||||
|
|
||||||
|
|
||||||
### Ansible bootstrap decisions
|
### Ansible bootstrap decisions
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,21 @@ Use for existing Proxmox VMs and metadata reconciliation.
|
|||||||
5. Keep lifecycle ignore rules narrow and explicit.
|
5. Keep lifecycle ignore rules narrow and explicit.
|
||||||
6. Iterate per VM until plan stabilizes.
|
6. Iterate per VM until plan stabilizes.
|
||||||
|
|
||||||
|
|
||||||
|
## Dynu DNS workflow
|
||||||
|
|
||||||
|
Directory: `infrastructure/terraform/dynu/`
|
||||||
|
|
||||||
|
Use for existing Dynu domains and DNS records.
|
||||||
|
|
||||||
|
1. Add or confirm the documentation catalog entry for one hostname.
|
||||||
|
2. Confirm the provider resource type and import ID format.
|
||||||
|
3. Import one existing domain or DNS record at a time.
|
||||||
|
4. Inspect state with `terraform state show`.
|
||||||
|
5. Reconcile only stable, meaningful attributes into hand-maintained `.tf`.
|
||||||
|
6. Keep record IDs, dynamic DNS targets, and provider-computed values out unless intentionally required.
|
||||||
|
7. Re-run plan until intended scope is clean.
|
||||||
|
|
||||||
## Physical host metadata workflow
|
## Physical host metadata workflow
|
||||||
|
|
||||||
Physical host metadata currently lives in Proxmox Terraform locals/outputs and is used as documentation inventory context.
|
Physical host metadata currently lives in Proxmox Terraform locals/outputs and is used as documentation inventory context.
|
||||||
@@ -75,4 +90,4 @@ Treat generated files as:
|
|||||||
|
|
||||||
- [docs/source-of-truth.md](source-of-truth.md)
|
- [docs/source-of-truth.md](source-of-truth.md)
|
||||||
- [docs/infrastructure-inventory.md](infrastructure-inventory.md)
|
- [docs/infrastructure-inventory.md](infrastructure-inventory.md)
|
||||||
- [infrastructure/terraform/README.md](../infrastructure/terraform/README.md)
|
- [infrastructure/terraform/README.md](https://github.com/beatz174-bit/docker/blob/main/infrastructure/terraform/README.md)
|
||||||
|
|||||||
@@ -10,17 +10,21 @@ It does **not** replace Docker Compose as runtime deployment authority.
|
|||||||
- Physical host metadata represented in Terraform locals/outputs.
|
- Physical host metadata represented in Terraform locals/outputs.
|
||||||
- Select Docker container mirror resources for documentation-oriented tracking.
|
- Select Docker container mirror resources for documentation-oriented tracking.
|
||||||
- Outputs that can support documentation and later downstream tooling.
|
- Outputs that can support documentation and later downstream tooling.
|
||||||
|
- Dynu DNS domain/record import and documentation inventory.
|
||||||
|
|
||||||
## What Terraform is not used for (today)
|
## What Terraform is not used for (today)
|
||||||
|
|
||||||
- Replacing `services-up.sh` / Compose for day-to-day app runtime orchestration.
|
- Replacing `services-up.sh` / Compose for day-to-day app runtime orchestration.
|
||||||
- Broad, immediate greenfield provisioning of the whole stack.
|
- Broad, immediate greenfield provisioning of the whole stack.
|
||||||
- Casual `apply` operations across all infrastructure.
|
- Casual `apply` operations across all infrastructure.
|
||||||
|
- Replacing Dynu as DNS authority.
|
||||||
|
- Blindly recreating production DNS records without import/reconciliation.
|
||||||
|
|
||||||
## Directory map
|
## Directory map
|
||||||
|
|
||||||
- `proxmox/` — imported/reconciled VM resources and host metadata outputs.
|
- `proxmox/` — imported/reconciled VM resources and host metadata outputs.
|
||||||
- `docker/` — selective Docker container import/mirror resources.
|
- `docker/` — selective Docker container import/mirror resources.
|
||||||
|
- `dynu/` — Dynu DNS brownfield import/reconciliation and DNS documentation outputs.
|
||||||
- `bootstrap/` — backend/provider bootstrap scaffolding.
|
- `bootstrap/` — backend/provider bootstrap scaffolding.
|
||||||
- `modules/` — placeholder module directories for future stable abstractions.
|
- `modules/` — placeholder module directories for future stable abstractions.
|
||||||
- `scripts/reconcile_from_plan.sh` — helper to convert generated plan config into reviewable draft files.
|
- `scripts/reconcile_from_plan.sh` — helper to convert generated plan config into reviewable draft files.
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
# This file is maintained automatically by "terraform init".
|
||||||
|
# Manual edits may be lost in future updates.
|
||||||
|
|
||||||
|
provider "registry.terraform.io/beatz174-bit/dynu" {
|
||||||
|
version = "0.3.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:yftAEp/lcPmbVRV8YenFaMJElUkt3j79TSt3OcQnwk4=",
|
||||||
|
"zh:1f7344737dff5b12155e8308b1cb55b0cc6f83a4a5776eb1cc2273bc84bb8fa2",
|
||||||
|
"zh:212662c4f5b979401f282f7f9856480bad86d9e488110bebc589a4eeb892ff02",
|
||||||
|
"zh:2ed5294fc7db7639c41f99a9d7bcfff6585f1f372eb23cd8229adfe219cba63a",
|
||||||
|
"zh:30fc9df00120f309ae969ae107e4dc4a0b04517f2c07a78934a2c479995f77b8",
|
||||||
|
"zh:3126369f6dc86e8083ec12a2643ea87a13543ed12631b40375b7b9563da41474",
|
||||||
|
"zh:3c5775a6763608253e2698b85dcee42eafd6ca8e08a8851866123de403a331b0",
|
||||||
|
"zh:50bedffbee48505604d05181172018143e54c68249761a749fb7c115eec4ce04",
|
||||||
|
"zh:528549a2763dd2fbf3ffe047fa19c0524eb08addd777c9c0350800394ff16235",
|
||||||
|
"zh:99049e25d7d3fb26e2a94d6e609c8989efcee1af1568a77110a70bce2c01f1ef",
|
||||||
|
"zh:9a6490b67aca08b135e5ba7092fc315e67177be1f280f6c0d06b9c64a0892d3a",
|
||||||
|
"zh:bfaae08fb5a0b10184a7b6e8382038d0a0b9936ea13efa1462c35cee902b0c14",
|
||||||
|
"zh:c0dbe59b9bfcbd42f3da1732615669a579275acc654c75127612d86f319b38b3",
|
||||||
|
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
|
||||||
|
"zh:f815fa2f8681477f159eb9a32b78f8988065e5040b7feea42604bac469c2c4eb",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
# Dynu Terraform Layer (Brownfield DNS Reconciliation)
|
||||||
|
|
||||||
|
This Terraform root is for **Dynu DNS brownfield reconciliation**. The intended pattern is:
|
||||||
|
|
||||||
|
1. Import the existing root domain object.
|
||||||
|
2. Read inventory through `data.dynu_dns_records.root`.
|
||||||
|
3. Generate reviewable `dynu_dns_record` resources and import commands.
|
||||||
|
4. Import every existing DNS record into matching Terraform resources.
|
||||||
|
5. Use `terraform plan` as the reconciliation check before any apply.
|
||||||
|
|
||||||
|
## Provider behavior to keep in mind
|
||||||
|
|
||||||
|
- Source: `beatz174-bit/dynu`
|
||||||
|
- `dynu_domain` import requires a **numeric Dynu domain ID**.
|
||||||
|
- Importing `dynu_domain` imports only the root domain object.
|
||||||
|
- It **does not** import DNS records/subdomains.
|
||||||
|
- `dynu_dns_record` imports require `<domain_id>/<record_id>`.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
- `dynu_root_domain` (default: `lan.ddnsgeek.com`)
|
||||||
|
- `dynu_api_key` (sensitive)
|
||||||
|
- `dynu_username` / `dynu_password` (optional)
|
||||||
|
|
||||||
|
## Safe validation commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd infrastructure/terraform/dynu
|
||||||
|
terraform fmt -check -recursive
|
||||||
|
terraform init -backend=false -input=false
|
||||||
|
terraform validate
|
||||||
|
python3 -m py_compile scripts/generate-brownfield-records.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Brownfield workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd infrastructure/terraform/dynu
|
||||||
|
|
||||||
|
terraform init
|
||||||
|
terraform import dynu_domain.lan_ddnsgeek_com '<numeric-dynu-domain-id>'
|
||||||
|
|
||||||
|
terraform apply -refresh-only
|
||||||
|
terraform output -json dynu_dns_records > /tmp/dynu-records.json
|
||||||
|
|
||||||
|
python3 scripts/generate-brownfield-records.py --dry-run
|
||||||
|
python3 scripts/generate-brownfield-records.py --overwrite
|
||||||
|
|
||||||
|
# Review generated/dynu_dns_records.generated.tf
|
||||||
|
# Review generated/import-dynu-dns-records.sh
|
||||||
|
|
||||||
|
bash generated/import-dynu-dns-records.sh
|
||||||
|
|
||||||
|
terraform plan
|
||||||
|
```
|
||||||
|
|
||||||
|
## What each component means
|
||||||
|
|
||||||
|
- `data.dynu_dns_records.root`: read-only live inventory from Dynu.
|
||||||
|
- `generated/dynu_dns_records.generated.tf`: generated management-intent resources; includes `prevent_destroy = true` on each record.
|
||||||
|
- `generated/import-dynu-dns-records.sh`: imports each discovered record to its generated `dynu_dns_record` address using `<domain_id>/<record_id>`.
|
||||||
|
- `terraform plan` after imports: reconciliation checkpoint. Any create/update/delete must be reviewed manually before apply.
|
||||||
|
|
||||||
|
## Generated artifacts
|
||||||
|
|
||||||
|
The helper script writes these files under `generated/`:
|
||||||
|
|
||||||
|
- `generated/dynu_dns_records_inventory.json`
|
||||||
|
- `generated/dynu_dns_records.generated.tf`
|
||||||
|
- `generated/import-dynu-dns-records.sh`
|
||||||
|
|
||||||
|
These are generated outputs meant for operator review before use in production.
|
||||||
|
|
||||||
|
|
||||||
|
### Generator output selection (interactive + automation)
|
||||||
|
|
||||||
|
The brownfield generator defaults to Terraform output `dynu_dns_records`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/generate-brownfield-records.py --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
If the default output is missing/unusable and stdin is interactive, the script shows a picker of available Terraform outputs and indicates which ones are usable for DNS imports.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Interactive mode: choose from available Terraform outputs
|
||||||
|
python3 scripts/generate-brownfield-records.py --dry-run
|
||||||
|
|
||||||
|
# Non-interactive mode: specify output explicitly
|
||||||
|
python3 scripts/generate-brownfield-records.py \
|
||||||
|
--records-output dynu_dns_inventory \
|
||||||
|
--dry-run
|
||||||
|
|
||||||
|
# Disable menu and fail fast
|
||||||
|
python3 scripts/generate-brownfield-records.py \
|
||||||
|
--no-interactive \
|
||||||
|
--dry-run
|
||||||
|
|
||||||
|
# Use saved terraform output JSON and choose interactively
|
||||||
|
terraform output -json > generated/terraform-output.json
|
||||||
|
python3 scripts/generate-brownfield-records.py \
|
||||||
|
--from-file generated/terraform-output.json \
|
||||||
|
--dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- The menu shows Terraform outputs currently stored in state.
|
||||||
|
- If newly added outputs do not appear, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
terraform apply -refresh-only
|
||||||
|
```
|
||||||
|
|
||||||
|
- The selected output must contain real Dynu provider record fields:
|
||||||
|
- `id`
|
||||||
|
- `domain_id`
|
||||||
|
- `hostname`
|
||||||
|
- `record_type`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Plan shows a large wall of `+` values under outputs
|
||||||
|
|
||||||
|
Cause:
|
||||||
|
|
||||||
|
Terraform is planning to save **new output values** to state (for example, live records from `data.dynu_dns_records.root`). This is not creating DNS records by itself.
|
||||||
|
|
||||||
|
How to verify:
|
||||||
|
|
||||||
|
- Output-only changes appear under `Changes to Outputs`.
|
||||||
|
- Real DNS changes appear as `dynu_dns_record` resource create/update/delete actions.
|
||||||
|
|
||||||
|
Use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
terraform apply -refresh-only
|
||||||
|
```
|
||||||
|
|
||||||
|
to persist refreshed data source and output values only.
|
||||||
|
|
||||||
|
### Error: `There is no function named "regexreplace"`
|
||||||
|
|
||||||
|
Cause:
|
||||||
|
|
||||||
|
`regexreplace` is not a Terraform function. Resource-name slugification should not be implemented in Terraform HCL for this workflow.
|
||||||
|
|
||||||
|
Fix:
|
||||||
|
|
||||||
|
- Keep `inventory.tf` focused on reading live records via `data.dynu_dns_records.root`.
|
||||||
|
- Keep Terraform outputs simple (for example, `<domain_id>/<record_id>` mappings).
|
||||||
|
- Let `scripts/generate-brownfield-records.py` generate Terraform-safe resource names with Python `tf_name(record)`.
|
||||||
|
|
||||||
|
### Error: `'"'"'dynu_dns_records'"'"'`
|
||||||
|
|
||||||
|
Cause:
|
||||||
|
|
||||||
|
The helper script reads `terraform output -json` and expects an output named `dynu_dns_records`.
|
||||||
|
|
||||||
|
Fix:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd infrastructure/terraform/dynu
|
||||||
|
terraform init
|
||||||
|
terraform apply -refresh-only
|
||||||
|
terraform output -json | jq 'keys'
|
||||||
|
```
|
||||||
|
|
||||||
|
Confirm `dynu_dns_records` appears in the key list.
|
||||||
|
|
||||||
|
If it does not, check that the Terraform config contains:
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
data "dynu_dns_records" "root" {
|
||||||
|
hostname = var.dynu_root_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_records" {
|
||||||
|
value = data.dynu_dns_records.root.records
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then rerun:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/generate-brownfield-records.py --dry-run
|
||||||
|
```
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
data "dynu_domain" "lan" {
|
||||||
|
hostname = "lan.ddnsgeek.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_domain_id" {
|
||||||
|
value = data.dynu_domain.lan.domain.id
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
locals {
|
||||||
|
dynu_domain = var.dynu_root_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
# Import-first resource skeleton for the production Dynu zone.
|
||||||
|
# `name` is required by provider schema and can be reconciled after import.
|
||||||
|
resource "dynu_domain" "lan_ddnsgeek_com" {
|
||||||
|
name = local.dynu_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# GENERATED FILE - REVIEW BEFORE USE
|
||||||
|
#
|
||||||
|
# Generated from Dynu brownfield DNS inventory.
|
||||||
|
# Do not blindly apply this file to production DNS.
|
||||||
|
# Import records into Terraform state before allowing Terraform to manage them.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "auth_lan_ddnsgeek_com_a_18483099" {
|
||||||
|
hostname = "auth.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "auth"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "auth_lan_ddnsgeek_com_a_19646048" {
|
||||||
|
hostname = "auth.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "auth"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "edge_lan_ddnsgeek_com_a_10453241" {
|
||||||
|
hostname = "edge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "edge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "edge_lan_ddnsgeek_com_a_19646062" {
|
||||||
|
hostname = "edge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "edge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "familytree_lan_ddnsgeek_com_a_17017685" {
|
||||||
|
hostname = "familytree.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "familytree"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "familytree_lan_ddnsgeek_com_a_19646056" {
|
||||||
|
hostname = "familytree.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "familytree"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gitea_lan_ddnsgeek_com_a_14682463" {
|
||||||
|
hostname = "gitea.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "gitea"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gitea_lan_ddnsgeek_com_a_19646063" {
|
||||||
|
hostname = "gitea.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "gitea"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gotify_lan_ddnsgeek_com_a_17439061" {
|
||||||
|
hostname = "gotify.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "gotify"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gotify_lan_ddnsgeek_com_a_19646047" {
|
||||||
|
hostname = "gotify.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "gotify"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "grafana_lan_ddnsgeek_com_a_18113762" {
|
||||||
|
hostname = "grafana.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "grafana"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "grafana_lan_ddnsgeek_com_a_19646050" {
|
||||||
|
hostname = "grafana.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "grafana"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "influxdb_lan_ddnsgeek_com_a_18562198" {
|
||||||
|
hostname = "influxdb.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "influxdb"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "influxdb_lan_ddnsgeek_com_a_19646059" {
|
||||||
|
hostname = "influxdb.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "influxdb"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "kuma_lan_ddnsgeek_com_a_17454978" {
|
||||||
|
hostname = "kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 90
|
||||||
|
enabled = true
|
||||||
|
content = "120.155.99.146"
|
||||||
|
node_name = "kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "lan_ddnsgeek_com_soa_8299670" {
|
||||||
|
hostname = "lan.ddnsgeek.com"
|
||||||
|
record_type = "SOA"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "ns1.dynu.com. administrator.dynu.com. 0 3600 900 604800 300"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "monitor_kuma_lan_ddnsgeek_com_a_17462342" {
|
||||||
|
hostname = "monitor-kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "monitor-kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "monitor_kuma_lan_ddnsgeek_com_a_19646051" {
|
||||||
|
hostname = "monitor-kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "monitor-kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "mtls_bridge_lan_ddnsgeek_com_a_19232643" {
|
||||||
|
hostname = "mtls-bridge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "mtls-bridge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "mtls_bridge_lan_ddnsgeek_com_a_19646058" {
|
||||||
|
hostname = "mtls-bridge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "mtls-bridge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "nextcloud_lan_ddnsgeek_com_a_10453260" {
|
||||||
|
hostname = "nextcloud.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "nextcloud"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "nextcloud_lan_ddnsgeek_com_a_19646057" {
|
||||||
|
hostname = "nextcloud.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "nextcloud"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "node_red_lan_ddnsgeek_com_a_19041230" {
|
||||||
|
hostname = "node-red.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "node-red"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "node_red_lan_ddnsgeek_com_a_19646053" {
|
||||||
|
hostname = "node-red.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "node-red"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "passbolt_lan_ddnsgeek_com_a_10453262" {
|
||||||
|
hostname = "passbolt.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "passbolt"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "passbolt_lan_ddnsgeek_com_a_19646049" {
|
||||||
|
hostname = "passbolt.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "passbolt"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "portainer_lan_ddnsgeek_com_a_17458810" {
|
||||||
|
hostname = "portainer.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "portainer"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "portainer_lan_ddnsgeek_com_a_19646046" {
|
||||||
|
hostname = "portainer.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "portainer"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "prometheus_lan_ddnsgeek_com_a_18483311" {
|
||||||
|
hostname = "prometheus.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "prometheus"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "prometheus_lan_ddnsgeek_com_a_19646061" {
|
||||||
|
hostname = "prometheus.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "prometheus"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "searxng_lan_ddnsgeek_com_a_10453263" {
|
||||||
|
hostname = "searxng.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "searxng"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "searxng_lan_ddnsgeek_com_a_19646055" {
|
||||||
|
hostname = "searxng.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "searxng"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "shifts_lan_ddnsgeek_com_a_15901565" {
|
||||||
|
hostname = "shifts.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "shifts"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "shifts_lan_ddnsgeek_com_a_19646052" {
|
||||||
|
hostname = "shifts.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "shifts"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "stockfill_lan_ddnsgeek_com_a_17081867" {
|
||||||
|
hostname = "stockfill.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "stockfill"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "stockfill_lan_ddnsgeek_com_a_19646060" {
|
||||||
|
hostname = "stockfill.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "stockfill"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "traefik_lan_ddnsgeek_com_a_10453240" {
|
||||||
|
hostname = "traefik.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "traefik"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "traefik_lan_ddnsgeek_com_a_19646054" {
|
||||||
|
hostname = "traefik.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "traefik"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,518 @@
|
|||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# GENERATED FILE - REVIEW BEFORE USE
|
||||||
|
#
|
||||||
|
# Generated from Dynu brownfield DNS inventory.
|
||||||
|
# Do not blindly apply this file to production DNS.
|
||||||
|
# Import records into Terraform state before allowing Terraform to manage them.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "auth_lan_ddnsgeek_com_a_18483099" {
|
||||||
|
hostname = "auth.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "auth"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "auth_lan_ddnsgeek_com_a_19646048" {
|
||||||
|
hostname = "auth.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "auth"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "edge_lan_ddnsgeek_com_a_10453241" {
|
||||||
|
hostname = "edge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "edge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "edge_lan_ddnsgeek_com_a_19646062" {
|
||||||
|
hostname = "edge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "edge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "familytree_lan_ddnsgeek_com_a_17017685" {
|
||||||
|
hostname = "familytree.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "familytree"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "familytree_lan_ddnsgeek_com_a_19646056" {
|
||||||
|
hostname = "familytree.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "familytree"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gitea_lan_ddnsgeek_com_a_14682463" {
|
||||||
|
hostname = "gitea.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "gitea"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gitea_lan_ddnsgeek_com_a_19646063" {
|
||||||
|
hostname = "gitea.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "gitea"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gotify_lan_ddnsgeek_com_a_17439061" {
|
||||||
|
hostname = "gotify.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "gotify"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "gotify_lan_ddnsgeek_com_a_19646047" {
|
||||||
|
hostname = "gotify.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "gotify"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "grafana_lan_ddnsgeek_com_a_18113762" {
|
||||||
|
hostname = "grafana.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "grafana"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "grafana_lan_ddnsgeek_com_a_19646050" {
|
||||||
|
hostname = "grafana.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "grafana"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "influxdb_lan_ddnsgeek_com_a_18562198" {
|
||||||
|
hostname = "influxdb.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "influxdb"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "influxdb_lan_ddnsgeek_com_a_19646059" {
|
||||||
|
hostname = "influxdb.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "influxdb"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "kuma_lan_ddnsgeek_com_a_17454978" {
|
||||||
|
hostname = "kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 60
|
||||||
|
enabled = true
|
||||||
|
content = "120.155.99.146"
|
||||||
|
node_name = "kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "lan_ddnsgeek_com_soa_8299670" {
|
||||||
|
hostname = "lan.ddnsgeek.com"
|
||||||
|
record_type = "SOA"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "ns1.dynu.com. administrator.dynu.com. 0 3600 900 604800 300"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "monitor_kuma_lan_ddnsgeek_com_a_17462342" {
|
||||||
|
hostname = "monitor-kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "monitor-kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "monitor_kuma_lan_ddnsgeek_com_a_19646051" {
|
||||||
|
hostname = "monitor-kuma.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "monitor-kuma"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "mtls_bridge_lan_ddnsgeek_com_a_19232643" {
|
||||||
|
hostname = "mtls-bridge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "mtls-bridge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "mtls_bridge_lan_ddnsgeek_com_a_19646058" {
|
||||||
|
hostname = "mtls-bridge.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "mtls-bridge"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "nextcloud_lan_ddnsgeek_com_a_10453260" {
|
||||||
|
hostname = "nextcloud.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "nextcloud"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "nextcloud_lan_ddnsgeek_com_a_19646057" {
|
||||||
|
hostname = "nextcloud.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "nextcloud"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "node_red_lan_ddnsgeek_com_a_19041230" {
|
||||||
|
hostname = "node-red.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "node-red"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "node_red_lan_ddnsgeek_com_a_19646053" {
|
||||||
|
hostname = "node-red.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "node-red"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "passbolt_lan_ddnsgeek_com_a_10453262" {
|
||||||
|
hostname = "passbolt.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "passbolt"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "passbolt_lan_ddnsgeek_com_a_19646049" {
|
||||||
|
hostname = "passbolt.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "passbolt"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "portainer_lan_ddnsgeek_com_a_17458810" {
|
||||||
|
hostname = "portainer.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "portainer"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "portainer_lan_ddnsgeek_com_a_19646046" {
|
||||||
|
hostname = "portainer.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "portainer"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "prometheus_lan_ddnsgeek_com_a_18483311" {
|
||||||
|
hostname = "prometheus.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "prometheus"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "prometheus_lan_ddnsgeek_com_a_19646061" {
|
||||||
|
hostname = "prometheus.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "prometheus"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "searxng_lan_ddnsgeek_com_a_10453263" {
|
||||||
|
hostname = "searxng.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "searxng"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "searxng_lan_ddnsgeek_com_a_19646055" {
|
||||||
|
hostname = "searxng.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "searxng"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "shifts_lan_ddnsgeek_com_a_15901565" {
|
||||||
|
hostname = "shifts.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "shifts"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "shifts_lan_ddnsgeek_com_a_19646052" {
|
||||||
|
hostname = "shifts.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "shifts"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "stockfill_lan_ddnsgeek_com_a_17081867" {
|
||||||
|
hostname = "stockfill.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "stockfill"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "stockfill_lan_ddnsgeek_com_a_19646060" {
|
||||||
|
hostname = "stockfill.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "stockfill"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "traefik_lan_ddnsgeek_com_a_10453240" {
|
||||||
|
hostname = "traefik.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
dynamic = true
|
||||||
|
node_name = "traefik"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "dynu_dns_record" "traefik_lan_ddnsgeek_com_a_19646054" {
|
||||||
|
hostname = "traefik.lan.ddnsgeek.com"
|
||||||
|
record_type = "A"
|
||||||
|
ttl = 120
|
||||||
|
enabled = true
|
||||||
|
content = "167.179.167.166"
|
||||||
|
group = "home"
|
||||||
|
node_name = "traefik"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
prevent_destroy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "auth.lan.ddnsgeek.com",
|
||||||
|
"id": 18483099,
|
||||||
|
"node_name": "auth",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-02-17T12:59:58.803"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "auth.lan.ddnsgeek.com",
|
||||||
|
"id": 19646048,
|
||||||
|
"node_name": "auth",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "edge.lan.ddnsgeek.com",
|
||||||
|
"id": 10453241,
|
||||||
|
"node_name": "edge",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2024-03-18T01:27:26"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "edge.lan.ddnsgeek.com",
|
||||||
|
"id": 19646062,
|
||||||
|
"node_name": "edge",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:45.237"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "familytree.lan.ddnsgeek.com",
|
||||||
|
"id": 17017685,
|
||||||
|
"node_name": "familytree",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-11-17T04:43:07.953"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "familytree.lan.ddnsgeek.com",
|
||||||
|
"id": 19646056,
|
||||||
|
"node_name": "familytree",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:44.25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "gitea.lan.ddnsgeek.com",
|
||||||
|
"id": 14682463,
|
||||||
|
"node_name": "gitea",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-07-16T03:15:50.38"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "gitea.lan.ddnsgeek.com",
|
||||||
|
"id": 19646063,
|
||||||
|
"node_name": "gitea",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:45.343"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "gotify.lan.ddnsgeek.com",
|
||||||
|
"id": 17439061,
|
||||||
|
"node_name": "gotify",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-12-16T09:35:47.307"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "gotify.lan.ddnsgeek.com",
|
||||||
|
"id": 19646047,
|
||||||
|
"node_name": "gotify",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "grafana.lan.ddnsgeek.com",
|
||||||
|
"id": 18113762,
|
||||||
|
"node_name": "grafana",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-01-28T04:38:25.92"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "grafana.lan.ddnsgeek.com",
|
||||||
|
"id": 19646050,
|
||||||
|
"node_name": "grafana",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "influxdb.lan.ddnsgeek.com",
|
||||||
|
"id": 18562198,
|
||||||
|
"node_name": "influxdb",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-02-22T16:46:26.85"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "influxdb.lan.ddnsgeek.com",
|
||||||
|
"id": 19646059,
|
||||||
|
"node_name": "influxdb",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:44.85"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "120.155.99.146",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "kuma.lan.ddnsgeek.com",
|
||||||
|
"id": 17454978,
|
||||||
|
"node_name": "kuma",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 60,
|
||||||
|
"updated_on": "2026-04-21T04:50:04.81"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "ns1.dynu.com. administrator.dynu.com. 0 3600 900 604800 300",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "lan.ddnsgeek.com",
|
||||||
|
"id": 8299670,
|
||||||
|
"node_name": null,
|
||||||
|
"record_type": "SOA",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2022-03-15T10:08:15"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "monitor-kuma.lan.ddnsgeek.com",
|
||||||
|
"id": 17462342,
|
||||||
|
"node_name": "monitor-kuma",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-12-17T14:47:25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "monitor-kuma.lan.ddnsgeek.com",
|
||||||
|
"id": 19646051,
|
||||||
|
"node_name": "monitor-kuma",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.727"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "mtls-bridge.lan.ddnsgeek.com",
|
||||||
|
"id": 19232643,
|
||||||
|
"node_name": "mtls-bridge",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-04-13T04:20:00.11"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "mtls-bridge.lan.ddnsgeek.com",
|
||||||
|
"id": 19646058,
|
||||||
|
"node_name": "mtls-bridge",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:44.737"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "nextcloud.lan.ddnsgeek.com",
|
||||||
|
"id": 10453260,
|
||||||
|
"node_name": "nextcloud",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2024-03-18T01:40:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "nextcloud.lan.ddnsgeek.com",
|
||||||
|
"id": 19646057,
|
||||||
|
"node_name": "nextcloud",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:44.53"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "node-red.lan.ddnsgeek.com",
|
||||||
|
"id": 19041230,
|
||||||
|
"node_name": "node-red",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-03-30T04:51:39.68"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "node-red.lan.ddnsgeek.com",
|
||||||
|
"id": 19646053,
|
||||||
|
"node_name": "node-red",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.737"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "passbolt.lan.ddnsgeek.com",
|
||||||
|
"id": 10453262,
|
||||||
|
"node_name": "passbolt",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2024-03-18T01:40:18"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "passbolt.lan.ddnsgeek.com",
|
||||||
|
"id": 19646049,
|
||||||
|
"node_name": "passbolt",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "portainer.lan.ddnsgeek.com",
|
||||||
|
"id": 17458810,
|
||||||
|
"node_name": "portainer",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-12-17T10:23:40.077"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "portainer.lan.ddnsgeek.com",
|
||||||
|
"id": 19646046,
|
||||||
|
"node_name": "portainer",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.693"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "prometheus.lan.ddnsgeek.com",
|
||||||
|
"id": 18483311,
|
||||||
|
"node_name": "prometheus",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-02-17T13:17:00.55"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "prometheus.lan.ddnsgeek.com",
|
||||||
|
"id": 19646061,
|
||||||
|
"node_name": "prometheus",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:45.033"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "searxng.lan.ddnsgeek.com",
|
||||||
|
"id": 10453263,
|
||||||
|
"node_name": "searxng",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2024-03-18T01:40:34"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "searxng.lan.ddnsgeek.com",
|
||||||
|
"id": 19646055,
|
||||||
|
"node_name": "searxng",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:38.797"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "shifts.lan.ddnsgeek.com",
|
||||||
|
"id": 15901565,
|
||||||
|
"node_name": "shifts",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-09-30T04:25:20.65"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "shifts.lan.ddnsgeek.com",
|
||||||
|
"id": 19646052,
|
||||||
|
"node_name": "shifts",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.727"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "stockfill.lan.ddnsgeek.com",
|
||||||
|
"id": 17081867,
|
||||||
|
"node_name": "stockfill",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2025-11-21T06:49:33.47"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "stockfill.lan.ddnsgeek.com",
|
||||||
|
"id": 19646060,
|
||||||
|
"node_name": "stockfill",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:44.987"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": null,
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": null,
|
||||||
|
"host": null,
|
||||||
|
"hostname": "traefik.lan.ddnsgeek.com",
|
||||||
|
"id": 10453240,
|
||||||
|
"node_name": "traefik",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2024-03-18T01:27:13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "167.179.167.166",
|
||||||
|
"domain_id": 9695470,
|
||||||
|
"domain_name": "lan.ddnsgeek.com",
|
||||||
|
"group": "home",
|
||||||
|
"host": null,
|
||||||
|
"hostname": "traefik.lan.ddnsgeek.com",
|
||||||
|
"id": 19646054,
|
||||||
|
"node_name": "traefik",
|
||||||
|
"record_type": "A",
|
||||||
|
"state": true,
|
||||||
|
"ttl": 120,
|
||||||
|
"updated_on": "2026-05-12T21:11:37.737"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# GENERATED FILE - REVIEW BEFORE USE
|
||||||
|
#
|
||||||
|
# Imports existing Dynu DNS records into Terraform state.
|
||||||
|
# Does not apply changes.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
TF_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
cd "${TF_ROOT}"
|
||||||
|
|
||||||
|
# Re-running imports will fail for resources already in state.
|
||||||
|
# This script skips imports when state already contains the resource address.
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.auth_lan_ddnsgeek_com_a_18483099' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.auth_lan_ddnsgeek_com_a_18483099'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.auth_lan_ddnsgeek_com_a_18483099' '9695470/18483099'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.auth_lan_ddnsgeek_com_a_19646048' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.auth_lan_ddnsgeek_com_a_19646048'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.auth_lan_ddnsgeek_com_a_19646048' '9695470/19646048'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.edge_lan_ddnsgeek_com_a_10453241' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.edge_lan_ddnsgeek_com_a_10453241'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.edge_lan_ddnsgeek_com_a_10453241' '9695470/10453241'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.edge_lan_ddnsgeek_com_a_19646062' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.edge_lan_ddnsgeek_com_a_19646062'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.edge_lan_ddnsgeek_com_a_19646062' '9695470/19646062'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.familytree_lan_ddnsgeek_com_a_17017685' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.familytree_lan_ddnsgeek_com_a_17017685'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.familytree_lan_ddnsgeek_com_a_17017685' '9695470/17017685'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.familytree_lan_ddnsgeek_com_a_19646056' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.familytree_lan_ddnsgeek_com_a_19646056'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.familytree_lan_ddnsgeek_com_a_19646056' '9695470/19646056'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.gitea_lan_ddnsgeek_com_a_14682463' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.gitea_lan_ddnsgeek_com_a_14682463'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.gitea_lan_ddnsgeek_com_a_14682463' '9695470/14682463'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.gitea_lan_ddnsgeek_com_a_19646063' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.gitea_lan_ddnsgeek_com_a_19646063'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.gitea_lan_ddnsgeek_com_a_19646063' '9695470/19646063'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.gotify_lan_ddnsgeek_com_a_17439061' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.gotify_lan_ddnsgeek_com_a_17439061'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.gotify_lan_ddnsgeek_com_a_17439061' '9695470/17439061'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.gotify_lan_ddnsgeek_com_a_19646047' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.gotify_lan_ddnsgeek_com_a_19646047'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.gotify_lan_ddnsgeek_com_a_19646047' '9695470/19646047'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.grafana_lan_ddnsgeek_com_a_18113762' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.grafana_lan_ddnsgeek_com_a_18113762'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.grafana_lan_ddnsgeek_com_a_18113762' '9695470/18113762'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.grafana_lan_ddnsgeek_com_a_19646050' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.grafana_lan_ddnsgeek_com_a_19646050'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.grafana_lan_ddnsgeek_com_a_19646050' '9695470/19646050'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.influxdb_lan_ddnsgeek_com_a_18562198' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.influxdb_lan_ddnsgeek_com_a_18562198'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.influxdb_lan_ddnsgeek_com_a_18562198' '9695470/18562198'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.influxdb_lan_ddnsgeek_com_a_19646059' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.influxdb_lan_ddnsgeek_com_a_19646059'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.influxdb_lan_ddnsgeek_com_a_19646059' '9695470/19646059'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.kuma_lan_ddnsgeek_com_a_17454978' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.kuma_lan_ddnsgeek_com_a_17454978'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.kuma_lan_ddnsgeek_com_a_17454978' '9695470/17454978'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.lan_ddnsgeek_com_soa_8299670' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.lan_ddnsgeek_com_soa_8299670'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.lan_ddnsgeek_com_soa_8299670' '9695470/8299670'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_17462342' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_17462342'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_17462342' '9695470/17462342'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_19646051' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_19646051'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.monitor_kuma_lan_ddnsgeek_com_a_19646051' '9695470/19646051'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19232643' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19232643'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19232643' '9695470/19232643'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19646058' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19646058'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.mtls_bridge_lan_ddnsgeek_com_a_19646058' '9695470/19646058'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_10453260' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_10453260'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_10453260' '9695470/10453260'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_19646057' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_19646057'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.nextcloud_lan_ddnsgeek_com_a_19646057' '9695470/19646057'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.node_red_lan_ddnsgeek_com_a_19041230' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.node_red_lan_ddnsgeek_com_a_19041230'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.node_red_lan_ddnsgeek_com_a_19041230' '9695470/19041230'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.node_red_lan_ddnsgeek_com_a_19646053' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.node_red_lan_ddnsgeek_com_a_19646053'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.node_red_lan_ddnsgeek_com_a_19646053' '9695470/19646053'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.passbolt_lan_ddnsgeek_com_a_10453262' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.passbolt_lan_ddnsgeek_com_a_10453262'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.passbolt_lan_ddnsgeek_com_a_10453262' '9695470/10453262'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.passbolt_lan_ddnsgeek_com_a_19646049' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.passbolt_lan_ddnsgeek_com_a_19646049'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.passbolt_lan_ddnsgeek_com_a_19646049' '9695470/19646049'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.portainer_lan_ddnsgeek_com_a_17458810' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.portainer_lan_ddnsgeek_com_a_17458810'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.portainer_lan_ddnsgeek_com_a_17458810' '9695470/17458810'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.portainer_lan_ddnsgeek_com_a_19646046' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.portainer_lan_ddnsgeek_com_a_19646046'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.portainer_lan_ddnsgeek_com_a_19646046' '9695470/19646046'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.prometheus_lan_ddnsgeek_com_a_18483311' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.prometheus_lan_ddnsgeek_com_a_18483311'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.prometheus_lan_ddnsgeek_com_a_18483311' '9695470/18483311'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.prometheus_lan_ddnsgeek_com_a_19646061' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.prometheus_lan_ddnsgeek_com_a_19646061'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.prometheus_lan_ddnsgeek_com_a_19646061' '9695470/19646061'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.searxng_lan_ddnsgeek_com_a_10453263' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.searxng_lan_ddnsgeek_com_a_10453263'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.searxng_lan_ddnsgeek_com_a_10453263' '9695470/10453263'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.searxng_lan_ddnsgeek_com_a_19646055' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.searxng_lan_ddnsgeek_com_a_19646055'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.searxng_lan_ddnsgeek_com_a_19646055' '9695470/19646055'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.shifts_lan_ddnsgeek_com_a_15901565' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.shifts_lan_ddnsgeek_com_a_15901565'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.shifts_lan_ddnsgeek_com_a_15901565' '9695470/15901565'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.shifts_lan_ddnsgeek_com_a_19646052' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.shifts_lan_ddnsgeek_com_a_19646052'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.shifts_lan_ddnsgeek_com_a_19646052' '9695470/19646052'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.stockfill_lan_ddnsgeek_com_a_17081867' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.stockfill_lan_ddnsgeek_com_a_17081867'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.stockfill_lan_ddnsgeek_com_a_17081867' '9695470/17081867'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.stockfill_lan_ddnsgeek_com_a_19646060' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.stockfill_lan_ddnsgeek_com_a_19646060'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.stockfill_lan_ddnsgeek_com_a_19646060' '9695470/19646060'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.traefik_lan_ddnsgeek_com_a_10453240' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.traefik_lan_ddnsgeek_com_a_10453240'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.traefik_lan_ddnsgeek_com_a_10453240' '9695470/10453240'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if terraform state show 'dynu_dns_record.traefik_lan_ddnsgeek_com_a_19646054' >/dev/null 2>&1; then
|
||||||
|
echo 'Skipping already imported: dynu_dns_record.traefik_lan_ddnsgeek_com_a_19646054'
|
||||||
|
else
|
||||||
|
terraform import 'dynu_dns_record.traefik_lan_ddnsgeek_com_a_19646054' '9695470/19646054'
|
||||||
|
fi
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Copy this file to imports.tf and adjust IDs after confirming the
|
||||||
|
# published provider docs for import ID formats.
|
||||||
|
# For dynu_domain, import ID is commonly the root domain name.
|
||||||
|
|
||||||
|
import {
|
||||||
|
to = dynu_domain.lan_ddnsgeek_com
|
||||||
|
id = var.dynu_root_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
# DNS record imports are intentionally examples only because the provider
|
||||||
|
# requires explicit record_type/hostname in config before import.
|
||||||
|
#
|
||||||
|
# import {
|
||||||
|
# to = dynu_dns_record.grafana_lan_ddnsgeek_com
|
||||||
|
# id = var.dynu_record_import_id
|
||||||
|
# }
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
data "dynu_dns_records" "root" {
|
||||||
|
hostname = var.dynu_root_domain
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
output "dynu_domain" {
|
||||||
|
description = "Primary Dynu domain represented by this Terraform root."
|
||||||
|
value = local.dynu_domain
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_records_catalog" {
|
||||||
|
description = "Documentation catalog of expected Dynu DNS records discovered from repo service exposure."
|
||||||
|
value = local.dynu_dns_records_catalog
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_inventory" {
|
||||||
|
description = "Documentation-friendly Dynu DNS inventory for export and merge into broader infrastructure docs."
|
||||||
|
value = {
|
||||||
|
provider = "dynu"
|
||||||
|
domain = local.dynu_domain
|
||||||
|
record_count = length(local.dynu_dns_records_catalog)
|
||||||
|
records = local.dynu_dns_records_catalog
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_root_domain_id" {
|
||||||
|
description = "Dynu numeric domain ID resolved from dynu_root_domain."
|
||||||
|
value = data.dynu_dns_records.root.domain_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_root_domain_name" {
|
||||||
|
description = "Dynu root domain name resolved from dynu_root_domain."
|
||||||
|
value = data.dynu_dns_records.root.domain_name
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_records" {
|
||||||
|
description = "Full read-only DNS record inventory returned by Dynu."
|
||||||
|
value = data.dynu_dns_records.root.records
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_hostnames" {
|
||||||
|
description = "Sorted hostname list discovered for dynu_root_domain."
|
||||||
|
value = sort(distinct([for record in data.dynu_dns_records.root.records : record.hostname]))
|
||||||
|
}
|
||||||
|
|
||||||
|
output "dynu_dns_record_import_ids" {
|
||||||
|
description = "Map of Dynu DNS record identity to provider import IDs in domain_id/record_id format."
|
||||||
|
value = {
|
||||||
|
for record in data.dynu_dns_records.root.records :
|
||||||
|
format("%s/%s/%s", record.hostname, record.record_type, record.id) => format("%s/%s", record.domain_id, record.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
provider "dynu" {
|
||||||
|
# Keep auth local-only; do not commit credentials.
|
||||||
|
api_key = var.dynu_api_key
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
locals {
|
||||||
|
dynu_dns_records_catalog_base = {
|
||||||
|
auth = {
|
||||||
|
hostname = "auth"
|
||||||
|
service = "authelia"
|
||||||
|
source = "core/authelia/docker-compose.yml"
|
||||||
|
purpose = "Authentication portal"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
gitea = {
|
||||||
|
hostname = "gitea"
|
||||||
|
service = "gitea"
|
||||||
|
source = "apps/gitea/docker-compose.yml"
|
||||||
|
purpose = "Gitea service endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
gotify = {
|
||||||
|
hostname = "gotify"
|
||||||
|
service = "gotify"
|
||||||
|
source = "monitoring/gotify/docker-compose.yml"
|
||||||
|
purpose = "Gotify notifications"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
grafana = {
|
||||||
|
hostname = "grafana"
|
||||||
|
service = "grafana"
|
||||||
|
source = "monitoring/grafana/docker-compose.yml"
|
||||||
|
purpose = "Grafana monitoring UI"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
familytree = {
|
||||||
|
hostname = "familytree"
|
||||||
|
service = "gramps"
|
||||||
|
source = "apps/gramps/docker-compose.yml"
|
||||||
|
purpose = "Family tree application"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
influxdb = {
|
||||||
|
hostname = "influxdb"
|
||||||
|
service = "influxdb"
|
||||||
|
source = "monitoring/influxdb/docker-compose.yml"
|
||||||
|
purpose = "InfluxDB metrics endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
monitor_kuma = {
|
||||||
|
hostname = "monitor-kuma"
|
||||||
|
service = "uptime-kuma"
|
||||||
|
source = "monitoring/uptime-kuma/docker-compose.yml"
|
||||||
|
purpose = "Uptime Kuma monitoring UI"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
mtls_bridge = {
|
||||||
|
hostname = "mtls-bridge"
|
||||||
|
service = "mtls-bridge"
|
||||||
|
source = "monitoring/mtls-bridge/docker-compose.yml"
|
||||||
|
purpose = "mTLS bridge API"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
nextcloud = {
|
||||||
|
hostname = "nextcloud"
|
||||||
|
service = "nextcloud-webapp"
|
||||||
|
source = "apps/nextcloud/docker-compose.yml"
|
||||||
|
purpose = "Nextcloud service endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
node_red = {
|
||||||
|
hostname = "node-red"
|
||||||
|
service = "node-red"
|
||||||
|
source = "monitoring/node-red/docker-compose.yml"
|
||||||
|
purpose = "Node-RED automation UI/API"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
passbolt = {
|
||||||
|
hostname = "passbolt"
|
||||||
|
service = "passbolt-webapp"
|
||||||
|
source = "apps/passbolt/docker-compose.yml"
|
||||||
|
purpose = "Passbolt password management"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
portainer = {
|
||||||
|
hostname = "portainer"
|
||||||
|
service = "portainer"
|
||||||
|
source = "monitoring/portainer/docker-compose.yml"
|
||||||
|
purpose = "Portainer admin endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
prometheus = {
|
||||||
|
hostname = "prometheus"
|
||||||
|
service = "prometheus"
|
||||||
|
source = "monitoring/prometheus/docker-compose.yml"
|
||||||
|
purpose = "Prometheus metrics endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
searxng = {
|
||||||
|
hostname = "searxng"
|
||||||
|
service = "searxng"
|
||||||
|
source = "apps/searxng/docker-compose.yml"
|
||||||
|
purpose = "SearXNG search endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
traefik = {
|
||||||
|
hostname = "traefik"
|
||||||
|
service = "traefik"
|
||||||
|
source = "core/traefik/docker-compose.yml"
|
||||||
|
purpose = "Traefik dashboard/API endpoint"
|
||||||
|
record_type = null
|
||||||
|
ttl = null
|
||||||
|
target = null
|
||||||
|
proxied = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynu_dns_records_catalog = {
|
||||||
|
for key, record in local.dynu_dns_records_catalog_base :
|
||||||
|
key => merge(record, {
|
||||||
|
fqdn = format("%s.%s", record.hostname, local.dynu_domain)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate Terraform dynu_dns_record resources/import commands from Dynu inventory outputs."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
SCRIPT_PATH = Path(__file__).resolve()
|
||||||
|
TF_ROOT = SCRIPT_PATH.parents[1]
|
||||||
|
GENERATED_DIR = TF_ROOT / "generated"
|
||||||
|
TF_FILE = GENERATED_DIR / "dynu_dns_records.generated.tf"
|
||||||
|
IMPORT_SCRIPT = GENERATED_DIR / "import-dynu-dns-records.sh"
|
||||||
|
INVENTORY_FILE = GENERATED_DIR / "dynu_dns_records_inventory.json"
|
||||||
|
DEFAULT_RECORDS_OUTPUT = "dynu_dns_records"
|
||||||
|
REQUIRED_RECORD_FIELDS = ("id", "domain_id", "hostname", "record_type")
|
||||||
|
|
||||||
|
HEADER_TF = """# ---------------------------------------------------------------------------
|
||||||
|
# GENERATED FILE - REVIEW BEFORE USE
|
||||||
|
#
|
||||||
|
# Generated from Dynu brownfield DNS inventory.
|
||||||
|
# Do not blindly apply this file to production DNS.
|
||||||
|
# Import records into Terraform state before allowing Terraform to manage them.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
"""
|
||||||
|
|
||||||
|
HEADER_SH = """#!/usr/bin/env bash
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# GENERATED FILE - REVIEW BEFORE USE
|
||||||
|
#
|
||||||
|
# Imports existing Dynu DNS records into Terraform state.
|
||||||
|
# Does not apply changes.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
TF_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
cd "${TF_ROOT}"
|
||||||
|
|
||||||
|
# Re-running imports will fail for resources already in state.
|
||||||
|
# This script skips imports when state already contains the resource address.
|
||||||
|
"""
|
||||||
|
|
||||||
|
OPTIONAL_FIELDS = ["group", "host", "priority", "weight", "port", "flags", "tag", "value", "node_name"]
|
||||||
|
|
||||||
|
|
||||||
|
def run_terraform_output() -> dict:
|
||||||
|
if not (TF_ROOT / ".terraform").exists():
|
||||||
|
raise RuntimeError("Terraform is not initialized in infrastructure/terraform/dynu. Run: terraform init")
|
||||||
|
|
||||||
|
cmd = ["terraform", "output", "-json"]
|
||||||
|
proc = subprocess.run(cmd, cwd=TF_ROOT, capture_output=True, text=True)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
raise RuntimeError(f"Failed to run {' '.join(cmd)}:\n{proc.stderr.strip()}")
|
||||||
|
return json.loads(proc.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
def type_shape_name(value: object) -> str:
|
||||||
|
if isinstance(value, list):
|
||||||
|
return "list"
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return "object"
|
||||||
|
return type(value).__name__
|
||||||
|
|
||||||
|
|
||||||
|
def extract_records(payload: object, output_name: str) -> list[dict]:
|
||||||
|
source = payload
|
||||||
|
if isinstance(payload, list):
|
||||||
|
source = payload
|
||||||
|
elif isinstance(payload, dict):
|
||||||
|
if isinstance(payload.get("value"), list):
|
||||||
|
source = payload["value"]
|
||||||
|
elif isinstance(payload.get("records"), list):
|
||||||
|
source = payload["records"]
|
||||||
|
elif isinstance(payload.get("value"), dict) and isinstance(payload["value"].get("records"), list):
|
||||||
|
source = payload["value"]["records"]
|
||||||
|
elif output_name in payload and isinstance(payload[output_name], dict):
|
||||||
|
output_wrapper = payload[output_name]
|
||||||
|
if isinstance(output_wrapper.get("value"), list):
|
||||||
|
source = output_wrapper["value"]
|
||||||
|
elif isinstance(output_wrapper.get("value"), dict) and isinstance(output_wrapper["value"].get("records"), list):
|
||||||
|
source = output_wrapper["value"]["records"]
|
||||||
|
elif isinstance(output_wrapper.get("records"), list):
|
||||||
|
source = output_wrapper["records"]
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Output '{output_name}' does not contain a records list.")
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Output '{output_name}' not found and no records list discovered.")
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Unsupported JSON payload type: {type(payload).__name__}")
|
||||||
|
|
||||||
|
if not isinstance(source, list):
|
||||||
|
raise RuntimeError(f"Output '{output_name}' did not resolve to a list of records.")
|
||||||
|
return source
|
||||||
|
|
||||||
|
|
||||||
|
def validate_records(records: list[dict], output_name: str) -> None:
|
||||||
|
for i, record in enumerate(records):
|
||||||
|
if not isinstance(record, dict):
|
||||||
|
raise RuntimeError(f"Selected output '{output_name}' has non-object record at index {i}: {type(record).__name__}.")
|
||||||
|
missing = [field for field in REQUIRED_RECORD_FIELDS if field not in record]
|
||||||
|
if missing:
|
||||||
|
missing_text = ", ".join(missing)
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Selected output '{output_name}' contains records, but they are not importable Dynu provider records. "
|
||||||
|
f"Record #{i} is missing required fields: {missing_text}. "
|
||||||
|
"Choose an output sourced from data.dynu_dns_records.root, such as dynu_dns_records or dynu_dns_inventory."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def describe_output(output_name: str, output_wrapper: object, full_outputs: dict) -> dict:
|
||||||
|
details = {
|
||||||
|
"name": output_name,
|
||||||
|
"usable": False,
|
||||||
|
"shape": type_shape_name(output_wrapper),
|
||||||
|
"record_count": "none",
|
||||||
|
"error": "no records list found",
|
||||||
|
}
|
||||||
|
if isinstance(output_wrapper, dict) and "value" in output_wrapper:
|
||||||
|
details["shape"] = type_shape_name(output_wrapper.get("value"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
records = extract_records(full_outputs, output_name)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
details["error"] = str(exc)
|
||||||
|
return details
|
||||||
|
|
||||||
|
details["record_count"] = len(records)
|
||||||
|
try:
|
||||||
|
validate_records(records, output_name)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
details["error"] = str(exc)
|
||||||
|
if isinstance(output_wrapper, dict) and isinstance(output_wrapper.get("value"), dict) and isinstance(output_wrapper["value"].get("records"), list):
|
||||||
|
details["shape"] = "object with records list"
|
||||||
|
elif isinstance(output_wrapper, dict) and isinstance(output_wrapper.get("value"), list):
|
||||||
|
details["shape"] = "list"
|
||||||
|
return details
|
||||||
|
|
||||||
|
details["usable"] = True
|
||||||
|
details["error"] = None
|
||||||
|
if isinstance(output_wrapper, dict) and isinstance(output_wrapper.get("value"), dict) and isinstance(output_wrapper["value"].get("records"), list):
|
||||||
|
details["shape"] = "object with records list"
|
||||||
|
elif isinstance(output_wrapper, dict) and isinstance(output_wrapper.get("value"), list):
|
||||||
|
details["shape"] = "list"
|
||||||
|
return details
|
||||||
|
|
||||||
|
|
||||||
|
def choose_output_interactively(outputs: dict, descriptions: list[dict]) -> str | None:
|
||||||
|
print("\nAvailable Terraform outputs:\n")
|
||||||
|
indexed = {str(i): item for i, item in enumerate(descriptions, 1)}
|
||||||
|
by_name = {item["name"]: item for item in descriptions}
|
||||||
|
|
||||||
|
for i, item in enumerate(descriptions, 1):
|
||||||
|
print(f" {i}) {item['name']}")
|
||||||
|
print(f" usable: {'yes' if item['usable'] else 'no'}")
|
||||||
|
print(f" shape: {item['shape']}")
|
||||||
|
print(f" record count: {item['record_count']}")
|
||||||
|
if item["error"]:
|
||||||
|
print(f" reason: {item['error']}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
attempts = 0
|
||||||
|
while attempts < 3:
|
||||||
|
attempts += 1
|
||||||
|
try:
|
||||||
|
selection = input(f"Choose an output to use for DNS records [1-{len(descriptions)}], or press Enter to cancel: ").strip()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nSelection cancelled.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if selection == "":
|
||||||
|
print("Selection cancelled.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
candidate = indexed.get(selection) or by_name.get(selection)
|
||||||
|
if candidate is None:
|
||||||
|
print("Invalid selection. Enter a number from the list or an exact output name.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not candidate["usable"]:
|
||||||
|
print(f"Output '{candidate['name']}' is not usable: {candidate['error']}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
return candidate["name"]
|
||||||
|
|
||||||
|
raise RuntimeError("Too many invalid selections. Exiting without writing files.")
|
||||||
|
|
||||||
|
|
||||||
|
def tf_name(record: dict) -> str:
|
||||||
|
base = f"{record.get('hostname', '')}_{record.get('record_type', '')}_{record.get('id', '')}".lower()
|
||||||
|
base = base.replace("*", "wildcard")
|
||||||
|
base = re.sub(r"[^a-z0-9_]+", "_", base)
|
||||||
|
base = re.sub(r"_+", "_", base).strip("_")
|
||||||
|
if not base or not re.match(r"^[a-z]", base):
|
||||||
|
base = f"record_{base}" if base else "record"
|
||||||
|
if not base.endswith(str(record.get("id", ""))):
|
||||||
|
base = f"{base}_{record.get('id', '')}"
|
||||||
|
return base
|
||||||
|
|
||||||
|
|
||||||
|
def hcl_value(value):
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return "true" if value else "false"
|
||||||
|
if isinstance(value, (int, float)):
|
||||||
|
return str(value)
|
||||||
|
return json.dumps(value)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_resources(records: list[dict]) -> str:
|
||||||
|
chunks = [HEADER_TF.rstrip(), ""]
|
||||||
|
for rec in records:
|
||||||
|
name = tf_name(rec)
|
||||||
|
lines = [f'resource "dynu_dns_record" "{name}" {{']
|
||||||
|
lines.append(f" hostname = {hcl_value(rec.get('hostname'))}")
|
||||||
|
lines.append(f" record_type = {hcl_value(rec.get('record_type'))}")
|
||||||
|
if rec.get("ttl") is not None:
|
||||||
|
lines.append(f" ttl = {hcl_value(rec.get('ttl'))}")
|
||||||
|
enabled = rec.get("enabled")
|
||||||
|
if enabled is None:
|
||||||
|
enabled = rec.get("state")
|
||||||
|
if enabled is not None:
|
||||||
|
lines.append(f" enabled = {hcl_value(enabled)}")
|
||||||
|
|
||||||
|
content = rec.get("content")
|
||||||
|
rtype = str(rec.get("record_type", "")).upper()
|
||||||
|
if content in (None, "") and rtype in {"A", "AAAA"}:
|
||||||
|
lines.append(" dynamic = true")
|
||||||
|
elif content not in (None, ""):
|
||||||
|
lines.append(f" content = {hcl_value(content)}")
|
||||||
|
|
||||||
|
for field in OPTIONAL_FIELDS:
|
||||||
|
value = rec.get(field)
|
||||||
|
if value not in (None, ""):
|
||||||
|
lines.append(f" {field.ljust(11)}= {hcl_value(value)}")
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
"",
|
||||||
|
" lifecycle {",
|
||||||
|
" prevent_destroy = true",
|
||||||
|
" }",
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
])
|
||||||
|
chunks.extend(lines)
|
||||||
|
return "\n".join(chunks).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_import_script(records: list[dict]) -> str:
|
||||||
|
lines = [HEADER_SH.rstrip(), ""]
|
||||||
|
for rec in records:
|
||||||
|
name = tf_name(rec)
|
||||||
|
import_id = f"{rec['domain_id']}/{rec['id']}"
|
||||||
|
addr = f"dynu_dns_record.{name}"
|
||||||
|
lines.append(f"if terraform state show '{addr}' >/dev/null 2>&1; then")
|
||||||
|
lines.append(f" echo 'Skipping already imported: {addr}'")
|
||||||
|
lines.append("else")
|
||||||
|
lines.append(f" terraform import '{addr}' '{import_id}'")
|
||||||
|
lines.append("fi")
|
||||||
|
lines.append("")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def write_file(path: Path, content: str, dry_run: bool, overwrite: bool) -> None:
|
||||||
|
if path.exists() and not overwrite:
|
||||||
|
raise RuntimeError(f"Refusing to overwrite existing file: {path}. Re-run with --overwrite.")
|
||||||
|
if dry_run:
|
||||||
|
print(f"[dry-run] Would write {path}")
|
||||||
|
return
|
||||||
|
path.write_text(content, encoding="utf-8")
|
||||||
|
print(f"Wrote {path}")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--dry-run", action="store_true", help="Print intended output paths without writing files.")
|
||||||
|
parser.add_argument("--overwrite", "--force", action="store_true", dest="overwrite", help="Overwrite existing generated files.")
|
||||||
|
parser.add_argument("--from-file", type=Path, help="Load inventory JSON from a file instead of calling terraform output.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--records-output",
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"Terraform output name containing Dynu DNS records. "
|
||||||
|
f"Defaults to {DEFAULT_RECORDS_OUTPUT}; if missing in an interactive terminal, "
|
||||||
|
"the script prompts you to choose from available outputs."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument("--no-interactive", action="store_true", help="Disable interactive output selection.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
records_output_explicit = args.records_output is not None
|
||||||
|
records_output = args.records_output or DEFAULT_RECORDS_OUTPUT
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = json.loads(args.from_file.read_text(encoding="utf-8")) if args.from_file else run_terraform_output()
|
||||||
|
|
||||||
|
selected_output = records_output
|
||||||
|
descriptions: list[dict] = []
|
||||||
|
if isinstance(payload, dict):
|
||||||
|
descriptions = [describe_output(name, payload[name], payload) for name in sorted(payload)]
|
||||||
|
|
||||||
|
try:
|
||||||
|
records = extract_records(payload, selected_output)
|
||||||
|
validate_records(records, selected_output)
|
||||||
|
except RuntimeError as exc:
|
||||||
|
is_interactive = sys.stdin.isatty() and not args.no_interactive
|
||||||
|
should_prompt = isinstance(payload, dict) and not records_output_explicit and is_interactive
|
||||||
|
if should_prompt:
|
||||||
|
print(f"Terraform output '{selected_output}' was not found or is unusable.\n")
|
||||||
|
chosen = choose_output_interactively(payload, descriptions)
|
||||||
|
if chosen is None:
|
||||||
|
print("Exiting without writing files.")
|
||||||
|
return 1
|
||||||
|
selected_output = chosen
|
||||||
|
records = extract_records(payload, selected_output)
|
||||||
|
validate_records(records, selected_output)
|
||||||
|
else:
|
||||||
|
if isinstance(payload, dict):
|
||||||
|
available = ", ".join(sorted(payload.keys())) or "(none)"
|
||||||
|
if records_output_explicit:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Missing or unusable Terraform output '{selected_output}'. "
|
||||||
|
f"Available outputs: {available}. Details: {exc}"
|
||||||
|
)
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Missing or unusable Terraform output '{selected_output}'. "
|
||||||
|
f"Available outputs: {available}.\n\n"
|
||||||
|
"Run interactively to choose an output, or pass one explicitly, for example:\n\n"
|
||||||
|
" python3 scripts/generate-brownfield-records.py --records-output dynu_dns_inventory --dry-run"
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
GENERATED_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
write_file(INVENTORY_FILE, json.dumps(records, indent=2, sort_keys=True) + "\n", args.dry_run, args.overwrite)
|
||||||
|
write_file(TF_FILE, generate_resources(records), args.dry_run, args.overwrite)
|
||||||
|
write_file(IMPORT_SCRIPT, generate_import_script(records), args.dry_run, args.overwrite)
|
||||||
|
if not args.dry_run:
|
||||||
|
IMPORT_SCRIPT.chmod(0o755)
|
||||||
|
return 0
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f"Error: {exc}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Local-only credentials. Do not commit real values.
|
||||||
|
dynu_api_key = "replace-with-dynu-api-key"
|
||||||
|
dynu_username = null
|
||||||
|
dynu_password = null
|
||||||
|
|
||||||
|
dynu_root_domain = "lan.ddnsgeek.com"
|
||||||
|
dynu_record_import_id = "REPLACE_WITH_DYNU_RECORD_IMPORT_ID"
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
variable "dynu_root_domain" {
|
||||||
|
description = "Dynu root domain name to reconcile/import (for example: lan.ddnsgeek.com)."
|
||||||
|
type = string
|
||||||
|
default = "lan.ddnsgeek.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "dynu_api_key" {
|
||||||
|
description = "Dynu API key/token used by the Dynu Terraform provider."
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "dynu_username" {
|
||||||
|
description = "Optional Dynu username, only if required by the provider."
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "dynu_password" {
|
||||||
|
description = "Optional Dynu password, only if required by the provider."
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "dynu_record_import_id" {
|
||||||
|
description = "Placeholder import ID for a single dynu_dns_record during one-at-a-time reconciliation."
|
||||||
|
type = string
|
||||||
|
default = "REPLACE_WITH_DYNU_RECORD_IMPORT_ID"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.6.0"
|
||||||
|
|
||||||
|
required_providers {
|
||||||
|
dynu = {
|
||||||
|
source = "beatz174-bit/dynu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,10 +13,16 @@ output "physical_hosts" {
|
|||||||
value = local.physical_hosts
|
value = local.physical_hosts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output "virtual_hosts" {
|
||||||
|
description = "Virtual host/VM inventory used for documentation"
|
||||||
|
value = local.virtual_hosts
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
output "infrastructure_inventory" {
|
output "infrastructure_inventory" {
|
||||||
description = "Combined infrastructure inventory"
|
description = "Combined infrastructure inventory"
|
||||||
value = {
|
value = {
|
||||||
physical_hosts = local.physical_hosts
|
physical_hosts = local.physical_hosts
|
||||||
|
virtual_hosts = local.virtual_hosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,4 +21,59 @@ locals {
|
|||||||
notes = "Raspberry Pi host"
|
notes = "Raspberry Pi host"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Virtual host inventory for documentation output. This is intentionally
|
||||||
|
# concise and shaped for docs tooling (not a full provider object dump).
|
||||||
|
virtual_hosts = {
|
||||||
|
docker = {
|
||||||
|
name = "docker"
|
||||||
|
type = "virtual"
|
||||||
|
role = "docker-host"
|
||||||
|
proxmox_node = "pve"
|
||||||
|
vm_id = 103
|
||||||
|
management_ip = ""
|
||||||
|
os_family = "linux"
|
||||||
|
notes = "Primary Docker VM"
|
||||||
|
}
|
||||||
|
server_nixos = {
|
||||||
|
name = "server-nixos"
|
||||||
|
type = "virtual"
|
||||||
|
role = "nixos-server"
|
||||||
|
proxmox_node = "pve"
|
||||||
|
vm_id = 104
|
||||||
|
management_ip = ""
|
||||||
|
os_family = "nixos"
|
||||||
|
notes = "General-purpose NixOS VM"
|
||||||
|
}
|
||||||
|
nix_cache = {
|
||||||
|
name = "nix-cache"
|
||||||
|
type = "virtual"
|
||||||
|
role = "cache"
|
||||||
|
proxmox_node = "pve"
|
||||||
|
vm_id = 105
|
||||||
|
management_ip = ""
|
||||||
|
os_family = "linux"
|
||||||
|
notes = "Nix binary cache VM"
|
||||||
|
}
|
||||||
|
pbs = {
|
||||||
|
name = "pbs"
|
||||||
|
type = "virtual"
|
||||||
|
role = "backup"
|
||||||
|
proxmox_node = "pve"
|
||||||
|
vm_id = 106
|
||||||
|
management_ip = ""
|
||||||
|
os_family = "linux"
|
||||||
|
notes = "Proxmox Backup Server VM"
|
||||||
|
}
|
||||||
|
pihole = {
|
||||||
|
name = "pihole"
|
||||||
|
type = "virtual"
|
||||||
|
role = "dns"
|
||||||
|
proxmox_node = "pve"
|
||||||
|
vm_id = 108
|
||||||
|
management_ip = ""
|
||||||
|
os_family = "linux"
|
||||||
|
notes = "DNS filtering VM"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
site_name: Public Infrastructure Documentation
|
||||||
|
site_description: Public-facing infrastructure documentation
|
||||||
|
repo_url: https://github.com/beatz174-bit/docker
|
||||||
|
site_url: https://beatz174-bit.github.io/docker/
|
||||||
|
docs_dir: docs/public
|
||||||
|
site_dir: site-public
|
||||||
|
|
||||||
|
nav:
|
||||||
|
- Home: index.md
|
||||||
|
- Diagrams: diagrams.md
|
||||||
|
- Compose Inventory: compose-inventory.md
|
||||||
|
- Traefik Routes: traefik-routes.md
|
||||||
|
|
||||||
|
theme:
|
||||||
|
name: mkdocs
|
||||||
|
extra_css:
|
||||||
|
- stylesheets/extra.css
|
||||||
|
|
||||||
|
validation:
|
||||||
|
nav:
|
||||||
|
omitted_files: ignore
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
site_name: Infrastructure Documentation
|
||||||
|
site_description: Generated and maintained infrastructure documentation
|
||||||
|
repo_url: https://github.com/beatz174-bit/docker
|
||||||
|
docs_dir: docs
|
||||||
|
|
||||||
|
nav:
|
||||||
|
- Home: index.md
|
||||||
|
- Docker Environment: docker.md
|
||||||
|
- Networking: networking.md
|
||||||
|
- Monitoring: monitoring.md
|
||||||
|
- Automation: automation.md
|
||||||
|
- Operations: operations.md
|
||||||
|
- Public Showcase: showcase.md
|
||||||
|
- Generated:
|
||||||
|
- Compose Inventory: generated/compose-inventory.md
|
||||||
|
- Traefik Routes: generated/traefik-routes.md
|
||||||
|
|
||||||
|
theme:
|
||||||
|
name: mkdocs
|
||||||
|
|
||||||
|
validation:
|
||||||
|
nav:
|
||||||
|
omitted_files: ignore
|
||||||
|
exclude_docs: |
|
||||||
|
README.md
|
||||||
@@ -1,3 +1,28 @@
|
|||||||
{
|
{
|
||||||
"dockerUpdateAttempts": {}
|
"dockerUpdateAttempts": {
|
||||||
|
"nextcloud-redis|redis:latest|docker": {
|
||||||
|
"time": 1778483142172,
|
||||||
|
"status": "test_failed",
|
||||||
|
"failedAt": 1778483206801,
|
||||||
|
"notified": true
|
||||||
|
},
|
||||||
|
"telegraf|telegraf:latest|raspi": {
|
||||||
|
"time": 1778569512188,
|
||||||
|
"status": "pull_failed",
|
||||||
|
"failedAt": 1778569512904,
|
||||||
|
"notified": true
|
||||||
|
},
|
||||||
|
"traefik|traefik:3|raspi": {
|
||||||
|
"time": 1778569512188,
|
||||||
|
"status": "pull_failed",
|
||||||
|
"failedAt": 1778569512880,
|
||||||
|
"notified": true
|
||||||
|
},
|
||||||
|
"searxng-webapp|searxng/searxng:latest|docker": {
|
||||||
|
"time": 1778613012267,
|
||||||
|
"status": "success",
|
||||||
|
"completedAt": 1778613022513,
|
||||||
|
"notified": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -442,3 +442,79 @@
|
|||||||
{"ts":"2026-04-17T07:05:12.795Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
{"ts":"2026-04-17T07:05:12.795Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
{"ts":"2026-04-17T07:05:12.795Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
{"ts":"2026-04-17T07:05:12.795Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
{"ts":"2026-04-17T19:11:29.490Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
{"ts":"2026-04-17T19:11:29.490Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:05:42.645Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:05:42.646Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:05:59.089Z","flow":"docker-updates","event":"completed","container":"gitea","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:06:45.971Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:06:45.971Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:06:56.112Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-21T07:06:56.112Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:05:43.226Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:05:43.226Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:05:43.237Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:05:43.237Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:06:55.068Z","flow":"docker-updates","event":"completed","container":"influxdb","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-22T07:06:55.069Z","flow":"docker-updates","event":"completed","container":"influxdb","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-22T11:50:51.776Z","flow":"docker-updates","event":"completed","container":"gitea","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-24T07:06:46.595Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-24T07:06:46.596Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-25T07:06:01.141Z","flow":"docker-updates","event":"completed","container":"gitea","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":1,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-25T07:06:05.952Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-25T08:21:45.451Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-25T08:21:45.451Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-26T07:05:42.647Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-26T07:05:42.647Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-26T07:06:59.195Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-26T19:10:52.147Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-26T19:10:52.183Z","flow":"docker-updates","event":"completed","container":"gitea","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-27T07:05:42.810Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-27T07:05:42.811Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-27T07:05:42.820Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-27T07:05:42.820Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-27T19:11:52.376Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-29T07:06:01.058Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-30T07:05:42.792Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-30T07:05:42.793Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-04-30T07:07:03.429Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-04-30T07:55:52.210Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-02T07:06:02.030Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-03T19:11:00.985Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-04T07:05:43.437Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-04T07:05:43.437Z","flow":"docker-updates","event":"completed","container":"gramps-web-celery","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-04T07:05:43.478Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-04T07:05:43.478Z","flow":"docker-updates","event":"completed","container":"gramps-web","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-04T07:06:49.671Z","flow":"docker-updates","event":"completed","container":"pihole-exporter","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-05T07:06:53.883Z","flow":"docker-updates","event":"completed","container":"influxdb","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-05T07:06:53.883Z","flow":"docker-updates","event":"completed","container":"influxdb","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-05T07:15:53.751Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-05T19:11:46.870Z","flow":"docker-updates","event":"completed","container":"pihole-exporter","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-06T07:05:43.370Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-06T07:05:43.371Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-06T07:06:52.049Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-06T07:06:52.050Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-06T07:07:04.711Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-06T19:21:00.548Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-07T07:05:43.486Z","flow":"docker-updates","event":"completed","container":"portainer-agent","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-07T07:05:43.486Z","flow":"docker-updates","event":"completed","container":"portainer-agent","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-07T07:06:00.453Z","flow":"docker-updates","event":"completed","container":"gramps-redis","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-07T07:06:54.399Z","flow":"docker-updates","event":"completed","container":"portainer","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-07T07:16:46.710Z","flow":"docker-updates","event":"completed","container":"pihole-exporter","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-07T19:11:59.538Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-08T07:25:53.059Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-08T19:10:53.346Z","flow":"docker-updates","event":"completed","container":"gramps-redis","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-08T19:11:48.007Z","flow":"docker-updates","event":"completed","container":"portainer","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":1,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-08T19:21:46.912Z","flow":"docker-updates","event":"completed","container":"pihole-exporter","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-09T07:05:43.856Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-09T07:05:43.856Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-09T07:06:56.795Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-09T07:06:56.795Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-09T07:16:59.180Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-09T19:30:53.415Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-11T07:06:02.234Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-11T07:06:46.802Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"failed","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-11T07:06:46.802Z","flow":"docker-updates","event":"completed","container":"nextcloud-redis","project":"unknown","host":"docker","status":"locked","success":0,"failed":1,"duration_ms":0,"code":0,"error":""}
|
||||||
|
{"ts":"2026-05-12T07:05:12.881Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-12T07:05:12.881Z","flow":"docker-updates","event":"completed","container":"traefik","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-12T07:05:12.904Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"failed","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-12T07:05:12.904Z","flow":"docker-updates","event":"completed","container":"telegraf","project":"unknown","host":"raspi","status":"locked","success":0,"failed":1,"duration_ms":0,"code":1,"error":""}
|
||||||
|
{"ts":"2026-05-12T19:10:22.519Z","flow":"docker-updates","event":"completed","container":"searxng-webapp","project":"unknown","host":"docker","status":"success","success":1,"failed":0,"duration_ms":0,"code":0,"error":""}
|
||||||
|
|||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
inv_dir="${repo_root}/infrastructure/terraform/proxmox"
|
||||||
|
json_out="${repo_root}/data/terraform/proxmox-inventory.json"
|
||||||
|
md_out="${repo_root}/docs/generated/host-topology.md"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "${json_out}")" "$(dirname "${md_out}")"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "${inv_dir}"
|
||||||
|
terraform output -json infrastructure_inventory > "${json_out}"
|
||||||
|
)
|
||||||
|
|
||||||
|
python3 "${repo_root}/scripts/docs/generate_host_topology.py" \
|
||||||
|
--input "${json_out}" \
|
||||||
|
--output "${md_out}"
|
||||||
|
|
||||||
|
echo "Generated: ${md_out}"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
PROJECT_ROOT=.
|
||||||
|
TZ=UTC
|
||||||
|
DOMAIN=example.internal
|
||||||
|
SECRETS_ENV=scripts/docs/ci-secrets-placeholder.env
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
EXAMPLE_PASSWORD=placeholder
|
||||||
|
EXAMPLE_TOKEN=placeholder
|
||||||
Executable
+115
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
ALLOW_STALE_TERRAFORM=0
|
||||||
|
SKIP_TERRAFORM=0
|
||||||
|
SKIP_DNS=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'USAGE'
|
||||||
|
Usage: scripts/docs/generate-all.sh [--allow-stale-terraform] [--skip-terraform] [--skip-dns]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--allow-stale-terraform Use existing Terraform JSON when terraform is unavailable.
|
||||||
|
--skip-terraform Skip Terraform refresh and require existing JSON artifacts.
|
||||||
|
--skip-dns Skip Dynu DNS Terraform refresh.
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--allow-stale-terraform) ALLOW_STALE_TERRAFORM=1 ;;
|
||||||
|
--skip-terraform) SKIP_TERRAFORM=1 ;;
|
||||||
|
--skip-dns) SKIP_DNS=1 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) echo "ERROR: Unknown option: $1" >&2; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir -p docs/generated docs/diagrams docs/public data/terraform
|
||||||
|
[[ -d infrastructure/terraform/proxmox ]] && mkdir -p infrastructure/terraform/proxmox/generated
|
||||||
|
[[ -d infrastructure/terraform/dynu ]] && mkdir -p infrastructure/terraform/dynu/generated
|
||||||
|
|
||||||
|
if ! scripts/docs/render-compose-config.sh; then
|
||||||
|
echo "ERROR: Docker Compose config render failed." >&2
|
||||||
|
echo "Check services-up.sh, compose files, and default-environment.env." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -s docs/generated/docker-compose.resolved.yml ]]; then
|
||||||
|
echo "ERROR: Expected non-empty docs/generated/docker-compose.resolved.yml after compose render." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PROXMOX_DIR="infrastructure/terraform/proxmox"
|
||||||
|
PRIMARY_HOST_INV="data/terraform/proxmox-inventory.json"
|
||||||
|
FALLBACK_HOST_INV="infrastructure/terraform/proxmox/generated/infrastructure_inventory.json"
|
||||||
|
HOST_INVENTORY=""
|
||||||
|
|
||||||
|
if [[ -d "$PROXMOX_DIR" ]]; then
|
||||||
|
if [[ "$SKIP_TERRAFORM" -eq 1 ]]; then
|
||||||
|
echo "INFO: --skip-terraform set; using pre-generated Terraform JSON artifacts." >&2
|
||||||
|
elif command -v terraform >/dev/null 2>&1; then
|
||||||
|
scripts/docs/build_host_topology.sh
|
||||||
|
elif [[ "$ALLOW_STALE_TERRAFORM" -eq 1 ]]; then
|
||||||
|
echo "WARNING: terraform unavailable; using stale Terraform JSON due to --allow-stale-terraform." >&2
|
||||||
|
else
|
||||||
|
echo "ERROR: terraform is not available, but $PROXMOX_DIR exists and must be refreshed." >&2
|
||||||
|
echo "Install terraform and rerun scripts/docs/generate-all.sh, or use --allow-stale-terraform/--skip-terraform intentionally." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ERROR: Required Terraform directory missing: $PROXMOX_DIR" >&2
|
||||||
|
echo "Physical topology diagrams require host inventory from Terraform." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for p in "$PRIMARY_HOST_INV" "$FALLBACK_HOST_INV"; do
|
||||||
|
if [[ -s "$p" ]]; then
|
||||||
|
HOST_INVENTORY="$p"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -z "$HOST_INVENTORY" ]]; then
|
||||||
|
echo "ERROR: Host topology inventory is missing." >&2
|
||||||
|
echo "Expected one of: $PRIMARY_HOST_INV or $FALLBACK_HOST_INV" >&2
|
||||||
|
echo "Run scripts/docs/build_host_topology.sh from a machine with Terraform state access, then rerun scripts/docs/generate-all.sh." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DNS_INVENTORY="infrastructure/terraform/dynu/generated/dynu_dns_records_inventory.json"
|
||||||
|
if [[ "$SKIP_DNS" -eq 0 && -d infrastructure/terraform/dynu ]]; then
|
||||||
|
if [[ "$SKIP_TERRAFORM" -eq 1 ]]; then
|
||||||
|
echo "INFO: Skipping Dynu Terraform refresh due to --skip-terraform." >&2
|
||||||
|
elif command -v terraform >/dev/null 2>&1; then
|
||||||
|
scripts/docs/generate_dynu_dns_inventory.sh
|
||||||
|
elif [[ "$ALLOW_STALE_TERRAFORM" -eq 1 ]]; then
|
||||||
|
echo "WARNING: terraform unavailable; using stale Dynu DNS inventory due to --allow-stale-terraform." >&2
|
||||||
|
else
|
||||||
|
echo "ERROR: terraform unavailable; cannot refresh Dynu DNS inventory while infrastructure/terraform/dynu exists." >&2
|
||||||
|
echo "Install terraform and rerun, or use --allow-stale-terraform/--skip-terraform intentionally." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 scripts/docs/generate-compose-inventory.py docs/generated/docker-compose.resolved.yml docs/generated/compose-inventory.md
|
||||||
|
python3 scripts/docs/generate-traefik-routes.py docs/generated/docker-compose.resolved.yml docs/generated/traefik-routes.md
|
||||||
|
python3 scripts/docs/generate-docs-index.py docs/generated/index.md
|
||||||
|
|
||||||
|
GEN_ARGS=(--compose docs/generated/docker-compose.resolved.yml --out-dir docs/diagrams --domain-display redacted-label --host-inventory "$HOST_INVENTORY")
|
||||||
|
[[ -s "$DNS_INVENTORY" && "$SKIP_DNS" -eq 0 ]] && GEN_ARGS+=(--dns-inventory "$DNS_INVENTORY")
|
||||||
|
python3 scripts/docs/generate-diagrams.py "${GEN_ARGS[@]}"
|
||||||
|
python3 scripts/docs/sanitize-public-docs.py docs/generated docs/diagrams docs/public
|
||||||
|
|
||||||
|
[[ -s docs/public/physical-topology.svg ]] || { echo "ERROR: docs/public/physical-topology.svg missing or empty." >&2; exit 1; }
|
||||||
|
if grep -Fq "Host inventory JSON not found" docs/public/physical-topology.svg || grep -Fq "Generate terraform inventory" docs/public/physical-topology.svg; then
|
||||||
|
echo "ERROR: docs/public/physical-topology.svg contains placeholder/error text; host inventory refresh failed." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[[ -s docs/public/docker-traefik-dynu.svg ]] || { echo "ERROR: docs/public/docker-traefik-dynu.svg missing or empty." >&2; exit 1; }
|
||||||
|
[[ -s docs/generated/docker-compose.resolved.yml ]] || { echo "ERROR: docs/generated/docker-compose.resolved.yml missing or empty." >&2; exit 1; }
|
||||||
|
[[ -s docs/generated/host-topology.md ]] || { echo "ERROR: docs/generated/host-topology.md missing or empty." >&2; exit 1; }
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import hashlib
|
||||||
|
import sys, yaml
|
||||||
|
|
||||||
|
def md(v): return str(v).replace('|','\\|') if v is not None else ''
|
||||||
|
|
||||||
|
inp,out=sys.argv[1],sys.argv[2]
|
||||||
|
with open(inp) as f: c=yaml.safe_load(f) or {}
|
||||||
|
svcs=c.get('services',{}) or {}
|
||||||
|
nets=c.get('networks',{}) or {}
|
||||||
|
vols=c.get('volumes',{}) or {}
|
||||||
|
raw=open(inp,'rb').read()
|
||||||
|
fingerprint=hashlib.sha256(raw).hexdigest()[:12]
|
||||||
|
lines=["# Docker Compose Inventory","",f"Source fingerprint: `{fingerprint}`","","## Summary","","| Item | Count |","|---|---:|",f"| Services | {len(svcs)} |",f"| Networks | {len(nets)} |",f"| Volumes | {len(vols)} |","","## Services","","| Service | Container | Image | Build | Profiles | Networks | Ports | Restart |","|---|---|---|---|---|---|---|---|"]
|
||||||
|
for n,s in sorted(svcs.items()):
|
||||||
|
build=s.get('build','')
|
||||||
|
if isinstance(build,dict): build=build.get('context','')
|
||||||
|
ports=', '.join(str(p) for p in s.get('ports',[]) )
|
||||||
|
networks=', '.join((s.get('networks') or {}).keys() if isinstance(s.get('networks'),dict) else (s.get('networks') or []))
|
||||||
|
profiles=', '.join(s.get('profiles',[]) or [])
|
||||||
|
lines.append(f"| {md(n)} | {md(s.get('container_name',''))} | {md(s.get('image',''))} | {md(build)} | {md(profiles)} | {md(networks)} | {md(ports)} | {md(s.get('restart',''))} |")
|
||||||
|
lines += ["","## Networks","","| Network | Driver | External |","|---|---|---|"]
|
||||||
|
for n,v in sorted(nets.items()): lines.append(f"| {md(n)} | {md((v or {}).get('driver',''))} | {md((v or {}).get('external',False))} |")
|
||||||
|
lines += ["","## Volumes","","| Volume | External |","|---|---|"]
|
||||||
|
for n,v in sorted(vols.items()): lines.append(f"| {md(n)} | {md((v or {}).get('external',False))} |")
|
||||||
|
open(out,'w').write('\n'.join(lines)+'\n')
|
||||||
@@ -0,0 +1,360 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
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 {}
|
||||||
|
|
||||||
|
|
||||||
|
PARENT_KEYS = ("node", "node_name", "host", "physical_host", "hypervisor_host", "proxmox_node")
|
||||||
|
|
||||||
|
|
||||||
|
def display_domain(value: str, mode: str) -> str:
|
||||||
|
if mode == "full":
|
||||||
|
return value
|
||||||
|
if mode == "placeholder":
|
||||||
|
return "<internal-domain>" if INTERNAL_DOMAIN_RE.search(value) else value
|
||||||
|
if INTERNAL_DOMAIN_RE.search(value):
|
||||||
|
label = re.sub(r"\.lan\.ddnsgeek\.com$", "", value)
|
||||||
|
return f"{label}.<domain>"
|
||||||
|
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 categorize_service(service_name: str) -> str:
|
||||||
|
s = service_name.lower()
|
||||||
|
if any(k in s for k in ["traefik", "authelia", "oauth", "auth", "proxy", "nginx", "caddy"]):
|
||||||
|
return "edge/proxy/auth"
|
||||||
|
if any(k in s for k in ["prometheus", "grafana", "loki", "promtail", "alert", "node-exporter", "cadvisor"]):
|
||||||
|
return "monitoring"
|
||||||
|
if any(k in s for k in ["watchtower", "diun", "ansible", "cron", "runner", "backup"]):
|
||||||
|
return "automation"
|
||||||
|
if any(k in s for k in ["postgres", "mariadb", "mysql", "redis", "minio", "nfs", "storage", "db", "queue"]):
|
||||||
|
return "storage/database/support"
|
||||||
|
return "apps"
|
||||||
|
|
||||||
|
|
||||||
|
def load_inventory(path: Path | None) -> dict:
|
||||||
|
if not path or not path.exists():
|
||||||
|
return {}
|
||||||
|
payload = json.loads(path.read_text())
|
||||||
|
return payload.get("value", payload) if isinstance(payload, dict) else {}
|
||||||
|
|
||||||
|
|
||||||
|
def to_records(data) -> list[dict]:
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return []
|
||||||
|
out = []
|
||||||
|
for key, value in data.items():
|
||||||
|
if isinstance(value, dict):
|
||||||
|
rec = dict(value)
|
||||||
|
rec.setdefault("_key", str(key))
|
||||||
|
rec.setdefault("name", rec.get("hostname") or rec.get("vm_name") or str(key))
|
||||||
|
out.append(rec)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def parent_name(item: dict) -> str:
|
||||||
|
for k in PARENT_KEYS:
|
||||||
|
v = item.get(k)
|
||||||
|
if v:
|
||||||
|
return str(v)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_physical_topology(compose: dict, inventory: dict, out_dot: Path, out_svg: Path) -> None:
|
||||||
|
physical = to_records(inventory.get("physical_hosts", {}))
|
||||||
|
virtual = to_records(inventory.get("virtual_hosts", {})) + to_records(inventory.get("vms", {}))
|
||||||
|
if not physical and not virtual:
|
||||||
|
lines = [
|
||||||
|
"digraph PhysicalTopology {",
|
||||||
|
" graph [rankdir=LR, fontname=\"Helvetica\", nodesep=1.0, ranksep=1.5];",
|
||||||
|
' "placeholder:inventory" [shape=note, style="filled", fillcolor="#fef3c7", label="Host inventory JSON not found.\\nGenerate terraform inventory and rerun scripts/docs/generate-all.sh\\n(--host-inventory <path>)."];',
|
||||||
|
]
|
||||||
|
lines.append("}")
|
||||||
|
write_dot(out_dot, lines)
|
||||||
|
render_svg(out_dot, out_svg)
|
||||||
|
return
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
"digraph PhysicalTopology {",
|
||||||
|
" graph [rankdir=LR, compound=true, splines=polyline, nodesep=0.95, ranksep=1.7, ratio=compress, fontname=\"Helvetica\", fontsize=13, concentrate=true, newrank=true];",
|
||||||
|
" node [fontname=\"Helvetica\", fontsize=12, style=\"rounded,filled\", fillcolor=\"#ffffff\"];",
|
||||||
|
" edge [fontname=\"Helvetica\", fontsize=10, color=\"#64748b\"];",
|
||||||
|
]
|
||||||
|
phys_names = {str(p.get("name")): p for p in physical}
|
||||||
|
children: dict[str, list[dict]] = {k: [] for k in phys_names}
|
||||||
|
orphans: list[dict] = []
|
||||||
|
for vm in virtual:
|
||||||
|
parent = parent_name(vm)
|
||||||
|
if parent in children:
|
||||||
|
children[parent].append(vm)
|
||||||
|
else:
|
||||||
|
orphans.append(vm)
|
||||||
|
for host, record in sorted(phys_names.items()):
|
||||||
|
host_role = str(record.get("role", "") or "")
|
||||||
|
cluster_label = f"{host}\\n{host_role}" if host_role else host
|
||||||
|
lines.extend([
|
||||||
|
f' subgraph "cluster_{host}" {{',
|
||||||
|
f' label="{cluster_label}";',
|
||||||
|
' style="rounded,filled";',
|
||||||
|
' color="#60a5fa";',
|
||||||
|
' fillcolor="#eff6ff";',
|
||||||
|
f' "phys:{host}" [label="{host}", shape=box3d, fillcolor="#bfdbfe"];',
|
||||||
|
])
|
||||||
|
for vm in sorted(children.get(host, []), key=lambda x: str(x.get("name", "")).lower()):
|
||||||
|
vm_name = str(vm.get("name"))
|
||||||
|
vm_role = str(vm.get("role", "") or "virtual host")
|
||||||
|
cluster_id = f"cluster_{host}_{re.sub(r'[^a-zA-Z0-9]+', '_', vm_name)}"
|
||||||
|
lines.extend([
|
||||||
|
f' subgraph "{cluster_id}" {{',
|
||||||
|
f' label="{vm_name}";',
|
||||||
|
' style="rounded,dashed";',
|
||||||
|
' color="#bfdbfe";',
|
||||||
|
' fillcolor="#f8fbff";',
|
||||||
|
f' "vm:{vm_name}" [label="{vm_name}\\n{vm_role}", shape=component, fillcolor="#dcfce7"];',
|
||||||
|
])
|
||||||
|
if "docker" in vm_role.lower() or "docker" in vm_name.lower():
|
||||||
|
lines.append(f' "role:{vm_name}" [label="Docker host", shape=box, fillcolor="#fef3c7"];')
|
||||||
|
lines.append(f' "vm:{vm_name}" -> "role:{vm_name}" [style=dashed, label="runs"];')
|
||||||
|
lines.append(' }')
|
||||||
|
lines.append(f' "phys:{host}" -> "vm:{vm_name}" [label="hosts"];')
|
||||||
|
lines.append(' }')
|
||||||
|
if orphans:
|
||||||
|
lines.extend([
|
||||||
|
' subgraph "cluster_orphans" {',
|
||||||
|
' label="Unmapped virtual hosts"; style="rounded,dashed"; color="#d1d5db";',
|
||||||
|
])
|
||||||
|
for vm in sorted(orphans, key=lambda x: str(x.get("name", "")).lower()):
|
||||||
|
vm_name = str(vm.get("name"))
|
||||||
|
lines.append(f' "vm:{vm_name}" [label="{vm_name}", shape=component, fillcolor="#fee2e2"];')
|
||||||
|
lines.append(" }")
|
||||||
|
|
||||||
|
lines.extend([
|
||||||
|
' subgraph "cluster_legend" {',
|
||||||
|
' label="Legend"; style="rounded"; color="#d1d5db";',
|
||||||
|
' "leg_host" [label="Physical host", shape=box3d, fillcolor="#eff6ff"];',
|
||||||
|
' "leg_vm" [label="Virtual machine", shape=component, fillcolor="#dcfce7"];',
|
||||||
|
' "leg_role" [label="Hosted role", shape=box, fillcolor="#fef3c7"];',
|
||||||
|
' "leg_host" -> "leg_vm" [label="hosts"];',
|
||||||
|
' "leg_vm" -> "leg_role" [style=dashed, label="runs"];',
|
||||||
|
' }',
|
||||||
|
"}",
|
||||||
|
])
|
||||||
|
write_dot(out_dot, lines)
|
||||||
|
render_svg(out_dot, out_svg)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_docker_traefik_dynu(compose: dict, dns_inventory: dict, domain_mode: str, out_dot: Path, out_svg: Path) -> None:
|
||||||
|
services = compose.get("services") or {}
|
||||||
|
networks = compose.get("networks") or {}
|
||||||
|
lines = [
|
||||||
|
"digraph DockerTraefikDynu {",
|
||||||
|
" graph [rankdir=LR, compound=true, splines=polyline, nodesep=0.9, ranksep=1.6, fontname=\"Helvetica\", concentrate=true, newrank=true];",
|
||||||
|
" node [fontname=\"Helvetica\", fontsize=11, style=\"rounded,filled\"];",
|
||||||
|
" edge [fontname=\"Helvetica\", fontsize=9, color=\"#334155\"];",
|
||||||
|
' "dynu" [label="Dynu / Public DNS", shape=box, fillcolor="#fde68a"];',
|
||||||
|
' "svc:traefik" [label="Traefik", shape=box, fillcolor="#bfdbfe"];',
|
||||||
|
' "dynu" -> "svc:traefik" [penwidth=1.6];',
|
||||||
|
]
|
||||||
|
|
||||||
|
routes: dict[str, dict] = {}
|
||||||
|
dns_nodes: set[str] = set()
|
||||||
|
|
||||||
|
for svc_name, svc in sorted(services.items()):
|
||||||
|
labels = parse_labels(svc)
|
||||||
|
router_prefix = "traefik.http.routers."
|
||||||
|
service_prefix = "traefik.http.services."
|
||||||
|
lb_ports = {}
|
||||||
|
for k, v in labels.items():
|
||||||
|
if k.startswith(service_prefix) and k.endswith(".loadbalancer.server.port"):
|
||||||
|
lb_ports[k[len(service_prefix):].split(".", 1)[0]] = v
|
||||||
|
|
||||||
|
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", "")
|
||||||
|
target = labels.get(f"{router_prefix}{router}.service", svc_name)
|
||||||
|
middlewares = labels.get(f"{router_prefix}{router}.middlewares", "")
|
||||||
|
tls = labels.get(f"{router_prefix}{router}.tls", "false")
|
||||||
|
port = lb_ports.get(target, "")
|
||||||
|
badges = []
|
||||||
|
if str(tls).lower() in ("true", "1"):
|
||||||
|
badges.append("TLS")
|
||||||
|
mw_low = middlewares.lower()
|
||||||
|
if "authelia" in mw_low:
|
||||||
|
badges.append("authelia")
|
||||||
|
if "mtls" in mw_low:
|
||||||
|
badges.append("mTLS")
|
||||||
|
hosts = [display_domain(h, domain_mode) for h in extract_hosts(rule)]
|
||||||
|
if not hosts:
|
||||||
|
continue
|
||||||
|
info = routes.setdefault(svc_name, {"hosts": set(), "port": port, "badges": set()})
|
||||||
|
info["hosts"].update(hosts)
|
||||||
|
if port:
|
||||||
|
info["port"] = port
|
||||||
|
info["badges"].update(badges)
|
||||||
|
|
||||||
|
for svc_name, info in sorted(routes.items()):
|
||||||
|
label = svc_name
|
||||||
|
if info.get("port"):
|
||||||
|
label += f"\n:{info['port']}"
|
||||||
|
if info.get("badges"):
|
||||||
|
label += "\n[" + ", ".join(sorted(info["badges"])) + "]"
|
||||||
|
lines.append(f' "svc:{svc_name}" [label="{label}", shape=box, fillcolor="#dcfce7"];')
|
||||||
|
lines.append(f' "svc:traefik" -> "svc:{svc_name}" [penwidth=1.4];')
|
||||||
|
for host in sorted(info["hosts"]):
|
||||||
|
dns_nodes.add(host)
|
||||||
|
lines.append(f' "dns:{host}" [label="{host}", shape=note, fillcolor="#fef3c7"];')
|
||||||
|
lines.append(f' "dns:{host}" -> "dynu";')
|
||||||
|
for record in (dns_inventory.get("records", []) if isinstance(dns_inventory, dict) else []):
|
||||||
|
host = record.get("hostname") or record.get("name")
|
||||||
|
if not host:
|
||||||
|
continue
|
||||||
|
host_disp = display_domain(str(host), domain_mode)
|
||||||
|
if host_disp in dns_nodes:
|
||||||
|
continue
|
||||||
|
dns_nodes.add(host_disp)
|
||||||
|
lines.append(f' "dns:{host_disp}" [label="{host_disp}", shape=note, fillcolor="#fef3c7"];')
|
||||||
|
lines.append(f' "dns:{host_disp}" -> "dynu" [style=dashed, color=\"#94a3b8\"];')
|
||||||
|
|
||||||
|
lines.append(' { rank=same; ' + '; '.join([f'"dns:{d}"' for d in sorted(dns_nodes)]) + '; }' if dns_nodes else '')
|
||||||
|
|
||||||
|
lines.append(' subgraph "cluster_networks" {')
|
||||||
|
lines.append(' label="Docker backend networks"; style="rounded,dashed"; color="#d1d5db";')
|
||||||
|
for net in sorted(networks.keys()):
|
||||||
|
lines.append(f' "net:{net}" [label="{net}", shape=ellipse, fillcolor="#f8fafc"];')
|
||||||
|
lines.append(' }')
|
||||||
|
|
||||||
|
for svc_name in sorted(routes.keys()):
|
||||||
|
svc = services.get(svc_name, {})
|
||||||
|
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}" [style=dashed, color="#94a3b8", arrowsize=0.7];')
|
||||||
|
|
||||||
|
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")
|
||||||
|
parser.add_argument("--host-inventory")
|
||||||
|
parser.add_argument("--dns-inventory")
|
||||||
|
parser.add_argument("--domain-display", choices=["full", "redacted-label", "placeholder"], default="redacted-label")
|
||||||
|
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 <compose.yml> --out-dir <dir>")
|
||||||
|
|
||||||
|
out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
compose = load_compose(compose_path)
|
||||||
|
host_inventory = load_inventory(Path(args.host_inventory)) if args.host_inventory else {}
|
||||||
|
dns_inventory = load_inventory(Path(args.dns_inventory)) if args.dns_inventory else {}
|
||||||
|
|
||||||
|
generate_docker_traefik_dynu(compose, dns_inventory, args.domain_display, out_dir / "docker-traefik-dynu.dot", out_dir / "docker-traefik-dynu.svg")
|
||||||
|
generate_physical_topology(compose, host_inventory, 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()
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
out = Path(sys.argv[1])
|
||||||
|
out.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
out.write_text(
|
||||||
|
"""# Generated Documentation
|
||||||
|
|
||||||
|
This directory contains documentation generated automatically from repository configuration.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- [Compose file list](compose-files.txt)
|
||||||
|
- [Resolved Docker Compose config](docker-compose.resolved.yml)
|
||||||
|
- [Compose inventory](compose-inventory.md)
|
||||||
|
- [Traefik routes](traefik-routes.md)
|
||||||
|
- [Docker Compose diagram](../diagrams/docker-compose.svg)
|
||||||
|
"""
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys,yaml,glob
|
||||||
|
out=sys.argv[1]
|
||||||
|
patterns=["monitoring/prometheus/rules/**/*.yml","monitoring/prometheus/rules/**/*.yaml","**/prometheus/rules/**/*.yml","**/prometheus/rules/**/*.yaml"]
|
||||||
|
files=sorted({f for p in patterns for f in glob.glob(p,recursive=True)})
|
||||||
|
lines=["# Prometheus Rules","", "| File | Group | Alert | Expr | For | Labels | Annotations |","|---|---|---|---|---|---|---|"]
|
||||||
|
if not files:
|
||||||
|
open(out,'w').write("# Prometheus Rules\n\nNo Prometheus rule files were found.\n"); sys.exit(0)
|
||||||
|
for fp in files:
|
||||||
|
try:data=yaml.safe_load(open(fp)) or {}
|
||||||
|
except Exception as e: raise SystemExit(f"Malformed YAML in {fp}: {e}")
|
||||||
|
for g in data.get('groups',[]) or []:
|
||||||
|
for r in g.get('rules',[]) or []:
|
||||||
|
lines.append(f"| {fp} | {g.get('name','')} | {r.get('alert','')} | {str(r.get('expr','')).replace('|','\\|')} | {r.get('for','')} | {r.get('labels',{})} | {r.get('annotations',{})} |")
|
||||||
|
open(out,'w').write('\n'.join(lines)+'\n')
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys,yaml,re
|
||||||
|
inp,out=sys.argv[1],sys.argv[2]
|
||||||
|
with open(inp) as f: c=yaml.safe_load(f) or {}
|
||||||
|
rows=[]
|
||||||
|
for sname,svc in (c.get('services') or {}).items():
|
||||||
|
labels=svc.get('labels') or {}
|
||||||
|
if isinstance(labels,list):
|
||||||
|
d={}
|
||||||
|
for l in labels:
|
||||||
|
if '=' in str(l):k,v=str(l).split('=',1);d[k]=v
|
||||||
|
labels=d
|
||||||
|
routers={}
|
||||||
|
for k,v in labels.items():
|
||||||
|
m=re.match(r'traefik\.http\.routers\.([^.]+)\.(rule|entrypoints|tls|middlewares)$',k)
|
||||||
|
if m: routers.setdefault(m.group(1),{})[m.group(2)]=v
|
||||||
|
ports={}
|
||||||
|
for k,v in labels.items():
|
||||||
|
m=re.match(r'traefik\.http\.services\.([^.]+)\.loadbalancer\.server\.port$',k)
|
||||||
|
if m: ports[m.group(1)]=v
|
||||||
|
for r,rv in routers.items():
|
||||||
|
rows.append((sname,r,rv.get('rule',''),rv.get('entrypoints',''),rv.get('tls',''),rv.get('middlewares',''),ports.get(r,'')))
|
||||||
|
lines=["# Traefik Routes","", "| Service | Router | Rule | Entrypoints | TLS | Middlewares | Target Port |","|---|---|---|---|---|---|---|"]
|
||||||
|
if not rows:
|
||||||
|
lines=["# Traefik Routes","","No Traefik routes were detected."]
|
||||||
|
else:
|
||||||
|
for r in sorted(rows): lines.append('| '+' | '.join(str(x).replace('|','\\|') for x in r)+' |')
|
||||||
|
open(out,'w').write('\n'.join(lines)+'\n')
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
dynu_dir="${repo_root}/infrastructure/terraform/dynu"
|
||||||
|
out_json="${dynu_dir}/generated/dynu_dns_records_inventory.json"
|
||||||
|
|
||||||
|
if [[ ! -d "${dynu_dir}" ]]; then
|
||||||
|
echo "ERROR: Dynu Terraform directory not found at ${dynu_dir}." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v terraform >/dev/null 2>&1; then
|
||||||
|
echo "ERROR: terraform is required to refresh Dynu DNS inventory." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "${out_json}")"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "${dynu_dir}"
|
||||||
|
if terraform output -json dynu_dns_inventory > "${out_json}"; then
|
||||||
|
:
|
||||||
|
elif terraform output -json dynu_dns_records_catalog > "${out_json}"; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "ERROR: Failed to export Dynu DNS inventory from Terraform outputs. Tried: dynu_dns_inventory, dynu_dns_records_catalog." >&2
|
||||||
|
echo "Run 'cd infrastructure/terraform/dynu && terraform output' to inspect available outputs." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ ! -s "${out_json}" ]]; then
|
||||||
|
echo "ERROR: Dynu DNS inventory output file is empty: ${out_json}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Generated: ${out_json}"
|
||||||
Executable
+189
@@ -0,0 +1,189 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate host topology Markdown/Mermaid from Terraform inventory JSON."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
PARENT_KEYS = [
|
||||||
|
"node",
|
||||||
|
"node_name",
|
||||||
|
"host",
|
||||||
|
"physical_host",
|
||||||
|
"hypervisor_host",
|
||||||
|
"proxmox_node",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Generate Markdown topology from terraform output JSON"
|
||||||
|
)
|
||||||
|
parser.add_argument("--input", required=True, help="Input JSON path")
|
||||||
|
parser.add_argument("--output", required=True, help="Output Markdown path")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def load_inventory(raw: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
payload = raw.get("value", raw)
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise ValueError("Inventory payload must be an object")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def infer_name(key: str, item: dict[str, Any]) -> str:
|
||||||
|
for candidate in ("name", "hostname", "vm_name", "id"):
|
||||||
|
value = item.get(candidate)
|
||||||
|
if value:
|
||||||
|
return str(value)
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
def to_records(host_map: Any) -> list[dict[str, Any]]:
|
||||||
|
if isinstance(host_map, dict):
|
||||||
|
records: list[dict[str, Any]] = []
|
||||||
|
for key, val in host_map.items():
|
||||||
|
if isinstance(val, dict):
|
||||||
|
rec = dict(val)
|
||||||
|
rec.setdefault("_key", str(key))
|
||||||
|
rec.setdefault("name", infer_name(str(key), rec))
|
||||||
|
records.append(rec)
|
||||||
|
return sorted(records, key=lambda x: str(x.get("name", "")).lower())
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def escape_cell(value: Any) -> str:
|
||||||
|
if value is None:
|
||||||
|
return ""
|
||||||
|
text = str(value).replace("|", "\\|").replace("\n", "<br>")
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def get_first(item: dict[str, Any], *keys: str) -> str:
|
||||||
|
for key in keys:
|
||||||
|
value = item.get(key)
|
||||||
|
if value is not None and value != "":
|
||||||
|
return str(value)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def detect_virtual_hosts(inv: dict[str, Any]) -> list[dict[str, Any]]:
|
||||||
|
virtual: list[dict[str, Any]] = []
|
||||||
|
for key in ("virtual_hosts", "vms"):
|
||||||
|
virtual.extend(to_records(inv.get(key, {})))
|
||||||
|
return sorted(virtual, key=lambda x: str(x.get("name", "")).lower())
|
||||||
|
|
||||||
|
|
||||||
|
def build_mermaid(physical: list[dict[str, Any]], virtual: list[dict[str, Any]]) -> list[str]:
|
||||||
|
lines = ["```mermaid", "flowchart TD"]
|
||||||
|
for p in physical:
|
||||||
|
pname = get_first(p, "name", "hostname", "_key")
|
||||||
|
pid = f"phys_{pname.lower().replace('-', '_').replace(' ', '_')}"
|
||||||
|
lines.append(f' {pid}["{pname}\\nphysical"]')
|
||||||
|
|
||||||
|
for v in virtual:
|
||||||
|
vname = get_first(v, "name", "hostname", "_key")
|
||||||
|
vid = f"virt_{vname.lower().replace('-', '_').replace(' ', '_')}"
|
||||||
|
parent = ""
|
||||||
|
for k in PARENT_KEYS:
|
||||||
|
parent = get_first(v, k)
|
||||||
|
if parent:
|
||||||
|
break
|
||||||
|
|
||||||
|
lines.append(f' {vid}["{vname}\\nvirtual"]')
|
||||||
|
if parent:
|
||||||
|
pid = f"phys_{parent.lower().replace('-', '_').replace(' ', '_')}"
|
||||||
|
lines.append(f" {pid} --> {vid}")
|
||||||
|
|
||||||
|
lines.append("```")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def build_table(headers: list[str], rows: list[list[str]]) -> list[str]:
|
||||||
|
out = ["| " + " | ".join(headers) + " |", "| " + " | ".join(["---"] * len(headers)) + " |"]
|
||||||
|
for row in rows:
|
||||||
|
out.append("| " + " | ".join(escape_cell(cell) for cell in row) + " |")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
args = parse_args()
|
||||||
|
raw = json.loads(Path(args.input).read_text(encoding="utf-8"))
|
||||||
|
inv = load_inventory(raw)
|
||||||
|
|
||||||
|
physical = to_records(inv.get("physical_hosts", {}))
|
||||||
|
virtual = detect_virtual_hosts(inv)
|
||||||
|
|
||||||
|
now = datetime.now(timezone.utc).replace(microsecond=0).isoformat()
|
||||||
|
lines: list[str] = [
|
||||||
|
"# Host Topology",
|
||||||
|
"",
|
||||||
|
f"> Generated by `scripts/docs/generate_host_topology.py` on {now}.",
|
||||||
|
"",
|
||||||
|
"## Topology Diagram",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
lines.extend(build_mermaid(physical, virtual))
|
||||||
|
lines.extend(["", "## Physical Hosts", ""])
|
||||||
|
|
||||||
|
physical_rows = [
|
||||||
|
[
|
||||||
|
get_first(p, "name", "hostname", "_key"),
|
||||||
|
get_first(p, "type"),
|
||||||
|
get_first(p, "role"),
|
||||||
|
get_first(p, "management", "management_ip"),
|
||||||
|
get_first(p, "os", "os_family"),
|
||||||
|
get_first(p, "hypervisor"),
|
||||||
|
get_first(p, "location"),
|
||||||
|
get_first(p, "notes"),
|
||||||
|
]
|
||||||
|
for p in physical
|
||||||
|
]
|
||||||
|
lines.extend(
|
||||||
|
build_table(
|
||||||
|
["Name", "Type", "Role", "Management", "OS", "Hypervisor", "Location", "Notes"],
|
||||||
|
physical_rows,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.extend(["", "## Virtual Hosts", ""])
|
||||||
|
if virtual:
|
||||||
|
virtual_rows = []
|
||||||
|
for v in virtual:
|
||||||
|
parent = ""
|
||||||
|
for k in PARENT_KEYS:
|
||||||
|
parent = get_first(v, k)
|
||||||
|
if parent:
|
||||||
|
break
|
||||||
|
virtual_rows.append(
|
||||||
|
[
|
||||||
|
get_first(v, "name", "hostname", "_key"),
|
||||||
|
get_first(v, "type"),
|
||||||
|
get_first(v, "role"),
|
||||||
|
parent,
|
||||||
|
get_first(v, "management", "management_ip", "ip"),
|
||||||
|
get_first(v, "os", "os_family"),
|
||||||
|
get_first(v, "notes"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
lines.extend(
|
||||||
|
build_table(
|
||||||
|
["Name", "Type", "Role", "Parent/Node", "Management", "OS", "Notes"],
|
||||||
|
virtual_rows,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
lines.append("No VM/virtual host data found in the current Terraform inventory output.")
|
||||||
|
|
||||||
|
out_path = Path(args.output)
|
||||||
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
out_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Discover compose files for docs tooling and CI without running containers.
|
||||||
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
declare -a files=()
|
||||||
|
|
||||||
|
if [ -f services-up.sh ]; then
|
||||||
|
# Parse literal FILES array entries in services-up.sh (e.g. default-network.yml).
|
||||||
|
while IFS= read -r line; do
|
||||||
|
path=$(sed -E 's#.*\$PROJECT_ROOT/([^" ]+).*#\1#' <<<"$line")
|
||||||
|
[ -f "$path" ] && files+=("$path")
|
||||||
|
done < <(awk '/^FILES=\(/,/^\)/ {print}' services-up.sh | grep -E '\-f[[:space:]]+"\$PROJECT_ROOT/')
|
||||||
|
|
||||||
|
# Reuse the same compose roots used by services-up.sh to avoid archived compose files.
|
||||||
|
if grep -q 'find "\$PROJECT_ROOT/apps" "\$PROJECT_ROOT/monitoring" "\$PROJECT_ROOT/core"' services-up.sh; then
|
||||||
|
while IFS= read -r f; do files+=("$f"); done < <(
|
||||||
|
find apps monitoring core -maxdepth 2 -type f \
|
||||||
|
\( -name 'docker-compose.yml' -o -name 'docker-compose.yaml' -o -name 'compose.yml' -o -name 'compose.yaml' \) \
|
||||||
|
| sed 's#^\./##' | sort
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${#files[@]}" -eq 0 ]; then
|
||||||
|
while IFS= read -r f; do files+=("$f"); done < <(
|
||||||
|
find . -type f \
|
||||||
|
\( -name 'docker-compose.yml' -o -name 'docker-compose.yaml' -o -name 'compose.yml' -o -name 'compose.yaml' \) \
|
||||||
|
| sed 's#^\./##' | grep -v '^archive/' | sort
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\n' "${files[@]}" | awk 'NF' | awk '!seen[$0]++'
|
||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
mkdir -p docs/generated
|
||||||
|
mapfile -t COMPOSE_FILES < <(scripts/docs/list-compose-files.sh)
|
||||||
|
if [ "${#COMPOSE_FILES[@]}" -eq 0 ]; then
|
||||||
|
echo "No compose files found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${COMPOSE_FILES[@]}" > docs/generated/compose-files.txt
|
||||||
|
|
||||||
|
if [ ! -x ./services-up.sh ]; then
|
||||||
|
echo "services-up.sh is missing or not executable" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
./services-up.sh --profile all config > docs/generated/docker-compose.resolved.yml
|
||||||
|
|
||||||
|
service_count="$(
|
||||||
|
python3 - <<'PY'
|
||||||
|
import yaml
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
data = yaml.safe_load(Path("docs/generated/docker-compose.resolved.yml").read_text()) or {}
|
||||||
|
print(len(data.get("services") or {}))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ "$service_count" -eq 0 ]; then
|
||||||
|
echo "ERROR: rendered compose config contains zero services; check --profile all / COMPOSE_PROFILES." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
src_generated = Path(sys.argv[1])
|
||||||
|
src_diagrams = Path(sys.argv[2])
|
||||||
|
out_dir = Path(sys.argv[3])
|
||||||
|
out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitize_text(content: str) -> str:
|
||||||
|
content = re.sub(r'\b([a-zA-Z0-9-]+)\.lan\.ddnsgeek\.com\b', r'\1.<domain>', content)
|
||||||
|
content = re.sub(
|
||||||
|
r'\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b',
|
||||||
|
'<private-ip>',
|
||||||
|
content,
|
||||||
|
)
|
||||||
|
content = re.sub(r'(?i)\b(password|token|api[_-]?key|secret)\s*[:=]\s*[^\s\n]+', r'\1=<redacted>', content)
|
||||||
|
content = re.sub(r'(?m)^([A-Z0-9_]*(?:PASSWORD|TOKEN|API_KEY|SECRET)[A-Z0-9_]*)\s*[:=]\s*.*$', r'\1=<redacted>', content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
for name in ['compose-inventory.md', 'traefik-routes.md']:
|
||||||
|
src = src_generated / name
|
||||||
|
if src.exists():
|
||||||
|
(out_dir / name).write_text(sanitize_text(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 documentation is generated from the infrastructure repository. Sensitive values are redacted.
|
||||||
|
|
||||||
|
> Generated docs are sanitised/redacted before publishing to GitHub Pages.
|
||||||
|
|
||||||
|
## Infrastructure diagrams
|
||||||
|
|
||||||
|
### Physical / virtual topology
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Docker, Traefik and Dynu routing
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Documents
|
||||||
|
|
||||||
|
- [Diagrams](diagrams.md)
|
||||||
|
- [Compose Inventory](compose-inventory.md)
|
||||||
|
- [Traefik Routes](traefik-routes.md)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
(out_dir / 'diagrams.md').write_text(
|
||||||
|
"""# Infrastructure diagrams
|
||||||
|
|
||||||
|
## Physical / virtual topology
|
||||||
|
|
||||||
|
This view groups containers by inferred host and service role (edge/proxy/auth, monitoring, automation, apps, and supporting storage/services).
|
||||||
|
|
||||||
|
<div class="diagram-wrap">
|
||||||
|
<img src="physical-topology.svg" alt="Physical topology">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Docker, Traefik and Dynu routing
|
||||||
|
|
||||||
|
This view shows sanitised public DNS names flowing to Traefik, then to exposed Docker services, with backend Docker network membership shown as secondary context.
|
||||||
|
|
||||||
|
_Diagrams are generated from Compose data and Traefik labels._
|
||||||
|
|
||||||
|
<div class="diagram-wrap">
|
||||||
|
<img src="docker-traefik-dynu.svg" alt="Docker Traefik Dynu">
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
)
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
mkdir -p docs/generated docs/diagrams docs/public
|
||||||
|
|
||||||
|
scripts/docs/generate-all.sh
|
||||||
|
|
||||||
|
if [ ! -d docs/public ] || [ -z "$(find docs/public -mindepth 1 -print -quit)" ]; then
|
||||||
|
echo "ERROR: docs/public is missing or empty after generation." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Public docs generated in docs/public. Review changes before commit."
|
||||||
@@ -26,6 +26,12 @@ def parse_args() -> argparse.Namespace:
|
|||||||
parser.add_argument("--diagrams-dir", default="docs/diagrams", help="Diagram output directory.")
|
parser.add_argument("--diagrams-dir", default="docs/diagrams", help="Diagram output directory.")
|
||||||
parser.add_argument("--readme-file", default="README.md", help="README path for regeneration notes.")
|
parser.add_argument("--readme-file", default="README.md", help="README path for regeneration notes.")
|
||||||
parser.add_argument("--architecture-file", default="docs/architecture.md", help="Architecture markdown path.")
|
parser.add_argument("--architecture-file", default="docs/architecture.md", help="Architecture markdown path.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--dynu-dns-inventory-file",
|
||||||
|
default="infrastructure/terraform/dynu/generated/dynu_dns_records_inventory.json",
|
||||||
|
help="Path to Dynu DNS brownfield inventory JSON.",
|
||||||
|
)
|
||||||
|
parser.add_argument("--skip-dynu-dns", action="store_true", help="Skip Dynu DNS inventory loading/rendering.")
|
||||||
parser.add_argument("--network-file", default="docs/network.md", help="Network markdown path.")
|
parser.add_argument("--network-file", default="docs/network.md", help="Network markdown path.")
|
||||||
parser.add_argument("--coverage-file", default="docs/monitoring-coverage.md", help="Coverage markdown path.")
|
parser.add_argument("--coverage-file", default="docs/monitoring-coverage.md", help="Coverage markdown path.")
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Print changes instead of writing files.")
|
parser.add_argument("--dry-run", action="store_true", help="Print changes instead of writing files.")
|
||||||
@@ -41,6 +47,109 @@ def load_json(path: Path) -> dict[str, Any]:
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def load_optional_json(path: Path) -> Any | None:
|
||||||
|
if not path.exists():
|
||||||
|
return None
|
||||||
|
with path.open("r", encoding="utf-8") as handle:
|
||||||
|
return json.load(handle)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_dynu_dns_records(payload: Any) -> list[dict[str, Any]]:
|
||||||
|
records_payload = payload
|
||||||
|
if isinstance(payload, dict):
|
||||||
|
if isinstance(payload.get("records"), list):
|
||||||
|
records_payload = payload["records"]
|
||||||
|
elif isinstance(payload.get("value"), list):
|
||||||
|
records_payload = payload["value"]
|
||||||
|
if not isinstance(records_payload, list):
|
||||||
|
raise ValueError("Dynu DNS inventory must be a list or object with list field `records`/`value`.")
|
||||||
|
|
||||||
|
normalized: list[dict[str, Any]] = []
|
||||||
|
for record in records_payload:
|
||||||
|
if not isinstance(record, dict):
|
||||||
|
continue
|
||||||
|
normalized.append(
|
||||||
|
{
|
||||||
|
"id": record.get("id"),
|
||||||
|
"domain_id": record.get("domain_id"),
|
||||||
|
"domain_name": str(record.get("domain_name") or "unknown"),
|
||||||
|
"hostname": str(record.get("hostname") or "unknown"),
|
||||||
|
"node_name": str(record.get("node_name") or "unknown"),
|
||||||
|
"record_type": str(record.get("record_type") or "unknown"),
|
||||||
|
"content": record.get("content"),
|
||||||
|
"state": record.get("state") if "state" in record else record.get("enabled"),
|
||||||
|
"ttl": record.get("ttl"),
|
||||||
|
"updated_on": record.get("updated_on"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
normalized.sort(
|
||||||
|
key=lambda r: (
|
||||||
|
str(r.get("domain_name") or ""),
|
||||||
|
str(r.get("hostname") or ""),
|
||||||
|
str(r.get("record_type") or ""),
|
||||||
|
str(r.get("id") or ""),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return normalized
|
||||||
|
|
||||||
|
|
||||||
|
def render_dynu_dns_architecture_section(records: list[dict[str, Any]], inventory_path: Path | None) -> str:
|
||||||
|
domains = sorted({r["domain_name"] for r in records if r["domain_name"] != "unknown"})
|
||||||
|
dynamic_count = 0
|
||||||
|
static_count = 0
|
||||||
|
disabled_count = 0
|
||||||
|
rows: list[list[str]] = []
|
||||||
|
for record in records:
|
||||||
|
rtype = str(record.get("record_type") or "").upper()
|
||||||
|
raw_content = record.get("content")
|
||||||
|
content = "" if raw_content is None else str(raw_content).strip()
|
||||||
|
is_dynamic = rtype in {"A", "AAAA"} and not content
|
||||||
|
mode = "dynamic" if is_dynamic else ("static" if content else ("record" if rtype not in {"A", "AAAA"} else "static"))
|
||||||
|
target = "dynamic" if is_dynamic else (content or ("unknown" if not content else content))
|
||||||
|
if is_dynamic:
|
||||||
|
dynamic_count += 1
|
||||||
|
else:
|
||||||
|
static_count += 1
|
||||||
|
|
||||||
|
enabled_value = record.get("state")
|
||||||
|
enabled_text = "unknown" if enabled_value is None else str(bool(enabled_value)).lower()
|
||||||
|
if enabled_value is False:
|
||||||
|
disabled_count += 1
|
||||||
|
|
||||||
|
rows.append(
|
||||||
|
[
|
||||||
|
str(record.get("hostname") or "unknown"),
|
||||||
|
rtype or "unknown",
|
||||||
|
target,
|
||||||
|
mode,
|
||||||
|
str(record.get("ttl") if record.get("ttl") is not None else "unknown"),
|
||||||
|
enabled_text,
|
||||||
|
str(record.get("id") if record.get("id") is not None else "unknown"),
|
||||||
|
str(record.get("updated_on") or "unknown"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_text = ", ".join(domains) if domains else "unknown"
|
||||||
|
lines = [
|
||||||
|
"### Dynu DNS brownfield inventory",
|
||||||
|
"",
|
||||||
|
"Dynu DNS is managed as a brownfield reconciliation source. Terraform imports the root domain and individual DNS records into state, while generated configuration provides reviewable management intent.",
|
||||||
|
"",
|
||||||
|
f"- Inventory source: `{inventory_path}`" if inventory_path else "- Inventory source: `unknown`",
|
||||||
|
f"- Records observed: `{len(records)}`",
|
||||||
|
f"- Domains observed: `{domain_text}`",
|
||||||
|
f"- Dynamic A/AAAA records: `{dynamic_count}`",
|
||||||
|
f"- Static records: `{static_count}`",
|
||||||
|
f"- Disabled records: `{disabled_count}`",
|
||||||
|
"",
|
||||||
|
"#### DNS records",
|
||||||
|
"",
|
||||||
|
markdown_table(["hostname", "type", "target/content", "mode", "ttl", "enabled", "record id", "updated"], rows or [["none", "", "", "", "", "", "", ""]]),
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def merged_labels(target: dict[str, Any]) -> dict[str, str]:
|
def merged_labels(target: dict[str, Any]) -> dict[str, str]:
|
||||||
discovered = target.get("discovered_labels") or {}
|
discovered = target.get("discovered_labels") or {}
|
||||||
labels = target.get("labels") or {}
|
labels = target.get("labels") or {}
|
||||||
@@ -244,12 +353,18 @@ def render_network_doc(inventory: dict[str, Any], targets: list[dict[str, Any]])
|
|||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def render_architecture_section(inventory: dict[str, Any], targets: list[dict[str, Any]]) -> str:
|
def render_architecture_section(
|
||||||
|
inventory: dict[str, Any],
|
||||||
|
targets: list[dict[str, Any]],
|
||||||
|
dynu_records: list[dict[str, Any]] | None = None,
|
||||||
|
dynu_inventory_path: Path | None = None,
|
||||||
|
dynu_inventory_missing: bool = False,
|
||||||
|
) -> str:
|
||||||
summaries = summarize_targets(targets, normalize_targets({"targets": inventory.get("unhealthy_targets") or []}))
|
summaries = summarize_targets(targets, normalize_targets({"targets": inventory.get("unhealthy_targets") or []}))
|
||||||
notes = inventory.get("notes") or []
|
notes = inventory.get("notes") or []
|
||||||
|
|
||||||
lines = [
|
lines = [
|
||||||
"## Runtime visibility from Prometheus",
|
"## Runtime and infrastructure inventory",
|
||||||
"",
|
"",
|
||||||
GENERATED_BEGIN,
|
GENERATED_BEGIN,
|
||||||
"",
|
"",
|
||||||
@@ -267,12 +382,42 @@ def render_architecture_section(inventory: dict[str, Any], targets: list[dict[st
|
|||||||
[[job, str(data["active"]), str(data["unhealthy"])] for job, data in summaries["by_job"].items()] or [["none", "0", "0"]],
|
[[job, str(data["active"]), str(data["unhealthy"])] for job, data in summaries["by_job"].items()] or [["none", "0", "0"]],
|
||||||
),
|
),
|
||||||
"",
|
"",
|
||||||
"### Data sources",
|
|
||||||
"",
|
|
||||||
"- `docs/runtime/prometheus-inventory.json` (normalized runtime export)",
|
|
||||||
"- Prometheus scrape metadata (`targets` + label sets)",
|
|
||||||
"- Existing repository architecture docs for declared topology",
|
|
||||||
]
|
]
|
||||||
|
if dynu_records is not None:
|
||||||
|
lines.extend(["", render_dynu_dns_architecture_section(dynu_records, dynu_inventory_path).rstrip(), ""])
|
||||||
|
elif dynu_inventory_missing:
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
"### Dynu DNS brownfield inventory",
|
||||||
|
"",
|
||||||
|
f"Dynu DNS inventory was not found at `{dynu_inventory_path}`.",
|
||||||
|
"",
|
||||||
|
"Generate it with:",
|
||||||
|
"",
|
||||||
|
"```bash",
|
||||||
|
"cd infrastructure/terraform/dynu",
|
||||||
|
"python3 scripts/generate-brownfield-records.py --overwrite",
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
"### Data sources",
|
||||||
|
"",
|
||||||
|
"- `docs/runtime/prometheus-inventory.json` (normalized runtime export)",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if dynu_records is not None:
|
||||||
|
lines.append(f"- `{dynu_inventory_path}` (Dynu DNS brownfield inventory)")
|
||||||
|
elif dynu_inventory_missing:
|
||||||
|
lines.append("- Dynu DNS inventory not available; run the Dynu brownfield generator.")
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
"- Prometheus scrape metadata (`targets` + label sets)",
|
||||||
|
"- Existing repository architecture docs for declared topology",
|
||||||
|
]
|
||||||
|
)
|
||||||
if notes:
|
if notes:
|
||||||
lines.extend(["", "### Notes from inventory", ""])
|
lines.extend(["", "### Notes from inventory", ""])
|
||||||
for note in notes:
|
for note in notes:
|
||||||
@@ -284,14 +429,26 @@ def render_architecture_section(inventory: dict[str, Any], targets: list[dict[st
|
|||||||
def upsert_generated_section(path: Path, section_markdown: str, dry_run: bool, verbose: bool) -> None:
|
def upsert_generated_section(path: Path, section_markdown: str, dry_run: bool, verbose: bool) -> None:
|
||||||
existing = path.read_text(encoding="utf-8") if path.exists() else ""
|
existing = path.read_text(encoding="utf-8") if path.exists() else ""
|
||||||
section_body = section_markdown
|
section_body = section_markdown
|
||||||
|
legacy_heading = "## Runtime visibility from Prometheus"
|
||||||
|
new_heading = "## Runtime and infrastructure inventory"
|
||||||
|
|
||||||
if GENERATED_BEGIN in existing and GENERATED_END in existing:
|
if GENERATED_BEGIN in existing and GENERATED_END in existing:
|
||||||
|
# Migration: replace legacy heading that exists outside the generated markers.
|
||||||
|
existing = re.sub(
|
||||||
|
rf"^{re.escape(legacy_heading)}(?=\n)",
|
||||||
|
new_heading,
|
||||||
|
existing,
|
||||||
|
count=1,
|
||||||
|
flags=re.MULTILINE,
|
||||||
|
)
|
||||||
pattern = re.compile(
|
pattern = re.compile(
|
||||||
rf"{re.escape(GENERATED_BEGIN)}.*?{re.escape(GENERATED_END)}",
|
rf"{re.escape(GENERATED_BEGIN)}.*?{re.escape(GENERATED_END)}",
|
||||||
re.DOTALL,
|
re.DOTALL,
|
||||||
)
|
)
|
||||||
replacement = "\n".join(
|
replacement = "\n".join(
|
||||||
line for line in section_body.splitlines() if line.strip() not in {"## Runtime visibility from Prometheus"}
|
line
|
||||||
|
for line in section_body.splitlines()
|
||||||
|
if line.strip() not in {legacy_heading, new_heading}
|
||||||
)
|
)
|
||||||
updated = pattern.sub(replacement.strip(), existing)
|
updated = pattern.sub(replacement.strip(), existing)
|
||||||
else:
|
else:
|
||||||
@@ -384,6 +541,7 @@ def main() -> int:
|
|||||||
inventory_path = Path(args.inventory_file)
|
inventory_path = Path(args.inventory_file)
|
||||||
docs_dir = Path(args.docs_dir)
|
docs_dir = Path(args.docs_dir)
|
||||||
diagrams_dir = Path(args.diagrams_dir)
|
diagrams_dir = Path(args.diagrams_dir)
|
||||||
|
dynu_inventory_path = Path(args.dynu_dns_inventory_file)
|
||||||
|
|
||||||
inventory = load_json(inventory_path)
|
inventory = load_json(inventory_path)
|
||||||
targets = normalize_targets(inventory)
|
targets = normalize_targets(inventory)
|
||||||
@@ -394,7 +552,25 @@ def main() -> int:
|
|||||||
|
|
||||||
coverage_md = render_monitoring_coverage(inventory, targets)
|
coverage_md = render_monitoring_coverage(inventory, targets)
|
||||||
network_md = render_network_doc(inventory, targets)
|
network_md = render_network_doc(inventory, targets)
|
||||||
architecture_section = render_architecture_section(inventory, targets)
|
dynu_records: list[dict[str, Any]] | None = None
|
||||||
|
dynu_inventory_missing = False
|
||||||
|
if not args.skip_dynu_dns:
|
||||||
|
try:
|
||||||
|
dynu_payload = load_optional_json(dynu_inventory_path)
|
||||||
|
except json.JSONDecodeError as exc:
|
||||||
|
raise ValueError(f"Invalid JSON in Dynu DNS inventory file {dynu_inventory_path}: {exc}") from exc
|
||||||
|
if dynu_payload is None:
|
||||||
|
dynu_inventory_missing = True
|
||||||
|
else:
|
||||||
|
dynu_records = normalize_dynu_dns_records(dynu_payload)
|
||||||
|
|
||||||
|
architecture_section = render_architecture_section(
|
||||||
|
inventory,
|
||||||
|
targets,
|
||||||
|
dynu_records=dynu_records,
|
||||||
|
dynu_inventory_path=dynu_inventory_path,
|
||||||
|
dynu_inventory_missing=dynu_inventory_missing,
|
||||||
|
)
|
||||||
monitoring_mmd = render_monitoring_mermaid(targets)
|
monitoring_mmd = render_monitoring_mermaid(targets)
|
||||||
architecture_mmd = render_architecture_mermaid(targets)
|
architecture_mmd = render_architecture_mermaid(targets)
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -1,13 +1,13 @@
|
|||||||
10:17:35 INFO: === Update started: 2026-04-21 10:17:35 ===
|
12:50:25 INFO: === Update started: 2026-05-12 12:50:25 ===
|
||||||
10:17:35 WARNING: Skipping traefik (directory does not exist)
|
12:50:25 WARNING: Skipping traefik (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping nextcloud (directory does not exist)
|
12:50:25 WARNING: Skipping nextcloud (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping passbolt (directory does not exist)
|
12:50:25 WARNING: Skipping passbolt (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping searxng (directory does not exist)
|
12:50:25 WARNING: Skipping searxng (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping gitea (directory does not exist)
|
12:50:25 WARNING: Skipping gitea (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping gotify (directory does not exist)
|
12:50:25 WARNING: Skipping gotify (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping grafana (directory does not exist)
|
12:50:25 WARNING: Skipping grafana (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping gramps (directory does not exist)
|
12:50:25 WARNING: Skipping gramps (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping portainer (directory does not exist)
|
12:50:25 WARNING: Skipping portainer (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping prometheus (directory does not exist)
|
12:50:25 WARNING: Skipping prometheus (directory does not exist)
|
||||||
10:17:35 WARNING: Skipping uptime-kuma (directory does not exist)
|
12:50:25 WARNING: Skipping uptime-kuma (directory does not exist)
|
||||||
10:17:35 INFO: Pruning unused containers, images, networks, and volumes...
|
12:50:25 INFO: Pruning unused containers, images, networks, and volumes...
|
||||||
|
|||||||
Reference in New Issue
Block a user