docs: Update docs for the correctness (#13)

This commit is contained in:
deytenit authored and GitHub committed 2026-04-15 00:48:06 +03:00
1 parent 8dba55272c
commit 51a783f93a
60 files changed
+2456 -380

No files matched your search

+3 -5
View File
@@ -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)
@@ -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." >}}
@@ -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 >}}
@@ -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.
---
@@ -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.
---
@@ -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 %}}
@@ -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)
@@ -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 <your-configs-repo-url> ~/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 <<EOF > /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 <<EOF | sudo -u adam tee /home/adam/.ssh/config
Host github.com
AddKeysToAgent yes
IdentityFile ~/.ssh/github_ed25519
EOF
# Display the public key to be added to GitHub (Settings > 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 <node_name>
root configure/ufw <node_name>
```
---
**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/)
@@ -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)
@@ -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 <<EOF > /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 <<EOF | sudo -u adam tee /home/adam/.ssh/config
Host github.com
AddKeysToAgent yes
IdentityFile ~/.ssh/github_ed25519
EOF
# Display the public key to be added to GitHub (Settings > 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)
@@ -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 %}}
@@ -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 <node> <action>` | 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)
@@ -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 <input> <output>`: Renders a single file.
- `root_template_render_directory <src> <dest>`: Recursively renders an entire directory structure.
- `root_template_crontab <template>`: Renders and installs a crontab for the current user.
## Core Configuration Actions {#actions}
| Action | Description |
| :--- | :--- |
| `configure/base` | Installs essential packages (`sudo`, `ufw`, `docker`) and sets up basic system users. |
| `configure/cron` | Renders and installs node-specific crontabs. |
| `configure/crowdsec` | Sets up the CrowdSec agent and bouncers. |
| `configure/routing` | Configures system-level routing and bridge networks. |
| `configure/systemd` | Installs and enables systemd service units. |
| `configure/ufw` | Renders and applies firewall rules using UFW and `ufw-docker`. |
## Example: Nginx Template {#example}
```nginx filename="nginx.conf.template"
# This template uses ROOT_NODE environment variable
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Injected from environment
server_name ${ROOT_NODE}.example.com;
}
```
---
**See also:**
- [Concept: Infrastructure Architecture](/root/concepts/architecture)
- [Reference: ROOT_ API Reference](/root/reference/root-api)
@@ -0,0 +1,40 @@
---
title: System Initialization
description: Repository setup, Git hooks, and PATH configuration.
weight: 51
---
The Root framework requires a one-time initialization on each host to establish path linkages and repository-level configurations.
## The `init.sh` Script {#init-script}
The `init.sh` script located at the repository root is the primary bootstrap mechanism. It performs the following critical tasks:
1. **Submodule Initialization**: Ensures the [Commons](/root/glossary#commons) repository is present and up to date.
2. **Git Hook Configuration**: Points `core.hooksPath` to `.operator/shared/githooks` to enable standardized pre-commit checks.
3. **Safe Directory Registration**: Adds the repository to Git's `safe.directory` list, which is required for operations performed by different users (e.g., `root`, `adam`).
4. **Vim Configuration**: Links a standardized `.vimrc` to both the current user and the `root` user for a consistent editing experience.
5. **PATH Persistence**: Adds the `.operator/shared/scripts/run` directory to the user's `~/.bashrc`, making the `root` command available globally.
## Git Hooks {#githooks}
Root enforces standards through Git hooks stored in `.operator/shared/githooks/`.
- **Pre-commit**: Validates that all scripts follow the namespacing and structure conventions.
- **Commit-msg**: (Optional) Enforces conventional commit messages if configured.
## PATH Configuration {#path}
The `root` command is a wrapper located in `.operator/shared/scripts/run/root`. By adding this directory to the `PATH`, the dispatcher can be invoked from any directory within the system, automatically resolving the repository root based on the current working directory or environment variables.
```bash
# Example of manual PATH addition (performed automatically by init.sh)
export PATH="$HOME/repo/.operator/shared/scripts/run:$PATH"
```
---
**See also:**
- [Guide: Initial Host Setup](/root/guides/installation)
- [Reference: ROOT_ API Reference](/root/reference/root-api)
@@ -4,11 +4,19 @@ description: Standardized environment variables for path resolution and node con
weight: 50
---
Every [Action](/root/glossary#action) script executed via the `root` dispatcher has access to a standardized set of environment variables. These variables are the single source of truth for path resolution and node context.
Every [Action](/root/glossary#action) script executed via the `root` dispatcher has access to a standardized set of environment variables and Bash libraries. This provides a consistent "API" for interacting with the infrastructure.
## The `root` Dispatcher {#dispatcher}
The `root` command (located in `.operator/shared/scripts/run/root`) is the main entrypoint for all orchestration. Its primary responsibilities include:
1. **Context Resolution**: Locating the target [Node](/root/glossary#node) and its associated storage [Tiers](/root/glossary#tier).
2. **Library Loading**: Sourcing the core namespaced libraries (e.g., `root_core`, `root_sys`).
3. **Action Execution**: Discovering and running the requested action, prioritizing local overrides.
## Path resolution variables {#paths}
These variables define the physical location of the infrastructure components.
These variables are established by the dispatcher and are available to all actions.
| Variable | Description |
| :--- | :--- |
@@ -20,40 +28,35 @@ These variables define the physical location of the infrastructure components.
## Node context variables {#node-context}
When an action targets a specific [Node](/root/glossary#node), the following variables are established by the `root_require_node` helper.
When an action targets a specific node, the following variables are established by the `root_require_node` helper.
| Variable | Description |
| :--- | :--- |
| `ROOT_NODE` | The identifier of the target node (e.g., `icarus`). |
| `ROOT_NODE` | The identifier of the target node (e.g., `daedalus`). |
| `ROOT_NODE_DIR` | Absolute path to the node configuration directory. |
| `ROOT_TIER1` | Absolute path to the [Tier 1](/root/glossary#tier) storage directory. |
| `ROOT_TIER2` | Absolute path to the Tier 2 storage directory. |
| `ROOT_TIER3` | Absolute path to the Tier 3 storage directory. |
## Logging helpers {#logging}
## Core Logging Helpers {#logging}
Standardized logging uses the `[$ROOT_NODE] [$ROOT_ACTION_PATH]` prefix for consistency across the orchestration logs.
Standardized logging ensure consistent output across all actions.
- `root_log_info`: Standard informational output.
- `root_log_warn`: Warnings requiring attention but not stopping execution.
- `root_log_warn`: Warnings requiring attention.
- `root_log_error`: Critical errors sent to `stderr`.
- `root_log_success`: Confirmation of successful task completion.
## Help system metadata {#help}
## The Help System {#help}
The `root` [Dispatcher](/root/glossary#dispatcher) provides a built-in `--help` system. To keep action scripts "stupid", they do not implement their own help flags. Instead, the dispatcher parses a specific `action_metadata` block defined at the top of every action script.
When a user runs `root <action> --help`, the dispatcher extracts and displays this YAML-formatted block without executing the script.
### Example metadata
The dispatcher provides a built-in help system by parsing an `action_metadata` block at the top of each script. This allows scripts to remain "stupid" and declarative without implementing their own CLI argument parsing.
```bash filename="example-action-metadata"
action_metadata() {
cat <<EOF
description: "Brief summary of the task."
description: "Brief summary of the action."
args:
- NODE: "The node name"
- PARAM: "A custom parameter"
- NODE: "The name of the target node."
EOF
}
```
@@ -0,0 +1,42 @@
---
title: The `source/` Directory
description: Conceptual overview of the self-contained source directory structure.
weight: 52
---
The `source/` directory at the repository root contains the core components and projects that the Root framework orchestrates. It is designed for maximum isolation and self-containment.
## Core Philosophy {#philosophy}
The `source/` directory is not just a place to store code; it is a collection of independent [Projects](/root/glossary#project). Each project within this directory should follow these principles:
1. **Isolation**: Each project lives in its own subdirectory (e.g., `source/my-app/`).
2. **Self-Documentation**: Each project directory **MUST** contain its own `README.md` file describing its purpose, dependencies, and configuration.
3. **Internal Logic**: Projects handle their own build processes, Dockerfiles, and internal configurations. The Root framework's [Actions](/root/glossary#action) simply orchestrate these existing components.
## Directory Structure {#structure}
A typical project within the `source/` directory might look like this:
{{< filetree/container >}}
{{< filetree/folder name="source" state="open" >}}
{{< filetree/folder name="happ-subscription-generator" state="open" >}}
{{< filetree/file name="Dockerfile" >}}
{{< filetree/file name="generator.py" >}}
{{< filetree/file name="README.md" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
## Relationship with Actions {#actions}
Root actions (like `compose` or `sync`) interact with the `source/` directory by referencing paths within it. For example, the `compose` action might use a `docker-compose.yml` file that points to a `Dockerfile` located in `source/app/`.
This separation of concerns ensures that the orchestration logic (Actions) remains decoupled from the implementation details (Source).
---
**See also:**
- [Concept: Infrastructure Architecture](/root/concepts/architecture)
- [Reference: ROOT_ API Reference](/root/reference/root-api)
@@ -0,0 +1,36 @@
---
title: Synchronization Actions
description: Repository updates, package synchronization, and data backups.
weight: 54
---
Synchronization actions ensure that the host's state remains consistent with the defined configurations in the remote repositories.
## Core Synchronization Actions {#actions}
| Action | Description |
| :--- | :--- |
| `sync/packages` | Synchronizes node packages and their configurations across the system. |
| `sync/repository` | Updates the main configuration repository to its latest state from GitHub. |
| `sync/tiers` | Triggers the node-specific backup strategy for the configured [Tiers](/root/glossary#tier). |
## Repository Synchronization (`sync/repository`) {#repository}
The `sync/repository` action is responsible for keeping the host's configuration repository up-to-date with its remote source. It typically performs a `git pull` on the main configuration repository and may optionally trigger sub-module updates for the [Commons](/root/glossary#commons) repository.
This ensures that any changes to the node configurations, actions, or source files are correctly pulled down to the target host.
## Backup Synchronization (`sync/tiers`) {#tiers}
The `sync/tiers` action is the primary entry point for a node's backup strategy.
- **No Default Implementation**: The framework itself does not provide a default backup mechanism, allowing operators to design a custom strategy suitable for their needs.
- **Custom Overrides**: As a "Smart Dispatcher" action, you can define your backup logic by placing a custom script in `.operator/local/scripts/actions/sync/tiers`.
- **Example Implementation**: A common practice is to use a tool like [Restic](https://restic.net/) within this custom script to perform off-site backups of critical data (Tiers 1 and 2) to an S3-compatible storage backend.
---
**See also:**
- [Concept: Tiered Storage Model](/root/concepts/tiered-storage)
- [Reference: ROOT_ API Reference](/root/reference/root-api)
@@ -0,0 +1,44 @@
---
title: Tier Management Actions
description: Storage classification, symbolic linking, and privilege isolation.
weight: 55
---
Tier management actions are responsible for enforcing the framework's [Tiered Storage Model](/root/concepts/tiered-storage) and ensuring correct filesystem ownership and isolation.
## Core Tier Actions {#actions}
| Action | Description |
| :--- | :--- |
| `tiers/chown` | Sets correct filesystem ownership for project-specific [Non-Root Users](#useradd). |
| `tiers/link` | Manages symbolic links between the project directories and their corresponding [Tiers](/root/glossary#tier). |
| `tiers/useradd` | Provisions a unique system user for each project to achieve [Privilege Isolation](/root/concepts/security-model). |
## User Management (`tiers/useradd`) {#useradd}
The `tiers/useradd` action creates a dedicated, low-privileged system user for each project within a node. This user is then used to run the project's containers, ensuring that a compromise of one project does not grant the attacker access to the entire host.
- **Naming Convention**: Users are typically named after the project.
- **Group Membership**: Users can optionally be added to the `docker` group or interact with Docker via other securely configured methods, depending on the operator's preference.
## Storage Linking (`tiers/link`) {#link}
The `tiers/link` action creates the symbolic link structure required for the tiered storage model. It ensures that directories like `config`, `data`, and `logs` within a project folder point to their physical locations in `@tier1`, `@tier2`, and `@tier3` respectively.
```bash
# Example link structure created by tiers/link
/srv/root/icarus/synapse/config -> /srv/storage/@tier1/synapse
/srv/root/icarus/synapse/data -> /srv/storage/@tier2/synapse
/srv/root/icarus/synapse/logs -> /srv/storage/@tier3/synapse
```
## Ownership Management (`tiers/chown`) {#chown}
Once tiers and links are established, the `tiers/chown` action ensures that the physical directories in each tier are owned by the correct project user. This is critical for preventing permission-denied errors and ensuring that projects can only access their own data.
---
**See also:**
- [Concept: Tiered Storage Model](/root/concepts/tiered-storage)
- [Concept: Security & Privilege Isolation](/root/concepts/security-model)
@@ -0,0 +1,37 @@
---
title: Utility Actions
description: Common helper scripts for maintenance, validation, and certificate management.
weight: 56
---
Utility actions provide common helper functions for node maintenance, validation, and project-specific tasks.
## Core Utility Actions {#actions}
| Action | Description |
| :--- | :--- |
| `utils/extract-traefik-certs` | Extracts SSL/TLS certificates and private keys from Traefik's `acme.json` storage. |
| `utils/generate-happ-subscriptions` | Automatically generates HApp subscription files based on current project metadata. |
| `utils/lint-docker-compose` | Performs a static analysis of all `docker-compose.yml` files to ensure they meet the framework's standards. |
## Certificate Management (`utils/extract-traefik-certs`) {#certificates}
Traefik stores its ACME-issued certificates (like those from Let's Encrypt) in a single `acme.json` file. The `utils/extract-traefik-certs` action parses this file and extracts individual `fullchain.pem` and `privkey.pem` files.
This is particularly useful when other services (e.g., mail servers, non-Dockerized applications) require the same SSL certificates.
## Quality Assurance (`utils/lint-docker-compose`) {#linting}
To maintain consistency and security, the `utils/lint-docker-compose` action validates all compose files across the infrastructure. It checks for:
- **Naming Standards**: Ensures project names and container names follow the `{node}-{project}` convention.
- **Security Context**: Flags containers running as `root` without a justified override.
- **Resource Constraints**: Identifies services lacking CPU or memory limits.
- **Label Standards**: Validates required labels for routing (e.g., [Traefik](https://traefik.io/)) and [CrowdSec](/root/concepts/security-model#crowdsec).
---
**See also:**
- [Concept: Infrastructure Principles](/root/concepts/principles)
- [Concept: Security & Privilege Isolation](/root/concepts/security-model)