From 51a783f93ad2783c47d5f015f6abc19524842bb0 Mon Sep 17 00:00:00 2001 From: Vladimir Eremin Date: Wed, 15 Apr 2026 00:48:06 +0300 Subject: [PATCH] docs: Update docs for the correctness (#13) --- .gemini/skills/write-docs/SKILL.md | 4 +- services/docs/content/en/_index.md | 2 +- .../{recipes => guides}/conversational-ai.md | 5 +- .../content/en/quetza/guides/deployment.md | 3 +- .../{recipes => guides}/voice-features.md | 5 +- .../docs/content/en/quetza/recipes/_index.md | 13 -- .../en/quetza/troubleshooting/diagnostics.md | 18 +- services/docs/content/en/root/_index.md | 8 +- .../docs/content/en/root/concepts/_index.md | 2 +- .../content/en/root/concepts/architecture.md | 25 ++- .../en/root/concepts/security-model.md | 45 +++- .../en/root/concepts/tiered-storage.md | 60 ++++-- .../docs/content/en/root/guides/_index.md | 5 +- .../docs/content/en/root/guides/first-node.md | 190 ++++++++++++++++ .../content/en/root/guides/installation.md | 203 +++++++++++++++--- .../docs/content/en/root/recipes/_index.md | 19 -- .../content/en/root/recipes/initial-setup.md | 202 ----------------- .../docs/content/en/root/reference/_index.md | 9 +- .../docs/content/en/root/reference/compose.md | 50 +++++ .../content/en/root/reference/configure.md | 66 ++++++ .../en/root/reference/initialization.md | 40 ++++ .../content/en/root/reference/root-api.md | 35 +-- .../docs/content/en/root/reference/source.md | 42 ++++ .../docs/content/en/root/reference/sync.md | 36 ++++ .../docs/content/en/root/reference/tiers.md | 44 ++++ .../docs/content/en/root/reference/utils.md | 37 ++++ services/docs/content/ru/_index.md | 3 +- services/docs/content/ru/quetza/_index.md | 35 +++ .../docs/content/ru/quetza/concepts/_index.md | 6 + .../ru/quetza/concepts/architecture.md | 45 ++++ .../ru/quetza/concepts/module-system.md | 67 ++++++ .../docs/content/ru/quetza/getting-started.md | 66 ++++++ .../docs/content/ru/quetza/guides/_index.md | 6 + .../ru/quetza/guides/conversational-ai.md | 56 +++++ .../content/ru/quetza/guides/deployment.md | 77 +++++++ .../ru/quetza/guides/module-development.md | 105 +++++++++ .../ru/quetza/guides/voice-features.md | 63 ++++++ .../ru/quetza/troubleshooting/_index.md | 12 ++ .../ru/quetza/troubleshooting/diagnostics.md | 73 +++++++ services/docs/content/ru/root/_index.md | 31 ++- .../docs/content/ru/root/concepts/_index.md | 14 ++ .../content/ru/root/concepts/architecture.md | 71 ++++++ .../content/ru/root/concepts/principles.md | 33 +++ .../ru/root/concepts/security-model.md | 64 ++++++ .../ru/root/concepts/tiered-storage.md | 71 ++++++ services/docs/content/ru/root/glossary.md | 41 ++++ .../docs/content/ru/root/guides/_index.md | 13 ++ .../ru/root/guides/action-development.md | 67 ++++++ .../docs/content/ru/root/guides/first-node.md | 190 ++++++++++++++++ .../installation.md} | 53 +++-- .../docs/content/ru/root/recipes/_index.md | 11 - .../docs/content/ru/root/reference/_index.md | 18 ++ .../docs/content/ru/root/reference/compose.md | 50 +++++ .../content/ru/root/reference/configure.md | 66 ++++++ .../ru/root/reference/initialization.md | 40 ++++ .../content/ru/root/reference/root-api.md | 62 ++++++ .../docs/content/ru/root/reference/source.md | 42 ++++ .../docs/content/ru/root/reference/sync.md | 36 ++++ .../docs/content/ru/root/reference/tiers.md | 44 ++++ .../docs/content/ru/root/reference/utils.md | 37 ++++ 60 files changed, 2456 insertions(+), 380 deletions(-) rename services/docs/content/en/quetza/{recipes => guides}/conversational-ai.md (97%) rename services/docs/content/en/quetza/{recipes => guides}/voice-features.md (91%) delete mode 100644 services/docs/content/en/quetza/recipes/_index.md create mode 100644 services/docs/content/en/root/guides/first-node.md delete mode 100644 services/docs/content/en/root/recipes/_index.md delete mode 100644 services/docs/content/en/root/recipes/initial-setup.md create mode 100644 services/docs/content/en/root/reference/compose.md create mode 100644 services/docs/content/en/root/reference/configure.md create mode 100644 services/docs/content/en/root/reference/initialization.md create mode 100644 services/docs/content/en/root/reference/source.md create mode 100644 services/docs/content/en/root/reference/sync.md create mode 100644 services/docs/content/en/root/reference/tiers.md create mode 100644 services/docs/content/en/root/reference/utils.md create mode 100644 services/docs/content/ru/quetza/_index.md create mode 100644 services/docs/content/ru/quetza/concepts/_index.md create mode 100644 services/docs/content/ru/quetza/concepts/architecture.md create mode 100644 services/docs/content/ru/quetza/concepts/module-system.md create mode 100644 services/docs/content/ru/quetza/getting-started.md create mode 100644 services/docs/content/ru/quetza/guides/_index.md create mode 100644 services/docs/content/ru/quetza/guides/conversational-ai.md create mode 100644 services/docs/content/ru/quetza/guides/deployment.md create mode 100644 services/docs/content/ru/quetza/guides/module-development.md create mode 100644 services/docs/content/ru/quetza/guides/voice-features.md create mode 100644 services/docs/content/ru/quetza/troubleshooting/_index.md create mode 100644 services/docs/content/ru/quetza/troubleshooting/diagnostics.md create mode 100644 services/docs/content/ru/root/concepts/_index.md create mode 100644 services/docs/content/ru/root/concepts/architecture.md create mode 100644 services/docs/content/ru/root/concepts/principles.md create mode 100644 services/docs/content/ru/root/concepts/security-model.md create mode 100644 services/docs/content/ru/root/concepts/tiered-storage.md create mode 100644 services/docs/content/ru/root/glossary.md create mode 100644 services/docs/content/ru/root/guides/_index.md create mode 100644 services/docs/content/ru/root/guides/action-development.md create mode 100644 services/docs/content/ru/root/guides/first-node.md rename services/docs/content/ru/root/{recipes/initial-setup.md => guides/installation.md} (78%) delete mode 100644 services/docs/content/ru/root/recipes/_index.md create mode 100644 services/docs/content/ru/root/reference/_index.md create mode 100644 services/docs/content/ru/root/reference/compose.md create mode 100644 services/docs/content/ru/root/reference/configure.md create mode 100644 services/docs/content/ru/root/reference/initialization.md create mode 100644 services/docs/content/ru/root/reference/root-api.md create mode 100644 services/docs/content/ru/root/reference/source.md create mode 100644 services/docs/content/ru/root/reference/sync.md create mode 100644 services/docs/content/ru/root/reference/tiers.md create mode 100644 services/docs/content/ru/root/reference/utils.md diff --git a/.gemini/skills/write-docs/SKILL.md b/.gemini/skills/write-docs/SKILL.md index ca154f3..4134faa 100644 --- a/.gemini/skills/write-docs/SKILL.md +++ b/.gemini/skills/write-docs/SKILL.md @@ -320,7 +320,7 @@ Use GitHub-flavored alerts for emphasis. ## 6. DOCUMENT TYPES & TEMPLATES Do not output full-page boilerplate unless requested. Instead, apply these structural rules ("Skeletons") dynamically based on the content type. -This is also serves as the fixed categories which should populate every project's docs: Getting Started, Guides, Recipes, Concepts, Troubleshooting. +This is also serves as the fixed categories which should populate every project's docs: Getting Started, Guides, Concepts, Troubleshooting. ### 6.1 General Skeleton (All Docs) @@ -349,7 +349,7 @@ This is also serves as the fixed categories which should populate every project' 3. **Procedure:** Strict numbered steps (or `{{% steps %}}`). 4. **Result Control:** How to verify success. -### 6.4 How-to / Recipe (Task-Oriented) +### 6.4 How-to / Guide (Task-Oriented) - **Goal:** Solve a specific problem. - **Structure:** diff --git a/services/docs/content/en/_index.md b/services/docs/content/en/_index.md index 8e4170c..c0cfbf3 100644 --- a/services/docs/content/en/_index.md +++ b/services/docs/content/en/_index.md @@ -7,6 +7,6 @@ title: "Ermnvldmr's Documentation" Welcome to the unified documentation for my own projects {{< cards >}} -{{< card link="root" title="root.ermnvldmr.com" icon="server" subtitle="Documentation for root.ermnvldmr.com infrastructure" >}} +{{< card link="root" title="ermnvldmr.com-root-commons" icon="server" subtitle="Documentation for the root deployment commons framework" >}} {{< card link="quetza" title="Quetza Bot" icon="terminal" subtitle="Modular Discord bot framework documentation" >}} {{< /cards >}} diff --git a/services/docs/content/en/quetza/recipes/conversational-ai.md b/services/docs/content/en/quetza/guides/conversational-ai.md similarity index 97% rename from services/docs/content/en/quetza/recipes/conversational-ai.md rename to services/docs/content/en/quetza/guides/conversational-ai.md index e459c2b..4e6869d 100644 --- a/services/docs/content/en/quetza/recipes/conversational-ai.md +++ b/services/docs/content/en/quetza/guides/conversational-ai.md @@ -1,6 +1,6 @@ --- title: Conversational AI Integration -weight: 2 +weight: 4 --- **Goal:** Integrate Large Language Models (LLMs) while managing context and Discord's timeout constraints. @@ -51,5 +51,6 @@ export async function execute(interaction, controller) { } ``` -> [!WARNING] > **API Costs:** +> [!WARNING] +> **API Costs:** > AI APIs are often billed by token. Implement strict user-based rate limits in your Controller to prevent abuse. diff --git a/services/docs/content/en/quetza/guides/deployment.md b/services/docs/content/en/quetza/guides/deployment.md index 90a9689..764aa30 100644 --- a/services/docs/content/en/quetza/guides/deployment.md +++ b/services/docs/content/en/quetza/guides/deployment.md @@ -65,7 +65,8 @@ Once running, use these mechanisms to check health: - **`/ping` Command:** Verifies network latency and API responsiveness. - **`/modules` Command:** Lists all loaded modules to confirm feature availability. -> [!WARNING] > **Scaling Constraint:** +> [!WARNING] +> **Scaling Constraint:** > Quetza follows a single-instance-per-token model. Do not run multiple instances with the same token, as this will cause WebSocket conflicts. --- diff --git a/services/docs/content/en/quetza/recipes/voice-features.md b/services/docs/content/en/quetza/guides/voice-features.md similarity index 91% rename from services/docs/content/en/quetza/recipes/voice-features.md rename to services/docs/content/en/quetza/guides/voice-features.md index 0285b5a..e4d88ea 100644 --- a/services/docs/content/en/quetza/recipes/voice-features.md +++ b/services/docs/content/en/quetza/guides/voice-features.md @@ -1,6 +1,6 @@ --- title: Interactive Voice Features -weight: 1 +weight: 3 --- **Goal:** Implement sophisticated voice interactions that respect guild boundaries and manage ephemeral resources. @@ -32,7 +32,8 @@ Audio sessions are ephemeral. - **Transient State:** Active audio stream (Lost on disconnect). - **Durable State:** Queue/Playlist (Persisted in Controller until restart). -> [!TIP] > **Resilience:** Separate the _Queue_ logic from the _Voice Connection_ logic. This allows the bot to reconnect without losing the user's playlist. +> [!TIP] +> **Resilience:** Separate the _Queue_ logic from the _Voice Connection_ logic. This allows the bot to reconnect without losing the user's playlist. ## 4. Implementation Sketch diff --git a/services/docs/content/en/quetza/recipes/_index.md b/services/docs/content/en/quetza/recipes/_index.md deleted file mode 100644 index 2121e86..0000000 --- a/services/docs/content/en/quetza/recipes/_index.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Recipes -weight: 3 ---- - -**Quetza** recipes are strategic architectural patterns for common functional requirements. They focus on _how_ to compose framework features to solve business problems. - -## Recipe Categories - -{{% cards %}} -{{< card link="voice-features" title="Interactive Voice Features" icon="users" subtitle="Managing audio players and guild-scoped state." >}} -{{< card link="conversational-ai" title="Conversational AI" icon="chip" subtitle="Handling LLM context and long-running responses." >}} -{{% /cards %}} diff --git a/services/docs/content/en/quetza/troubleshooting/diagnostics.md b/services/docs/content/en/quetza/troubleshooting/diagnostics.md index 40e39b4..e20ac70 100644 --- a/services/docs/content/en/quetza/troubleshooting/diagnostics.md +++ b/services/docs/content/en/quetza/troubleshooting/diagnostics.md @@ -22,18 +22,15 @@ weight: 1 **Symptom:** `/command` does not appear in Discord. -### Global vs. Guild Registration +### Global vs. Test Guild Registration -- **Global:** Takes up to 1 hour to propagate. -- **Guild:** Instant update. - - **Fix:** Set `DEV_GUILD_ID` in your `.env` for development. +- **Global:** Commands pushed to the application globally can take up to 1 hour to propagate and are subject to stricter rate limits. +- **Test Guild:** Quetza automatically pushes commands to a specific guild in development mode for instant updates. + - **Requirement:** Ensure `NODE_ENV=development` and `DEV_GUILD_ID` is correctly set in your `.env`. -### Data Malformation +### Rate Limits -Discord rejects invalid command structures silently or with generic errors. - -- **Name:** Must be lowercase, alphanumeric, `-` only. -- **Description:** Required, max 100 chars. +Frequent updates to global commands may trigger Discord's rate limits. Use a test guild for iterative development. ## 3. Interaction Failures @@ -71,5 +68,6 @@ Check your Controller. - **Multiple:** Events are additive. Did you register the same handler in two modules? - **None:** Did you export `name` and `execute` correctly? -> [!TIP] > **Debug Mode:** +> [!TIP] +> **Debug Mode:** > Enable verbose logging to see exactly which modules and commands are loaded at startup. diff --git a/services/docs/content/en/root/_index.md b/services/docs/content/en/root/_index.md index 8bede56..e45b3cb 100644 --- a/services/docs/content/en/root/_index.md +++ b/services/docs/content/en/root/_index.md @@ -1,13 +1,13 @@ --- -title: Root Infrastructure -description: Documentation for the root.ermnvldmr.com infrastructure. +title: Documentation of ermnvldmr.com root deployment commons +description: Documentation for the ermnvldmr.com root deployment commons framework. weight: 1 type: docs cascade: type: docs --- -The engine powering the shared infrastructure of `root.ermnvldmr.com`. This framework provides a minimal-dependency deployment environment for independent, self-hosted projects. +The `ermnvldmr.com-root-commons` framework provides a minimal-dependency deployment environment for independent, self-hosted projects. The generic logic, scripts, and deployment patterns used across multiple unrelated self-hosted applications are stored in the [GitHub: ermnvldmr.com-root-commons](https://github.com/deytenit/ermnvldmr.com-root-commons) repository. @@ -23,7 +23,6 @@ The generic logic, scripts, and deployment patterns used across multiple unrelat {{% cards %}} {{< card link="concepts" title="Concepts" icon="book-open" subtitle="Theoretical foundations, architecture, and security models." >}} {{< card link="guides" title="Guides" icon="map" subtitle="Step-by-step guides for installation and action development." >}} -{{< card link="recipes" title="Recipes" icon="beaker" subtitle="Collection of step-by-step procedures for infrastructure maintenance and deployment." >}} {{< card link="reference" title="Reference" icon="code" subtitle="API and technical references for developers." >}} {{% /cards %}} @@ -32,4 +31,3 @@ The generic logic, scripts, and deployment patterns used across multiple unrelat **See also:** - [GitHub: ermnvldmr.com-root-commons](https://github.com/deytenit/ermnvldmr.com-root-commons) -- [GitHub: root.ermnvldmr.com](https://github.com/deytenit/root.ermnvldmr.com) diff --git a/services/docs/content/en/root/concepts/_index.md b/services/docs/content/en/root/concepts/_index.md index 2a17d04..7ba7751 100644 --- a/services/docs/content/en/root/concepts/_index.md +++ b/services/docs/content/en/root/concepts/_index.md @@ -4,7 +4,7 @@ description: Theoretical foundations, architecture, and security models. weight: 10 --- -Theoretical foundations, architecture, and security models for the Root infrastructure framework. +Theoretical foundations, architecture, and security models for the ermnvldmr.com root deployment commons framework. {{% cards %}} {{< card link="principles" title="Infrastructure principles" icon="book-open" subtitle="Predictability, minimal dependencies, and decentralization." >}} diff --git a/services/docs/content/en/root/concepts/architecture.md b/services/docs/content/en/root/concepts/architecture.md index ae7bf3a..ca8fde7 100644 --- a/services/docs/content/en/root/concepts/architecture.md +++ b/services/docs/content/en/root/concepts/architecture.md @@ -33,16 +33,31 @@ The framework is typically deployed as a shared [Commons](/root/glossary#commons {{< filetree/container >}} {{< filetree/folder name="configs-repo" state="open" >}} {{< filetree/folder name=".operator" state="open" >}} - {{< filetree/folder name="shared" >}} - {{< filetree/file name="root (dispatcher)" >}} + {{< filetree/folder name="shared (submodule)" state="open" >}} + {{< filetree/folder name="scripts" >}} + {{< filetree/folder name="run" >}} + {{< filetree/file name="root (dispatcher)" >}} + {{< /filetree/folder >}} + {{< filetree/folder name="lib" >}} + {{< filetree/file name="shared libraries" >}} + {{< /filetree/folder >}} + {{< filetree/folder name="actions" >}} + {{< filetree/file name="shared actions" >}} + {{< /filetree/folder >}} + {{< /filetree/folder >}} {{< /filetree/folder >}} - {{< filetree/folder name="local" >}} - {{< filetree/file name="node-specific actions" >}} + {{< filetree/folder name="local" state="open" >}} + {{< filetree/folder name="scripts" >}} + {{< filetree/folder name="actions" >}} + {{< filetree/file name="node-specific overrides" >}} + {{< /filetree/folder >}} + {{< /filetree/folder >}} {{< /filetree/folder >}} {{< /filetree/folder >}} - {{< filetree/folder name="node-1" >}} + {{< filetree/folder name="daedalus (node)" >}} {{< filetree/file name="docker-compose.yml" >}} {{< /filetree/folder >}} + {{< filetree/file name="init.sh (bootstrap)" >}} {{< /filetree/folder >}} {{< /filetree/container >}} diff --git a/services/docs/content/en/root/concepts/security-model.md b/services/docs/content/en/root/concepts/security-model.md index 907668d..3e83e41 100644 --- a/services/docs/content/en/root/concepts/security-model.md +++ b/services/docs/content/en/root/concepts/security-model.md @@ -6,29 +6,62 @@ weight: 20 Security in Root is achieved through strict privilege isolation and project-level "sandboxing" to mitigate the impact of service compromises. -## The "No-Root" principle {#noroot} +## The "No-Root" Principle {#noroot} Running applications as `root` inside containers is a significant security risk. The framework enforces isolation via the `tiers/useradd` and `tiers/chown` actions. ### Project-specific users -Every project (e.g., `traefik`, `synapse`) is assigned a dedicated system user on the host. +Every project located at `{repository root}/{node}/{project}` is assigned a dedicated system user on the host. - **Isolation**: If a container is compromised, the attacker only gains the privileges of that specific low-privileged user. - **Filesystem safety**: Projects can only read/write to their own directories within the [Tiers](/root/glossary#tier). ## Docker socket protection {#socket-protection} -Direct access to `/var/run/docker.sock` is equivalent to root access on the host. To prevent services from abusing this access, the framework utilizes a **Socket Proxy**. +Direct access to `/var/run/docker.sock` is equivalent to root access on the host. As a best practice, it is highly recommended to protect the Docker socket. One way to achieve this is by utilizing a **Socket Proxy** (e.g., based on `tecnativa/docker-socket-proxy`) to filter and restrict access to the Docker API. -- **Restricted API**: The proxy filters Docker API calls, allowing only necessary operations (e.g., `GET containers`) and blocking dangerous ones (e.g., `POST containers/create`). +```yaml filename="docker-socket-proxy-example.yml" +services: + socket-proxy: + image: tecnativa/docker-socket-proxy:0 + container_name: root-socket-proxy + user: "0:0" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + CONTAINERS: 1 + SERVICES: 1 + TASKS: 1 + networks: + socket: {} + restart: unless-stopped + + traefik: + # ... + depends_on: + - socket-proxy + command: + # Use the proxy instead of the local socket + - "--providers.docker.endpoint=tcp://root-socket-proxy:2375" + networks: + socket: {} +``` + +## Security Monitoring (CrowdSec) {#crowdsec} + +The framework integrates **CrowdSec** for behavioral detection and automated response. + +- **Intrusion detection**: CrowdSec monitors logs from [Traefik](https://traefik.io/) and SSH for suspicious patterns (e.g., brute-force attacks, port scanning). +- **Automated blocking**: When a threat is detected, the **CrowdSec Firewall Bouncer** automatically updates [UFW](https://help.ubuntu.com/community/UFW) rules to block the malicious IP at the host level. +- **Shared threat intelligence**: CrowdSec shares anonymized threat data with its community, providing preemptive protection against known bad actors. ## Network hardening {#networking} Root uses `configure/ufw` to implement a "Default Deny" policy. -- **Internal routing**: Services communicate over a dedicated `root-direct` bridge network. -- **TProxy integration**: Outgoing traffic is routed through Xray for enclave-like isolation and granular routing rules. +- **Internal routing**: Services communicate over a dedicated `root-proxy` bridge network, which is often configured as `internal: true`. +- **Enclave isolation**: Outgoing traffic can be routed through a dedicated egress node for granular control. --- diff --git a/services/docs/content/en/root/concepts/tiered-storage.md b/services/docs/content/en/root/concepts/tiered-storage.md index ea194b1..0f419e0 100644 --- a/services/docs/content/en/root/concepts/tiered-storage.md +++ b/services/docs/content/en/root/concepts/tiered-storage.md @@ -8,37 +8,67 @@ The framework enforces a standardized storage taxonomy. This ensures that every ## The storage taxonomy {#taxonomy} -Data is divided into three logical [Tiers](/root/glossary#tier) based on its lifecycle, volume, and importance. +Data is divided into three logical [Tiers](/root/glossary#tier) based on its performance requirements, lifecycle, and importance. -### Tier 1: Configuration & critical state +### Tier 1: Configuration & Cache **Path:** `${ROOT_NODE_DIR}/@tier1` -- **Contents**: Config files, small SQLite databases, SSL certificates. -- **Characteristics**: Extremely high value, low volume. -- **Backup strategy**: Frequent (hourly/daily), long retention. +- **Contents**: Config files, small SQLite databases, SSL certificates, application cache. +- **Characteristics**: Extremely high value, low to medium volume, requires low latency. +- **Hardware**: High-speed SSD storage, typically shared with the Operating System. -### Tier 2: Application data +### Tier 2: Application Data **Path:** `${ROOT_NODE_DIR}/@tier2` - **Contents**: User uploads, large databases, persistent application state. -- **Characteristics**: High value, medium to high volume. -- **Backup strategy**: Daily, prioritized for integrity. +- **Characteristics**: High value, medium to high volume, requires high reliability. +- **Hardware**: Reliable HDD clusters, RAID arrays, or dedicated storage compute. -### Tier 3: Transients & bulk media +### Tier 3: Transients & Bulk Media **Path:** `${ROOT_NODE_DIR}/@tier3` -- **Contents**: Logs, caches, temporary files, bulk media downloads. -- **Characteristics**: Low value, high volume. -- **Backup strategy**: Minimal or none. These directories are typically excluded from sync operations. +- **Contents**: Logs, temporary files, bulk media (movies, music), and other non-critical large data. +- **Characteristics**: Low value, very high volume. +- **Hardware**: High-capacity HDDs optimized for continuous sequential write/read (e.g., WD Purple). Note that Tier 3 is **too slow for cache**. + +## Backup strategy {#backup} + +The framework does not enforce a specific backup strategy or provide a default implementation, allowing for complete node-specific flexibility. Operators are expected to implement their own backup logic. + +### Example: Restic backup + +A common best practice is to use **Restic** for backups. For example, you might create an operator compose file to run Restic: + +```yaml filename="operator-compose.yml" +services: + restic: + image: restic/restic:0.18.1 + container_name: operator-restic + volumes: + - ./@tier2/{project}/{service}/{data}:/data/@tier2/{project}/{service}/{data}:ro + - ./@tier1/{project}/{service}/{data}:/data/@tier1/{project}/{service}/{data}:ro + - ./@tier1/.operator/restic/cache:/var/restic-cache + environment: + RESTIC_REPOSITORY: "s3:example.com/bucket" + RESTIC_PASSWORD: ${RESTIC_PASSWORD} + # ... AWS/S3 credentials + network_mode: "host" + entrypoint: [ "restic" ] + user: "0:0" +``` + +### Implementing the strategy + +Operators can implement this strategy by defining a local action in `.operator/local/scripts/actions/sync/tiers`. The `root` dispatcher can then execute this script to trigger the backup, allowing for granular control over how data is persisted. ## Justification {#justification} -1. **Backup efficiency**: By separating logs (Tier 3) from configs (Tier 1), we avoid wasting storage space on redundant backups of transient data. -2. **Hardware optimization**: Tier 1 and 2 can be placed on fast SSD storage, while Tier 3 can be mounted on slower, high-capacity HDDs. -3. **Instant understanding**: Any operator can enter a [Node](/root/glossary#node) directory and immediately know where the critical data resides. +1. **Hardware optimization**: By mapping tiers to specific hardware (SSDs for Tier 1, RAID for Tier 2, Purples for Tier 3), we optimize for both performance and cost. +2. **Selective backup**: Separating transient logs and bulk media (Tier 3) from critical configs (Tier 1) prevents wasting expensive backup storage. +3. **Architectural clarity**: Any operator can inspect a [Node](/root/glossary#node) directory and immediately understand the storage requirements and priority of its contents. --- diff --git a/services/docs/content/en/root/guides/_index.md b/services/docs/content/en/root/guides/_index.md index 3b60a0a..591c615 100644 --- a/services/docs/content/en/root/guides/_index.md +++ b/services/docs/content/en/root/guides/_index.md @@ -4,9 +4,10 @@ description: Step-by-step guides for installation and action development. weight: 20 --- -Step-by-step guides for installing and developing within the Root infrastructure framework. +Step-by-step guides for installing and developing within the ermnvldmr.com root deployment commons framework. {{% cards %}} -{{< card link="installation" title="Installation" icon="arrow-down" subtitle="Initial setup of the Root framework on a new host." >}} +{{< card link="first-node" title="Setting Up Your First Node" icon="map" subtitle="Practical guide to creating your own config repository." >}} +{{< card link="installation" title="Installation" icon="arrow-down" subtitle="Initial setup of the framework on a new host." >}} {{< card link="action-development" title="Action development" icon="code" subtitle="Creating and managing atomic automation tasks." >}} {{% /cards %}} diff --git a/services/docs/content/en/root/guides/first-node.md b/services/docs/content/en/root/guides/first-node.md new file mode 100644 index 0000000..38ef8b8 --- /dev/null +++ b/services/docs/content/en/root/guides/first-node.md @@ -0,0 +1,190 @@ +--- +title: "Setting Up Your First Node" +description: A practical guide on creating your first node and hooking up the deployment commons. +weight: 25 +--- + +**Goal:** Create a configuration repository for your infrastructure, add the root deployment commons as a submodule, and define your first basic node. + +## 1. Creating the Configuration Repository + +Your infrastructure should be managed from a single Git repository. This repository will hold the configuration for all your servers (nodes). + +{{% steps %}} + +### Step 1: Initialize the repository + +Create a new directory and initialize Git. + +```bash +mkdir my-infrastructure +cd my-infrastructure +git init +``` + +### Step 2: Add the commons submodule + +The `ermnvldmr.com-root-commons` must be placed at `.operator/shared`. + +```bash +mkdir -p .operator +git submodule add https://github.com/deytenit/ermnvldmr.com-root-commons.git .operator/shared +``` + +### Step 3: Create the Bootstrap Script + +Create an `init.sh` file at the root of your repository. This script links the commons framework into your local environment. + +```bash filename="init.sh" +#!/usr/bin/env bash +# init.sh + +# Source common utilities from the submodule +source "$(git -C "$(dirname "$0")" rev-parse --show-toplevel)/.operator/shared/scripts/lib/common.sh" + +SCRIPT_NAME="init" + +navigate_to_repo_root + +log_info "Setting up Git hooks..." +git config core.hooksPath .operator/shared/githooks +git config --global --add safe.directory "${REPO_ROOT}" + +log_info "Setting up PATH for the root dispatcher..." +ABSOLUTE_RUN_DIR="$(realpath "${REPO_ROOT}/.operator/shared/scripts/run")" +BASHRC_ENTRY="export PATH=\"${ABSOLUTE_RUN_DIR}:\$PATH\"" + +sed -i '/\.operator\/shared\/scripts\/run/d' ~/.bashrc +echo "$BASHRC_ENTRY" >> ~/.bashrc +log_info "Done. Please run 'source ~/.bashrc' or re-login to your shell." +``` + +Make it executable: +```bash +chmod +x init.sh +``` + +{{% /steps %}} + +## 2. Defining Your First Node + +A Node is a folder at the repository root that represents one physical or virtual server. + +### Node Structure + +Let's create a node named `daedalus`. Inside, we'll define an operator configuration (e.g., for backups) and a core service. + +```bash +mkdir -p daedalus/.operator/configs/{cron,crowdsec,systemd,ufw/docker,ufw/host} +mkdir -p daedalus/root +``` + +### Base Configurations (Optional) + +You can place configuration files (like UFW rules or a crontab) inside the `daedalus/.operator/configs/` directory. For example, a basic crontab: + +```bash filename="daedalus/.operator/configs/cron/crontab.template" +# Run backups every night at 3:00 AM +0 3 * * * root sync tiers daedalus +``` + +## 3. Configuring Services (Docker Compose) + +The framework relies on `docker-compose.yml` to orchestrate services. + +### Node-Level Infrastructure (Operator) + +The `daedalus/docker-compose.yml` file runs infrastructure utilities, such as `restic` for backups or VPN agents. This compose file has direct access to the filesystem via `@tierX` mounts. + +```yaml filename="daedalus/docker-compose.yml" +name: 'operator' + +services: + restic: + image: restic/restic:0.18.1 + container_name: operator-restic + volumes: + # Example: mounting project data for backups (Read-Only) + - ./@tier2/my-app/data:/data/@tier2/my-app/data:ro + - ./@tier3/.operator/restic/cache:/var/restic-cache + environment: + RESTIC_REPOSITORY: "s3:example.com/my-bucket/daedalus" + RESTIC_PASSWORD: "${RESTIC_PASSWORD?error}" + # AWS credentials... + network_mode: "host" + entrypoint: [ "restic" ] +``` + +### The Root Project + +The `root` project typically contains your reverse proxies (Traefik) and core services that other projects will route through. + +```yaml filename="daedalus/root/docker-compose.yml" +name: root + +services: + socket-proxy: + image: tecnativa/docker-socket-proxy:0 + container_name: root-socket-proxy + user: "0:0" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + CONTAINERS: 1 + SERVICES: 1 + TASKS: 1 + networks: + socket: {} + restart: unless-stopped + + traefik: + image: traefik:3.6 + container_name: root-traefik + # UID and GID are automatically populated by the framework after running 'root tiers useradd' + user: "${UID?error}:${GID?error}" + group_add: + - "${SHARED_GID?error}" + depends_on: + - socket-proxy + volumes: + - ./@tier1/shared/root/traefik/letsencrypt:/letsencrypt + - ./@tier3/traefik/logs:/logs + - ./@tier1/traefik/dynamic:/etc/traefik/dynamic:ro + ports: + - '0.0.0.0:80:80' + - '0.0.0.0:443:443' + networks: + proxy: {} + socket: {} + command: + - "--api.dashboard=true" + - "--providers.docker=true" + - "--providers.docker.network=root-proxy" + - "--providers.docker.endpoint=tcp://root-socket-proxy:2375" + restart: unless-stopped + +networks: + proxy: + name: root-proxy + internal: true + driver: bridge + socket: + name: root-socket + internal: true + driver: bridge +``` + +## 4. Deployment + +Now that your structure is ready: + +1. Commit and push this repository to your Git server (e.g., GitHub). +2. SSH into your VPS. +3. Follow the [Installation](/root/guides/installation) guide, using your new repository URL instead of the example ones. + +--- + +**See also:** + +- [Guide: Installation on a new host](/root/guides/installation) +- [Concept: Infrastructure Architecture](/root/concepts/architecture) diff --git a/services/docs/content/en/root/guides/installation.md b/services/docs/content/en/root/guides/installation.md index b6bdcae..18df0e7 100644 --- a/services/docs/content/en/root/guides/installation.md +++ b/services/docs/content/en/root/guides/installation.md @@ -1,60 +1,199 @@ --- -title: Installation -description: Initial setup of the Root framework on a new host. -weight: 25 +title: Initial Host Setup +description: Setting up a fresh Debian host from scratch. +weight: 1 --- -This guide covers the initial setup of the Root framework on a new host. +Hardened setup for a fresh Debian host from zero to deployment. -## Prerequisites {#prerequisites} - -- A Debian-based Linux distribution (Debian or Ubuntu). -- Git installed. -- Sudo privileges. - -## Initializing the repository {#init} +## Setup Procedure {{% steps %}} -### Step 1: Clone the configuration repository +### Essential Packages -Clone the repository containing your [Node](/root/glossary#node) configurations. +Install `sudo` and `docker-ce` first. This is necessary because the subsequent user setup relies on the `docker` group and `sudo` configuration. + +**Install Sudo** ```bash -git clone ~/repo -cd ~/repo +# As root: +apt update && apt install sudo -y ``` -### Step 2: Run the initialization script +**Install Docker** -The `init.sh` script sets up the [Commons](/root/glossary#commons) submodule, configures Git hooks, and adds the `root` wrapper to your `PATH`. +Follow the [Official Docker Installation Guide for Debian](https://docs.docker.com/engine/install/debian/) to install the latest Docker Engine. + +### System User & Privileges + +The `adam` user handles all administrative tasks. SSH-key authentication and passwordless `sudo` via the `wheel` group minimize friction while maintaining security. + +**Create the Admin User** ```bash -./init.sh +# As root: +# Create the user with a bash shell +useradd -m -s /bin/bash adam + +# Create the wheel group (common for cross-distro consistency) +groupadd wheel + +# Create a modular sudoers file +# This allows members of 'wheel' to run sudo without a password +echo "%wheel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/99-custom-sudoers + +# Validate syntax +visudo -c -f /etc/sudoers.d/99-custom-sudoers + +# Add adam to the necessary groups +usermod -aG wheel,docker adam ``` -### Step 3: Refresh your shell +### Swap Setup -Source your `.bashrc` to activate the `root` command. +Configure a swap file to ensure system stability during memory-intensive operations. ```bash -source ~/.bashrc +# As root: +# Create a 2GB swap file (adjust size as needed) +fallocate -l 2G /swap +chmod 600 /swap +mkswap /swap +swapon /swap + +# Make it permanent +echo '/swap none swap sw 0 0' >> /etc/fstab +``` + +### SSH Access & Hardening + +Passwords are disabled. Access is strictly via SSH keys. + +**Authorize Operator Key** + +Import your local public key to the `adam` user. + +```bash +# As root: +# Setup directories +mkdir -p /home/adam/.ssh +chmod 700 /home/adam/.ssh + +# Add your public key (Replace [PASTE_PUB_KEY_HERE]) +echo "[PASTE_PUB_KEY_HERE]" > /home/adam/.ssh/authorized_keys +chmod 600 /home/adam/.ssh/authorized_keys +chown -R adam:adam /home/adam/.ssh +``` + +**Operator Side Access** + +Configure your local machine for easy access to the host. + +```bash +# ~/.ssh/config on operator side +Host daedalus.example.com + Port 2222 + User adam + IdentityFile ~/.ssh/adam_example_com_ed25519 +``` + +**Harden SSH Daemon** + +Modify the SSH configuration to change the default port and disable password entry. + +```bash +# As root: +# Create a dedicated override config +cat < /etc/ssh/sshd_config.d/99-custom-ssh.conf +Port 2222 +PasswordAuthentication no +PermitEmptyPasswords no +AllowUsers adam +EOF + +# Validate syntax before restarting to avoid lockout +sshd -t && systemctl restart ssh +``` + +### GitHub Access (Deploy Key) + +The host requires its own identity to pull updates from the GitHub repository. + +```bash +# As root: +# Generate a host-specific SSH key (no passphrase for automation) +sudo -u adam ssh-keygen -t ed25519 -f /home/adam/.ssh/github_ed25519 -N "" + +# Configure SSH to use this key for GitHub +cat < Deploy Keys) +cat /home/adam/.ssh/github_ed25519.pub +``` + +> [!TIP] +> Add the output above to the Deploy Keys settings of your infrastructure repository (e.g., `https://github.com/your-username/your-repo/settings/keys`) with **read access**. + +### Repository Deployment + +Clone your infrastructure repository and initialize the node. + +```bash +# As root: +# Setup the service directory +export REPO_DIR="/srv/your-infrastructure-repo" +mkdir -p $REPO_DIR +chown adam:adam $REPO_DIR + +# Clone as the adam user +sudo -u adam git clone git@github.com:your-username/your-repo.git $REPO_DIR + +# Initialize node (Set your node name, e.g., daedalus) +export NODE="daedalus" +cd $REPO_DIR +sudo -u adam ./init.sh +``` + +**Node-Specific Configuration** + +Run the staged initialization scripts using the `root` dispatcher: + +```bash +# Run the sequence for your specific node (as the 'adam' user) +# Ensure you have sourced ~/.bashrc or re-logged in if 'root' is not found +root configure base $NODE +root configure ufw $NODE +root configure crowdsec $NODE +root configure cron $NODE +``` + +### Storage & Hardening + +Define the data tiers and secure the environment by creating non-root users for containerized services. + +```bash +# Create (or mount) storage directories +sudo mkdir -p /srv/my-infrastructure-root-$NODE-{tier1,tier2,tier3} + +# Setup tiers and non-root users +root tiers link $NODE \ + /srv/my-infrastructure-root-$NODE-tier1 \ + /srv/my-infrastructure-root-$NODE-tier2 \ + /srv/my-infrastructure-root-$NODE-tier3 + +root tiers useradd $NODE +root tiers chown $NODE ``` {{% /steps %}} -## Provisioning a node {#provision} - -Once the framework is installed, you can provision a specific [Node](/root/glossary#node). - -```bash -root configure/base -root configure/ufw -``` - --- **See also:** -- [Concept: Infrastructure architecture](/root/concepts/architecture) -- [Reference: ROOT_ API reference](/root/reference/root-api) +- [Doc: Docker - Install on Debian](https://docs.docker.com/engine/install/debian/) diff --git a/services/docs/content/en/root/recipes/_index.md b/services/docs/content/en/root/recipes/_index.md deleted file mode 100644 index 49ccaa1..0000000 --- a/services/docs/content/en/root/recipes/_index.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: 'Recipes' -description: 'Collection of step-by-step procedures for infrastructure maintenance and deployment.' -weight: 50 ---- - -Step-by-step instructions for reproducible tasks and infrastructure maintenance. - -## Available Recipes - -{{% cards %}} -{{< card link="initial-setup" title="Initial Host Setup" icon="server" subtitle="Hardened setup for a fresh Debian host from zero to deployment." >}} -{{% /cards %}} - ---- - -**See also:** - -- [GitHub: root.ermnvldmr.com](https://github.com/deytenit/root.ermnvldmr.com) diff --git a/services/docs/content/en/root/recipes/initial-setup.md b/services/docs/content/en/root/recipes/initial-setup.md deleted file mode 100644 index ac11b34..0000000 --- a/services/docs/content/en/root/recipes/initial-setup.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -title: 'Initial Host Setup' -description: 'Setting up a fresh Debian host from scratch.' -weight: 1 ---- - -Hardened setup for a fresh Debian host from zero to deployment. - -## Setup Procedure - -{{% steps %}} - -### Essential Packages - -Install `sudo` and `docker-ce` first. This is necessary because the subsequent user setup relies on the `docker` group and `sudo` configuration. - -**Install Sudo** - -```bash -# As root: -apt update && apt install sudo -y -``` - -**Install Docker** - -Follow the [Official Docker Installation Guide for Debian](https://docs.docker.com/engine/install/debian/) to install the latest Docker Engine. - -### System User & Privileges - -The `adam` user handles all administrative tasks. SSH-key authentication and passwordless `sudo` via the `wheel` group minimize friction while maintaining security. - -**Create the Admin User** - -```bash -# As root: -# Create the user with a bash shell -useradd -m -s /bin/bash adam - -# Create the wheel group (common for cross-distro consistency) -groupadd wheel - -# Create a modular sudoers file -# This allows members of 'wheel' to run sudo without a password -echo "%wheel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/99-root-ermnvldmr - -# Validate syntax -visudo -c -f /etc/sudoers.d/99-root-ermnvldmr - -# Add adam to the necessary groups -usermod -aG wheel,docker adam -``` - -### Swap Setup - -Configure a swap file to ensure system stability during memory-intensive operations. - -```bash -# As root: -# Create a 2GB swap file (adjust size as needed) -fallocate -l 2G /swap -chmod 600 /swap -mkswap /swap -swapon /swap - -# Make it permanent -echo '/swap none swap sw 0 0' >> /etc/fstab -``` - -### SSH Access & Hardening - -Passwords are disabled. Access is strictly via SSH keys. - -**Authorize Operator Key** - -Import your local public key to the `adam` user. - -```bash -# As root: -# Setup directories -mkdir -p /home/adam/.ssh -chmod 700 /home/adam/.ssh - -# Add your public key (Replace [PASTE_PUB_KEY_HERE]) -echo "[PASTE_PUB_KEY_HERE]" > /home/adam/.ssh/authorized_keys -chmod 600 /home/adam/.ssh/authorized_keys -chown -R adam:adam /home/adam/.ssh -``` - -**Operator Side Access** - -Configure your local machine for easy access to the host. - -```bash -# ~/.ssh/config on operator side -Host daedalus.root.ermnvldmr.com - Port 2222 - User adam - IdentityFile ~/.ssh/adam_root_ermnvldmr_com_ed25519 -``` - -**Harden SSH Daemon** - -Modify the SSH configuration to change the default port and disable password entry. - -```bash -# As root: -# Create a dedicated override config -cat < /etc/ssh/sshd_config.d/99-root-ermnvldmr.conf -Port 2222 -PasswordAuthentication no -PermitEmptyPasswords no -AllowUsers adam -EOF - -# Validate syntax before restarting to avoid lockout -sshd -t && systemctl restart ssh -``` - -### GitHub Access (Deploy Key) - -The host requires its own identity to pull updates from the GitHub repository. - -```bash -# As root: -# Generate a host-specific SSH key (no passphrase for automation) -sudo -u adam ssh-keygen -t ed25519 -f /home/adam/.ssh/github_ed25519 -N "" - -# Configure SSH to use this key for GitHub -cat < Deploy Keys) -cat /home/adam/.ssh/github_ed25519.pub -``` - -> [!TIP] -> Add the output above to the [GitHub: Repository Deploy Keys](https://github.com/deytenit/root.ermnvldmr.com/settings/keys) with **read access**. - -### Repository Deployment - -Clone the infrastructure repository and initialize the node. - -```bash -# As root: -# Setup the service directory -export REPO_DIR="/srv/root.ermnvldmr.com" -mkdir -p $REPO_DIR -chown adam:adam $REPO_DIR - -# Clone as the adam user -sudo -u adam git clone git@github.com:deytenit/root.ermnvldmr.com.git $REPO_DIR - -# Initialize node (Set your node name, e.g., daedalus) -export NODE="daedalus" -cd $REPO_DIR -sudo -u adam ./init.sh -``` - -**Node-Specific Configuration** - -Run the staged initialization scripts in order: - -```bash -# As root: -# Run the sequence for your specific node -cd $REPO_DIR -./$NODE/.host/.scripts/00-base -./$NODE/.host/.scripts/10-ufw -./$NODE/.host/.scripts/20-crowd -./$NODE/.host/.scripts/30-cron -``` - -### Storage & Hardening - -Define the data tiers and secure the environment by creating non-root users for containerized services. - -```bash -# As root: -# Create (or mount) storage directories -mkdir -p /srv/com-ermnvldmr-root-$NODE-{tier1,tier2,tier3} - -# Setup tiers and non-root users -cd $REPO_DIR -sudo -u adam .scripts/ops/setup-tiers $NODE \ - /srv/com-ermnvldmr-root-$NODE-tier1 \ - /srv/com-ermnvldmr-root-$NODE-tier2 \ - /srv/com-ermnvldmr-root-$NODE-tier3 - -sudo -u adam .scripts/ops/setup-noroot-users $NODE -``` - -{{% /steps %}} - ---- - -**See also:** - -- [Doc: Docker - Install on Debian](https://docs.docker.com/engine/install/debian/) -- [GitHub: root.ermnvldmr.com](https://github.com/deytenit/root.ermnvldmr.com) diff --git a/services/docs/content/en/root/reference/_index.md b/services/docs/content/en/root/reference/_index.md index 435c576..5a49bad 100644 --- a/services/docs/content/en/root/reference/_index.md +++ b/services/docs/content/en/root/reference/_index.md @@ -4,8 +4,15 @@ description: API and technical references for developers. weight: 30 --- -Technical reference materials and APIs for the Root framework. +Technical reference materials and APIs for the ermnvldmr.com root deployment commons framework. {{% cards %}} +{{< card link="compose" title="Compose actions reference" icon="play" subtitle="High-level entrypoint for orchestrating docker-compose." >}} +{{< card link="configure" title="Configure actions reference" icon="arrow-down" subtitle="Host provisioning and system-level configuration." >}} +{{< card link="initialization" title="Initialization actions reference" icon="play" subtitle="Actions for initial node setup." >}} {{< card link="root-api" title="ROOT_ API reference" icon="code" subtitle="Standardized environment variables and logging helpers." >}} +{{< card link="source" title="Source services reference" icon="book-open" subtitle="Shared services built from source." >}} +{{< card link="sync" title="Sync actions reference" icon="check" subtitle="Actions for keeping nodes up-to-date." >}} +{{< card link="tiers" title="Tiers actions reference" icon="archive" subtitle="Storage tiers management." >}} +{{< card link="utils" title="Utility actions reference" icon="check" subtitle="Helper scripts and utilities." >}} {{% /cards %}} diff --git a/services/docs/content/en/root/reference/compose.md b/services/docs/content/en/root/reference/compose.md new file mode 100644 index 0000000..21e88ea --- /dev/null +++ b/services/docs/content/en/root/reference/compose.md @@ -0,0 +1,50 @@ +--- +title: Compose Actions +description: Standardized high-level entrypoint for orchestrating docker-compose across a node. +weight: 54 +--- + +The `compose` action provides a standardized, high-level entrypoint for orchestrating Docker Compose files across all projects within a specific node. + +## Core Compose Action {#actions} + +| Action | Description | +| :--- | :--- | +| `compose ` | Executes a given Docker Compose command (e.g., `up`, `down`, `restart`) across the node's infrastructure. | + +## Orchestration Order {#order} + +To maintain correct dependencies (especially when shutting down or starting up infrastructure-level proxies and networks), the `compose` action intelligently orders the execution: + +### Starting Up (`up`, `restart`) +When starting or restarting services, the action follows a **Forward Order**: +1. **Node Infrastructure**: First, it processes the node-level `docker-compose.yml` (located at the root of the node directory). +2. **Root Infrastructure**: Next, it processes the `root/docker-compose.yml` project, if it exists (usually contains Traefik, Socket Proxy, etc.). +3. **Projects**: Finally, it processes all other project directories in alphabetical order. + +### Shutting Down (`down`) +When stopping services, the action uses a **Reverse Order** to ensure projects disconnect gracefully before the network or proxy goes down: +1. **Projects**: All standard projects are stopped in reverse alphabetical order. +2. **Root Infrastructure**: The `root/docker-compose.yml` project is stopped. +3. **Node Infrastructure**: Finally, the node-level `docker-compose.yml` is brought down. + +## Options {#options} + +You can pass standard Docker Compose arguments to the end of the command. +Additionally, the action supports a dry-run mode: + +- `--dry-run`: Prints the commands that would be executed without actually running them. + +**Example usage:** +```bash +root compose daedalus up -d --remove-orphans +root compose daedalus restart --dry-run +root compose daedalus down +``` + +--- + +**See also:** + +- [Concept: Infrastructure Architecture](/root/concepts/architecture) +- [Reference: ROOT_ API Reference](/root/reference/root-api) diff --git a/services/docs/content/en/root/reference/configure.md b/services/docs/content/en/root/reference/configure.md new file mode 100644 index 0000000..f75c200 --- /dev/null +++ b/services/docs/content/en/root/reference/configure.md @@ -0,0 +1,66 @@ +--- +title: Configuration Actions +description: Host provisioning, template engine, and system-level configuration. +weight: 53 +--- + +Configuration actions are used to provision the host and maintain system-level services. They rely heavily on the built-in template engine to generate declarative configuration files. + +## The Template Engine {#template-engine} + +The Root framework uses `envsubst` (from `gettext-base`) to render templates. This allows you to use standard Bash environment variables directly within your configuration files. + +### Template Conventions + +- **File Extension**: Templates typically use the `.template` extension (e.g., `crontab.template`). +- **Variable Syntax**: Use `${VARIABLE_NAME}` or `$VARIABLE_NAME` to inject values. +- **Auto-Discovery**: Many actions automatically look for templates in specific directories within the [Configs](/root/glossary#configs) repository. + +### Rendering Helpers + +The `root_template.sh` library provides several helpers: + +- `root_template_render `: Renders a single file. +- `root_template_render_directory `: Recursively renders an entire directory structure. +- `root_template_crontab