Updating README
This commit is contained in:
@@ -21,6 +21,7 @@ Sovereign is an Ansible project that deploys a complete self-hosted infrastructu
|
|||||||
| Role | Service | URL |
|
| Role | Service | URL |
|
||||||
|------|---------|-----|
|
|------|---------|-----|
|
||||||
| `common` | Traefik (reverse proxy + TLS) | `traefik.<domain>` |
|
| `common` | Traefik (reverse proxy + TLS) | `traefik.<domain>` |
|
||||||
|
| `dns` | BIND9 (authoritative nameserver) | `ns1.<domain>` |
|
||||||
| `graylog` | Graylog + OpenSearch + MongoDB | `logs.<domain>` |
|
| `graylog` | Graylog + OpenSearch + MongoDB | `logs.<domain>` |
|
||||||
| `authentik` | Authentik (identity provider) | `auth.<domain>` |
|
| `authentik` | Authentik (identity provider) | `auth.<domain>` |
|
||||||
| `minio` | MinIO (object storage) | `s3.<domain>`, `minio.<domain>` |
|
| `minio` | MinIO (object storage) | `s3.<domain>`, `minio.<domain>` |
|
||||||
@@ -49,8 +50,8 @@ Sovereign is an Ansible project that deploys a complete self-hosted infrastructu
|
|||||||
|
|
||||||
- Ubuntu 22.04 or 24.04 (amd64)
|
- Ubuntu 22.04 or 24.04 (amd64)
|
||||||
- Root or sudo access
|
- Root or sudo access
|
||||||
- Ports 80, 443, and 51820/UDP open
|
- Ports 80, 443, 51820/UDP, and 53/TCP+UDP open
|
||||||
- DNS A records pointing `<domain>` and `*.<domain>` to the host IP
|
- Domain registered with a registrar that supports custom nameservers and glue records
|
||||||
|
|
||||||
### Installing Dependencies
|
### Installing Dependencies
|
||||||
|
|
||||||
@@ -77,14 +78,13 @@ git clone <repo-url> sovereign && cd sovereign
|
|||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
ansible-galaxy collection install -r requirements.yml
|
ansible-galaxy collection install -r requirements.yml
|
||||||
|
|
||||||
# 3. Configure the target host
|
# 3. Set the target host connection details
|
||||||
export SOVEREIGN_HOST=203.0.113.10
|
export SOVEREIGN_HOST=203.0.113.10
|
||||||
export SOVEREIGN_USER=ubuntu
|
export SOVEREIGN_USER=ubuntu
|
||||||
export SOVEREIGN_SSH_KEY=~/.ssh/id_rsa
|
export SOVEREIGN_SSH_KEY=~/.ssh/id_rsa
|
||||||
|
|
||||||
# 4. Edit the tenant config
|
# 4. Generate a complete, deployment-ready config
|
||||||
cp inventories/production/group_vars/all.yml inventories/production/group_vars/all.yml.bak
|
python3 configure.py
|
||||||
$EDITOR inventories/production/group_vars/all.yml
|
|
||||||
|
|
||||||
# 5. Deploy
|
# 5. Deploy
|
||||||
ansible-playbook playbooks/site.yml
|
ansible-playbook playbooks/site.yml
|
||||||
@@ -94,27 +94,48 @@ ansible-playbook playbooks/site.yml
|
|||||||
|
|
||||||
## New Tenant Setup
|
## New Tenant Setup
|
||||||
|
|
||||||
Each deployment is controlled entirely by `inventories/production/group_vars/all.yml`. Follow these steps for every new tenant.
|
Each deployment is controlled entirely by `inventories/production/group_vars/all.yml`. The recommended way to create this file for a new tenant is with the interactive configurator script.
|
||||||
|
|
||||||
### 1. Set the base domain
|
### Using the configurator (recommended)
|
||||||
|
|
||||||
```yaml
|
```bash
|
||||||
base_domain: "example.com"
|
python3 configure.py
|
||||||
```
|
```
|
||||||
|
|
||||||
All service subdomains are derived from this value automatically. DNS must have an A record for `example.com` and a wildcard `*.example.com` pointing to the server IP before deployment.
|
The script walks you through each configuration section, prompts for the handful of deployment-specific values (domain name, organisation name, server IP, admin email), and auto-generates every password and cryptographic secret using a cryptographically secure random source. It then writes a complete `group_vars/all.yml` with no `changeme_*` placeholders left, and prints a credential summary to the terminal.
|
||||||
|
|
||||||
### 2. Replace all secrets
|
You can also write to a custom path or pipe the YAML to stdout:
|
||||||
|
|
||||||
Search the config file for every `changeme_*` placeholder and replace with secure values. The sections below describe how to generate each one.
|
```bash
|
||||||
|
python3 configure.py -o /path/to/all.yml # custom output path
|
||||||
|
python3 configure.py --stdout > all.yml # print YAML; prompts go to stderr
|
||||||
|
just configure # shorthand via Justfile
|
||||||
|
just configure-to /path/to/all.yml
|
||||||
|
```
|
||||||
|
|
||||||
**General secrets** (use a password manager or `openssl rand -base64 32`):
|
The configurator prompts for the following values (all others take secure defaults):
|
||||||
|
|
||||||
|
| Prompt | Notes |
|
||||||
|
|--------|-------|
|
||||||
|
| Base domain | e.g. `acme.com` — required |
|
||||||
|
| Organisation name | Shown in service UIs |
|
||||||
|
| Admin email | Used for ACME/Let's Encrypt and initial admin accounts |
|
||||||
|
| Graylog host IP | IP reachable from Docker containers for GELF UDP |
|
||||||
|
| Server public IPv4 | Used to populate DNS A records |
|
||||||
|
| DMARC policy | `none`, `quarantine`, or `reject` |
|
||||||
|
| DKIM selector | Defaults to `default` |
|
||||||
|
|
||||||
|
All passwords, secret keys, database credentials, and signing tokens are generated automatically.
|
||||||
|
|
||||||
|
### Manual setup
|
||||||
|
|
||||||
|
If you prefer to configure the file by hand, copy `all.yml`, set `base_domain`, and replace every `changeme_*` placeholder with a secure value. Helper commands for generating specific values:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generic random secret
|
# Generic random secret
|
||||||
openssl rand -base64 32
|
openssl rand -base64 32
|
||||||
|
|
||||||
# Graylog password_secret (min 16 chars, recommend 64)
|
# Graylog password_secret (min 16 chars)
|
||||||
openssl rand -base64 48
|
openssl rand -base64 48
|
||||||
|
|
||||||
# Graylog root password hash
|
# Graylog root password hash
|
||||||
@@ -122,53 +143,48 @@ echo -n 'yourpassword' | sha256sum | awk '{print $1}'
|
|||||||
|
|
||||||
# Traefik dashboard password (htpasswd format)
|
# Traefik dashboard password (htpasswd format)
|
||||||
htpasswd -nb admin yourpassword
|
htpasswd -nb admin yourpassword
|
||||||
```
|
|
||||||
|
|
||||||
**Authentik secret key** — must be exactly 50 characters:
|
# Authentik secret key (exactly 50 characters)
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl rand -base64 37 | head -c 50
|
openssl rand -base64 37 | head -c 50
|
||||||
```
|
|
||||||
|
|
||||||
**Roundcube DES key** — must be exactly 24 characters:
|
# Roundcube DES key (exactly 24 characters)
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl rand -base64 18 | head -c 24
|
openssl rand -base64 18 | head -c 24
|
||||||
|
|
||||||
|
# Forgejo tokens (run 3× for secret_key, internal_token, lfs_jwt_secret)
|
||||||
|
openssl rand -hex 32
|
||||||
```
|
```
|
||||||
|
|
||||||
**Forgejo tokens** — generate three separate secrets:
|
### Post-deployment steps
|
||||||
|
|
||||||
```bash
|
These steps must be completed after the first `ansible-playbook` run regardless of whether you used the configurator or manual setup.
|
||||||
# forgejo_secret_key, forgejo_internal_token, forgejo_lfs_jwt_secret
|
|
||||||
for i in 1 2 3; do openssl rand -hex 32; done
|
|
||||||
```
|
|
||||||
|
|
||||||
**Vaultwarden admin token** — hash a password with argon2:
|
#### DNS — nameserver delegation
|
||||||
|
|
||||||
```bash
|
The `dns` role runs BIND9 as an authoritative nameserver for your domain. After deployment:
|
||||||
# Requires the vaultwarden container to be running, or use the web tool at
|
|
||||||
# https://argon2.online — use the token output directly
|
|
||||||
echo -n 'yourpassword' | argon2 "$(openssl rand -base64 32)" -id -t 3 -m 16 -p 4 -l 32 -e
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Configure SMTP
|
1. Register a **glue record** at your domain registrar: `ns1.<domain>` → your server's public IP.
|
||||||
|
2. Set your domain's **nameservers** to `ns1.<domain>`.
|
||||||
|
|
||||||
The `smtp_*` variables control outbound email for all services. The default routes through the bundled Stalwart mail server:
|
Once delegation propagates (typically minutes to hours), all service subdomains will resolve via BIND9 without needing individual A records at your registrar.
|
||||||
|
|
||||||
```yaml
|
#### DKIM — email signing key
|
||||||
smtp_host: "stalwart"
|
|
||||||
smtp_port: 587
|
|
||||||
smtp_from: "noreply@{{ base_domain }}"
|
|
||||||
smtp_user: "noreply@{{ base_domain }}"
|
|
||||||
smtp_password: "changeme_smtp"
|
|
||||||
smtp_tls: "starttls"
|
|
||||||
```
|
|
||||||
|
|
||||||
To use an external relay (SendGrid, Postmark, etc.), replace `smtp_host` with the relay hostname and update credentials accordingly.
|
Stalwart generates its DKIM signing key on first start. After Stalwart is running:
|
||||||
|
|
||||||
### 4. Create Authentik OIDC applications
|
1. Log in to the Stalwart admin UI at `https://mail.<domain>`.
|
||||||
|
2. Navigate to **Settings → DKIM keys** and copy the public key.
|
||||||
|
3. Add it to `all.yml`:
|
||||||
|
```yaml
|
||||||
|
stalwart_dkim_public_key: "MIGfMA0GCSqGSIb3DQEB..."
|
||||||
|
```
|
||||||
|
4. Re-run the DNS role to publish the TXT record:
|
||||||
|
```bash
|
||||||
|
ansible-playbook playbooks/site.yml --tags dns
|
||||||
|
```
|
||||||
|
|
||||||
After the first deployment, log into Authentik at `https://auth.<domain>` and create an OAuth2/OIDC provider and application for each service that integrates with SSO. Then fill in the `changeme_*_oidc_secret` placeholders in the relevant compose templates under `roles/<service>/templates/`.
|
#### Authentik OIDC applications
|
||||||
|
|
||||||
|
Log into Authentik at `https://auth.<domain>` and create an OAuth2/OIDC provider and application for each service that integrates with SSO. Then fill in the `changeme_*_oidc_secret` placeholders in the relevant compose templates under `roles/<service>/templates/`.
|
||||||
|
|
||||||
Services that require Authentik OIDC configuration:
|
Services that require Authentik OIDC configuration:
|
||||||
|
|
||||||
@@ -179,7 +195,7 @@ Services that require Authentik OIDC configuration:
|
|||||||
| Vaultwarden | `changeme_vaultwarden_oidc_secret` |
|
| Vaultwarden | `changeme_vaultwarden_oidc_secret` |
|
||||||
| Forgejo | `changeme_forgejo_oidc_secret` |
|
| Forgejo | `changeme_forgejo_oidc_secret` |
|
||||||
|
|
||||||
### 5. Wazuh TLS certificates
|
#### Wazuh TLS certificates
|
||||||
|
|
||||||
Wazuh requires TLS certificates between its manager, indexer, and dashboard components before the first run. Generate them using the Wazuh certificate tool:
|
Wazuh requires TLS certificates between its manager, indexer, and dashboard components before the first run. Generate them using the Wazuh certificate tool:
|
||||||
|
|
||||||
@@ -197,7 +213,7 @@ bash wazuh-certs-tool.sh -A
|
|||||||
|
|
||||||
Refer to the [Wazuh Docker documentation](https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html) for full details.
|
Refer to the [Wazuh Docker documentation](https://documentation.wazuh.com/current/deployment-options/docker/wazuh-container.html) for full details.
|
||||||
|
|
||||||
### 6. Static website content
|
#### Static website content
|
||||||
|
|
||||||
Place your static HTML/CSS/JS files in `/opt/sovereign/website/html/` on the target host. Nginx serves this directory at `https://<domain>`. The directory is created by the `website` role on first deployment — you can populate it before or after running the playbook.
|
Place your static HTML/CSS/JS files in `/opt/sovereign/website/html/` on the target host. Nginx serves this directory at `https://<domain>`. The directory is created by the `website` role on first deployment — you can populate it before or after running the playbook.
|
||||||
|
|
||||||
@@ -236,6 +252,31 @@ Services with branding support: Authentik (title, colour, logo via blueprint), E
|
|||||||
| `traefik_dashboard_password` | — | htpasswd-formatted credential for dashboard basic auth. |
|
| `traefik_dashboard_password` | — | htpasswd-formatted credential for dashboard basic auth. |
|
||||||
| `traefik_version` | `v3.1` | Traefik image tag. |
|
| `traefik_version` | `v3.1` | Traefik image tag. |
|
||||||
|
|
||||||
|
### DNS / BIND9
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `dns_server_ip` | — | Public IPv4 address of this server. Used for all service A records and the `ns1` glue record. |
|
||||||
|
| `dns_ns_hostname` | `ns1.<domain>` | Fully-qualified hostname of the nameserver. |
|
||||||
|
| `dns_ttl` | `3600` | Default TTL for zone records (seconds). |
|
||||||
|
| `bind_version` | `9.18-22.04_beta` | `ubuntu/bind9` image tag. |
|
||||||
|
| `stalwart_dkim_selector` | `default` | DKIM selector name. Must match the selector configured in Stalwart. |
|
||||||
|
| `stalwart_dkim_public_key` | `""` | RSA public key for DKIM signing. Retrieve from the Stalwart admin UI after first deployment. Leave empty to skip the DKIM TXT record. Long keys are automatically split into 255-byte chunks as required by RFC 4871. |
|
||||||
|
| `dmarc_policy` | `quarantine` | DMARC enforcement policy: `none`, `quarantine`, or `reject`. |
|
||||||
|
| `dmarc_rua` | `mailto:dmarc-reports@<domain>` | Address to receive aggregate DMARC reports. |
|
||||||
|
| `dmarc_ruf` | `mailto:dmarc-forensics@<domain>` | Address to receive forensic DMARC reports. |
|
||||||
|
|
||||||
|
The DNS role publishes the following records for `<domain>`:
|
||||||
|
|
||||||
|
| Type | Name | Value |
|
||||||
|
|------|------|-------|
|
||||||
|
| A | `ns1` | `dns_server_ip` |
|
||||||
|
| A | `@`, all service subdomains | `dns_server_ip` |
|
||||||
|
| MX | `@` | `mail.<domain>` (priority 10) |
|
||||||
|
| TXT | `@` | SPF: `v=spf1 mx ~all` |
|
||||||
|
| TXT | `_dmarc` | DMARC policy record |
|
||||||
|
| TXT | `<selector>._domainkey` | DKIM public key (when `stalwart_dkim_public_key` is set) |
|
||||||
|
|
||||||
### Graylog
|
### Graylog
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
@@ -345,7 +386,7 @@ Services with branding support: Authentik (title, colour, logo via blueprint), E
|
|||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `vaultwarden_domain` | `vault.<domain>` | Vaultwarden URL. |
|
| `vaultwarden_domain` | `vault.<domain>` | Vaultwarden URL. |
|
||||||
| `vaultwarden_version` | `latest` | Vaultwarden image tag. |
|
| `vaultwarden_version` | `latest` | Vaultwarden image tag. |
|
||||||
| `vaultwarden_admin_token` | — | Argon2-hashed token for the `/admin` panel. |
|
| `vaultwarden_admin_token` | — | Token for the `/admin` panel. |
|
||||||
| `vaultwarden_db_password` | — | PostgreSQL password for Vaultwarden's database. |
|
| `vaultwarden_db_password` | — | PostgreSQL password for Vaultwarden's database. |
|
||||||
|
|
||||||
### Forgejo
|
### Forgejo
|
||||||
@@ -355,9 +396,9 @@ Services with branding support: Authentik (title, colour, logo via blueprint), E
|
|||||||
| `forgejo_domain` | `git.<domain>` | Forgejo URL. |
|
| `forgejo_domain` | `git.<domain>` | Forgejo URL. |
|
||||||
| `forgejo_version` | `latest` | Forgejo image tag. |
|
| `forgejo_version` | `latest` | Forgejo image tag. |
|
||||||
| `forgejo_db_password` | — | PostgreSQL password for Forgejo's database. |
|
| `forgejo_db_password` | — | PostgreSQL password for Forgejo's database. |
|
||||||
| `forgejo_secret_key` | — | Random hex secret for internal signing. |
|
| `forgejo_secret_key` | — | Random secret for internal signing. |
|
||||||
| `forgejo_internal_token` | — | Random hex token for internal API calls. |
|
| `forgejo_internal_token` | — | Random token for internal API calls. |
|
||||||
| `forgejo_lfs_jwt_secret` | — | Random hex secret for Git LFS JWT tokens. |
|
| `forgejo_lfs_jwt_secret` | — | Random secret for Git LFS JWT tokens. |
|
||||||
| `forgejo_admin_user` | `admin` | Initial admin username. |
|
| `forgejo_admin_user` | `admin` | Initial admin username. |
|
||||||
| `forgejo_admin_password` | — | Initial admin password. |
|
| `forgejo_admin_password` | — | Initial admin password. |
|
||||||
| `forgejo_admin_email` | `admin@<domain>` | Initial admin email. |
|
| `forgejo_admin_email` | `admin@<domain>` | Initial admin email. |
|
||||||
@@ -380,7 +421,7 @@ These variables are consumed by every service that sends email.
|
|||||||
| `smtp_from` | `noreply@<domain>` | Default sender address. |
|
| `smtp_from` | `noreply@<domain>` | Default sender address. |
|
||||||
| `smtp_user` | `noreply@<domain>` | SMTP authentication username. |
|
| `smtp_user` | `noreply@<domain>` | SMTP authentication username. |
|
||||||
| `smtp_password` | — | SMTP authentication password. |
|
| `smtp_password` | — | SMTP authentication password. |
|
||||||
| `smtp_tls` | `starttls` | TLS mode: `starttls` or `tls`. |
|
| `smtp_tls` | `starttls` | TLS mode: `starttls`, `tls`, or `none`. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -402,19 +443,20 @@ export SOVEREIGN_SSH_KEY=~/.ssh/id_rsa
|
|||||||
ansible-playbook playbooks/site.yml
|
ansible-playbook playbooks/site.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
Services are deployed in dependency order: Graylog (logging) → Authentik (auth) → all other services.
|
Services are deployed in dependency order: common (Docker + Traefik) → DNS → Graylog (logging) → Authentik (auth) → all other services.
|
||||||
|
|
||||||
### Deploy a single service
|
### Deploy a single service
|
||||||
|
|
||||||
Use the role's tag to deploy only that service:
|
Use the role's tag to deploy only that service:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
ansible-playbook playbooks/site.yml --tags dns
|
||||||
ansible-playbook playbooks/site.yml --tags authentik
|
ansible-playbook playbooks/site.yml --tags authentik
|
||||||
ansible-playbook playbooks/site.yml --tags nextcloud
|
ansible-playbook playbooks/site.yml --tags nextcloud
|
||||||
ansible-playbook playbooks/site.yml --tags website
|
ansible-playbook playbooks/site.yml --tags website
|
||||||
```
|
```
|
||||||
|
|
||||||
Available tags: `common`, `graylog`, `authentik`, `minio`, `nextcloud`, `stalwart`, `roundcube`, `matrix`, `jitsi`, `headscale`, `wazuh`, `vaultwarden`, `forgejo`, `website`.
|
Available tags: `common`, `dns`, `graylog`, `authentik`, `minio`, `nextcloud`, `stalwart`, `roundcube`, `matrix`, `jitsi`, `headscale`, `wazuh`, `vaultwarden`, `forgejo`, `website`.
|
||||||
|
|
||||||
### Dry run
|
### Dry run
|
||||||
|
|
||||||
@@ -441,7 +483,7 @@ Each role has a [Molecule](https://ansible.readthedocs.io/projects/molecule/) te
|
|||||||
|
|
||||||
- **Directory creation** — all expected data directories are created with correct permissions.
|
- **Directory creation** — all expected data directories are created with correct permissions.
|
||||||
- **Template rendering** — every Jinja2 template renders without errors and with all variables substituted (no unresolved `{{ }}` in output files).
|
- **Template rendering** — every Jinja2 template renders without errors and with all variables substituted (no unresolved `{{ }}` in output files).
|
||||||
- **Config file content** — role-specific config files (Element `config.json`, Headscale `config.yaml`, Authentik branding blueprint, Roundcube `custom.inc.php`, Jitsi interface config, Wazuh dashboard YAML) contain the expected values.
|
- **Config file content** — role-specific config files (Element `config.json`, Headscale `config.yaml`, Authentik branding blueprint, Roundcube `custom.inc.php`, Jitsi interface config, Wazuh dashboard YAML, BIND9 `named.conf` and zone file) contain the expected values.
|
||||||
- **Docker Compose structure** — `docker-compose.yml` references the correct image, Traefik routing labels, GELF logging address, and external network declaration.
|
- **Docker Compose structure** — `docker-compose.yml` references the correct image, Traefik routing labels, GELF logging address, and external network declaration.
|
||||||
- **Idempotency** — Molecule re-runs each role after converge and asserts zero changed tasks.
|
- **Idempotency** — Molecule re-runs each role after converge and asserts zero changed tasks.
|
||||||
|
|
||||||
@@ -461,6 +503,13 @@ cd roles/authentik
|
|||||||
molecule test
|
molecule test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or using the Justfile shorthand:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just test-role authentik
|
||||||
|
just test-role dns
|
||||||
|
```
|
||||||
|
|
||||||
`molecule test` runs the full lifecycle: dependency → converge → idempotency check → verify → cleanup.
|
`molecule test` runs the full lifecycle: dependency → converge → idempotency check → verify → cleanup.
|
||||||
|
|
||||||
For a faster iteration loop during development:
|
For a faster iteration loop during development:
|
||||||
@@ -476,12 +525,11 @@ molecule destroy
|
|||||||
### Run tests for all roles
|
### Run tests for all roles
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
for role in roles/*/; do
|
just test
|
||||||
echo "=== Testing $role ==="
|
|
||||||
(cd "$role" && molecule test)
|
|
||||||
done
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This iterates over all roles and reports any failures at the end.
|
||||||
|
|
||||||
### Lint
|
### Lint
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -493,8 +541,8 @@ Both tools are configured via `.ansible-lint` and `.yamllint` at the repo root.
|
|||||||
|
|
||||||
### Adding tests for a new role
|
### Adding tests for a new role
|
||||||
|
|
||||||
1. Create `roles/<service>/molecule/default/` with `molecule.yml`, `converge.yml`, and `verify.yml` following the pattern of an existing simple role (e.g. `roles/website/molecule/default/`).
|
1. Create `roles/<service>/molecule/default/` with `molecule.yml`, `converge.yml`, and `verify.yml` following the pattern of an existing simple role (e.g. `roles/dns/molecule/default/`).
|
||||||
2. Add the new role's variables to `molecule/shared/vars.yml`.
|
2. Add the new role's variables to `roles/molecule/shared/vars.yml`.
|
||||||
3. Add `when: not (molecule_test_mode | default(false))` to any tasks that call `community.docker.docker_compose_v2`, `ansible.builtin.uri` (health checks), or `ansible.builtin.command` (docker exec).
|
3. Add `when: not (molecule_test_mode | default(false))` to any tasks that call `community.docker.docker_compose_v2`, `ansible.builtin.uri` (health checks), or `ansible.builtin.command` (docker exec).
|
||||||
4. Add the same guard to the role's restart handler in `handlers/main.yml`.
|
4. Add the same guard to the role's restart handler in `handlers/main.yml`.
|
||||||
|
|
||||||
@@ -583,6 +631,8 @@ Follow the pattern used by existing roles:
|
|||||||
|
|
||||||
- **Reverse proxy**: Traefik handles all inbound HTTPS traffic, terminates TLS using Let's Encrypt (TLS challenge), and routes to containers via Docker labels.
|
- **Reverse proxy**: Traefik handles all inbound HTTPS traffic, terminates TLS using Let's Encrypt (TLS challenge), and routes to containers via Docker labels.
|
||||||
- **Authentication**: The `authentik` Traefik forward-auth middleware is defined in the `common` role and can be applied to any router label: `traefik.http.routers.<name>.middlewares=authentik`.
|
- **Authentication**: The `authentik` Traefik forward-auth middleware is defined in the `common` role and can be applied to any router label: `traefik.http.routers.<name>.middlewares=authentik`.
|
||||||
|
- **DNS**: BIND9 runs as an authoritative-only nameserver (recursion disabled) on port 53/TCP+UDP. It publishes A records for every service subdomain, MX records pointing to Stalwart, and email authentication records (SPF, DMARC, DKIM). Users must register a glue record at their domain registrar and delegate the domain's nameservers to `ns1.<domain>` after deployment.
|
||||||
|
- **Email authentication**: SPF restricts sending to the MX host. DMARC policy is configurable (`none`/`quarantine`/`reject`). DKIM requires retrieving the public key from Stalwart after first deployment and re-running the `dns` role to publish it.
|
||||||
- **Networking**: All containers that need Traefik routing join the external `sovereign` Docker network. Services with databases also have a private `internal` network for backend isolation.
|
- **Networking**: All containers that need Traefik routing join the external `sovereign` Docker network. Services with databases also have a private `internal` network for backend isolation.
|
||||||
- **Logging**: Every container uses the `gelf` log driver pointed at `graylog_host:12201`. `graylog_host` should be an IP reachable from inside Docker containers (typically the host's IP on the Docker bridge, not `localhost`).
|
- **Logging**: Every container uses the `gelf` log driver pointed at `graylog_host:12201`. `graylog_host` should be an IP reachable from inside Docker containers (typically the host's IP on the Docker bridge, not `localhost`).
|
||||||
- **Data persistence**: Each service stores data under `{{ sovereign_base_dir }}/<service>/` (default `/opt/sovereign/<service>/`). This path is defined in each role's `defaults/main.yml` as `<service>_data_dir`.
|
- **Data persistence**: Each service stores data under `{{ sovereign_base_dir }}/<service>/` (default `/opt/sovereign/<service>/`). This path is defined in each role's `defaults/main.yml` as `<service>_data_dir`.
|
||||||
|
|||||||
Reference in New Issue
Block a user