Initial commit after Claude implementation
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(ls -la /home/iroddis/dev/sovereign/.*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**Sovereign** is an Ansible project that deploys a complete self-hosted infrastructure stack for small businesses using Docker and Docker Compose on a single Linux host.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Services
|
||||||
|
|
||||||
|
| Role | Tool | Subdomain |
|
||||||
|
|------|------|-----------|
|
||||||
|
| common | Traefik (reverse proxy + TLS) | `traefik.<domain>` |
|
||||||
|
| graylog | Graylog + OpenSearch + MongoDB | `logs.<domain>` |
|
||||||
|
| authentik | Authentik (identity provider) | `auth.<domain>` |
|
||||||
|
| minio | MinIO (object storage) | `s3.<domain>`, `minio.<domain>` |
|
||||||
|
| nextcloud | Nextcloud + MariaDB + Redis | `cloud.<domain>` |
|
||||||
|
| stalwart | Stalwart Mail (SMTP/IMAP) | `mail.<domain>` |
|
||||||
|
| roundcube | Roundcube (webmail) | `webmail.<domain>` |
|
||||||
|
| matrix | Synapse + Element | `matrix.<domain>`, `chat.<domain>` |
|
||||||
|
| jitsi | Jitsi Meet | `meet.<domain>` |
|
||||||
|
| headscale | Headscale (WireGuard mesh VPN) | `headscale.<domain>` |
|
||||||
|
| wazuh | Wazuh Manager + Indexer + Dashboard | `wazuh.<domain>` |
|
||||||
|
| vaultwarden | Vaultwarden + PostgreSQL | `vault.<domain>` |
|
||||||
|
| forgejo | Forgejo + PostgreSQL | `git.<domain>` |
|
||||||
|
|
||||||
|
### Design Principles
|
||||||
|
|
||||||
|
- **Single authentication**: All services authenticate via Authentik OIDC/OAuth2
|
||||||
|
- **Single config per deployment**: All variables live in `inventories/production/group_vars/all.yml`
|
||||||
|
- **Centralized logging**: Every container ships logs via GELF UDP to Graylog (`graylog_host:12201`)
|
||||||
|
- **Networking**: All services share an external Docker network named `sovereign` for Traefik routing; each service has its own `internal` network for db/cache isolation
|
||||||
|
- **Deployment order**: `site.yml` deploys Graylog first (logging), then Authentik (auth), then all other services
|
||||||
|
|
||||||
|
### Tenant Configuration
|
||||||
|
|
||||||
|
All deployment variables are in one place: `inventories/production/group_vars/all.yml`. For a new tenant/deployment, copy this file and update `base_domain`, passwords, and secrets. All service subdomains derive from `base_domain`.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
sovereign/
|
||||||
|
├── ansible.cfg
|
||||||
|
├── requirements.yml # Ansible Galaxy collections
|
||||||
|
├── inventories/
|
||||||
|
│ └── production/
|
||||||
|
│ ├── hosts.yml
|
||||||
|
│ └── group_vars/
|
||||||
|
│ └── all.yml # ← single tenant config file
|
||||||
|
├── playbooks/
|
||||||
|
│ └── site.yml
|
||||||
|
└── roles/
|
||||||
|
└── <service>/
|
||||||
|
├── defaults/main.yml
|
||||||
|
├── handlers/main.yml
|
||||||
|
├── tasks/main.yml
|
||||||
|
└── templates/
|
||||||
|
├── docker-compose.yml.j2
|
||||||
|
└── ... # service-specific configs
|
||||||
|
```
|
||||||
|
|
||||||
|
Each role deploys its Docker Compose stack to `/opt/sovereign/<service>/` on the target host.
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install required Ansible collections
|
||||||
|
ansible-galaxy collection install -r requirements.yml
|
||||||
|
|
||||||
|
# Run a full deployment
|
||||||
|
ansible-playbook playbooks/site.yml
|
||||||
|
|
||||||
|
# Deploy a single service
|
||||||
|
ansible-playbook playbooks/site.yml --tags authentik
|
||||||
|
|
||||||
|
# Dry run
|
||||||
|
ansible-playbook playbooks/site.yml --check --diff
|
||||||
|
|
||||||
|
# Syntax check
|
||||||
|
ansible-playbook playbooks/site.yml --syntax-check
|
||||||
|
|
||||||
|
# Lint
|
||||||
|
ansible-lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment variables for inventory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export SOVEREIGN_HOST=your-server-ip
|
||||||
|
export SOVEREIGN_USER=ubuntu
|
||||||
|
export SOVEREIGN_SSH_KEY=~/.ssh/id_rsa
|
||||||
|
```
|
||||||
|
|
||||||
|
## Initial Setup Notes
|
||||||
|
|
||||||
|
Before first deployment, update `inventories/production/group_vars/all.yml`:
|
||||||
|
1. Set `base_domain`
|
||||||
|
2. Replace all `changeme_*` passwords and secrets with secure values
|
||||||
|
3. Generate `graylog_root_password_sha2`: `echo -n yourpassword | sha256sum`
|
||||||
|
4. Create Authentik OIDC applications for each service that uses SSO (MinIO, Headscale, Vaultwarden, Forgejo) and fill in the `changeme_*_oidc_secret` placeholders in the respective compose templates
|
||||||
|
5. Wazuh requires TLS certificates — see Wazuh Docker documentation for generating certs before first run
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Sovereign
|
||||||
|
|
||||||
|
Sovereign is an ansible project that deploys a complete sovereign data solution for a small business using
|
||||||
|
docker and docker compose. The tools used are:
|
||||||
|
|
||||||
|
- Identity: Authentik
|
||||||
|
- E-mail: Stalwart Mail + Roundcube/SOGo
|
||||||
|
- Endpoint Management: Wazuh
|
||||||
|
- Remote Access: WireGuard / Headscale
|
||||||
|
- Collaboration (chat): Matrix/Element
|
||||||
|
- Collaboration (video): Jitsi Meet
|
||||||
|
- Online documents, fileshare, office suite, and calendar: Nextcloud + MinIO
|
||||||
|
- Password Management: Vaultwarden
|
||||||
|
- Software version control: Forgejo
|
||||||
|
- Centralized Logging: Graylog
|
||||||
|
|
||||||
|
Some common requirements:
|
||||||
|
|
||||||
|
- All solutions should use Authentik for login and authorization.
|
||||||
|
- Variables for the installation should be defined in a single file per tenant / deployment.
|
||||||
|
- Logs should be centrally captured in Graylog
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
[defaults]
|
||||||
|
inventory = inventories/production
|
||||||
|
roles_path = roles
|
||||||
|
retry_files_enabled = False
|
||||||
|
host_key_checking = False
|
||||||
|
stdout_callback = yaml
|
||||||
|
callbacks_enabled = timer, profile_tasks
|
||||||
|
|
||||||
|
[ssh_connection]
|
||||||
|
pipelining = True
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
---
|
||||||
|
# =============================================================================
|
||||||
|
# SOVEREIGN DEPLOYMENT CONFIGURATION
|
||||||
|
# All variables for this deployment are defined here.
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Base domain - all services are subdomains of this
|
||||||
|
base_domain: "example.com"
|
||||||
|
|
||||||
|
# Base directory for all service data
|
||||||
|
sovereign_base_dir: /opt/sovereign
|
||||||
|
|
||||||
|
# Traefik
|
||||||
|
traefik_acme_email: "admin@{{ base_domain }}"
|
||||||
|
traefik_domain: "traefik.{{ base_domain }}"
|
||||||
|
traefik_dashboard_password: "changeme" # htpasswd hash
|
||||||
|
|
||||||
|
# Authentik
|
||||||
|
authentik_domain: "auth.{{ base_domain }}"
|
||||||
|
authentik_version: "2024.10.5"
|
||||||
|
authentik_secret_key: "change-me-to-a-50-char-random-string"
|
||||||
|
authentik_db_password: "changeme_authentik_db"
|
||||||
|
authentik_admin_email: "admin@{{ base_domain }}"
|
||||||
|
authentik_admin_password: "changeme_admin"
|
||||||
|
|
||||||
|
# Graylog
|
||||||
|
graylog_domain: "logs.{{ base_domain }}"
|
||||||
|
graylog_version: "6.0"
|
||||||
|
graylog_password_secret: "changeme_graylog_secret_min_16_chars" # min 16 chars
|
||||||
|
graylog_root_password_sha2: "changeme_sha256_of_password" # echo -n yourpassword | sha256sum
|
||||||
|
graylog_host: "127.0.0.1" # host IP reachable from containers
|
||||||
|
graylog_gelf_port: 12201
|
||||||
|
|
||||||
|
# Stalwart Mail
|
||||||
|
stalwart_domain: "mail.{{ base_domain }}"
|
||||||
|
stalwart_admin_password: "changeme_mail_admin"
|
||||||
|
stalwart_version: "latest"
|
||||||
|
|
||||||
|
# Roundcube
|
||||||
|
roundcube_domain: "webmail.{{ base_domain }}"
|
||||||
|
roundcube_version: "latest"
|
||||||
|
roundcube_db_password: "changeme_roundcube_db"
|
||||||
|
roundcube_des_key: "changeme_24_char_des_key____"
|
||||||
|
|
||||||
|
# Wazuh
|
||||||
|
wazuh_domain: "wazuh.{{ base_domain }}"
|
||||||
|
wazuh_version: "4.9.0"
|
||||||
|
wazuh_admin_password: "changeme_wazuh_admin"
|
||||||
|
wazuh_api_password: "changeme_wazuh_api"
|
||||||
|
|
||||||
|
# WireGuard / Headscale
|
||||||
|
wireguard_domain: "vpn.{{ base_domain }}"
|
||||||
|
headscale_domain: "headscale.{{ base_domain }}"
|
||||||
|
headscale_version: "0.23.0"
|
||||||
|
wireguard_port: 51820
|
||||||
|
headscale_noise_private_key: "" # generated on first run
|
||||||
|
|
||||||
|
# Matrix / Element
|
||||||
|
matrix_domain: "matrix.{{ base_domain }}"
|
||||||
|
element_domain: "chat.{{ base_domain }}"
|
||||||
|
matrix_version: "v1.118.0"
|
||||||
|
matrix_registration_secret: "changeme_registration_secret"
|
||||||
|
matrix_db_password: "changeme_matrix_db"
|
||||||
|
|
||||||
|
# Jitsi
|
||||||
|
jitsi_domain: "meet.{{ base_domain }}"
|
||||||
|
jitsi_version: "stable-9753"
|
||||||
|
jitsi_jicofo_auth_password: "changeme_jicofo"
|
||||||
|
jitsi_jvb_auth_password: "changeme_jvb"
|
||||||
|
jitsi_jibri_recorder_password: "changeme_jibri_recorder"
|
||||||
|
jitsi_jibri_xmpp_password: "changeme_jibri_xmpp"
|
||||||
|
jitsi_turn_secret: "changeme_turn"
|
||||||
|
|
||||||
|
# MinIO
|
||||||
|
minio_domain: "s3.{{ base_domain }}"
|
||||||
|
minio_console_domain: "minio.{{ base_domain }}"
|
||||||
|
minio_version: "latest"
|
||||||
|
minio_root_user: "minioadmin"
|
||||||
|
minio_root_password: "changeme_minio"
|
||||||
|
minio_nextcloud_bucket: "nextcloud"
|
||||||
|
minio_nextcloud_access_key: "nextcloud"
|
||||||
|
minio_nextcloud_secret_key: "changeme_nextcloud_s3"
|
||||||
|
|
||||||
|
# Nextcloud
|
||||||
|
nextcloud_domain: "cloud.{{ base_domain }}"
|
||||||
|
nextcloud_version: "29"
|
||||||
|
nextcloud_admin_user: "admin"
|
||||||
|
nextcloud_admin_password: "changeme_nextcloud"
|
||||||
|
nextcloud_db_password: "changeme_nextcloud_db"
|
||||||
|
nextcloud_db_root_password: "changeme_nextcloud_db_root"
|
||||||
|
|
||||||
|
# Vaultwarden
|
||||||
|
vaultwarden_domain: "vault.{{ base_domain }}"
|
||||||
|
vaultwarden_version: "latest"
|
||||||
|
vaultwarden_admin_token: "changeme_vaultwarden_admin_token"
|
||||||
|
vaultwarden_db_password: "changeme_vaultwarden_db"
|
||||||
|
|
||||||
|
# Forgejo
|
||||||
|
forgejo_domain: "git.{{ base_domain }}"
|
||||||
|
forgejo_version: "latest"
|
||||||
|
forgejo_db_password: "changeme_forgejo_db"
|
||||||
|
forgejo_secret_key: "changeme_forgejo_secret"
|
||||||
|
forgejo_internal_token: "changeme_forgejo_internal_token"
|
||||||
|
forgejo_lfs_jwt_secret: "changeme_forgejo_lfs_jwt"
|
||||||
|
forgejo_admin_user: "admin"
|
||||||
|
forgejo_admin_password: "changeme_forgejo_admin"
|
||||||
|
forgejo_admin_email: "admin@{{ base_domain }}"
|
||||||
|
forgejo_ssh_port: 2222
|
||||||
|
|
||||||
|
# SMTP (for services that send email)
|
||||||
|
smtp_host: "stalwart"
|
||||||
|
smtp_port: 587
|
||||||
|
smtp_from: "noreply@{{ base_domain }}"
|
||||||
|
smtp_user: "noreply@{{ base_domain }}"
|
||||||
|
smtp_password: "changeme_smtp"
|
||||||
|
smtp_tls: "starttls"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
sovereign:
|
||||||
|
ansible_host: "{{ lookup('env', 'SOVEREIGN_HOST') | default('your-server-ip') }}"
|
||||||
|
ansible_user: "{{ lookup('env', 'SOVEREIGN_USER') | default('ubuntu') }}"
|
||||||
|
ansible_ssh_private_key_file: "{{ lookup('env', 'SOVEREIGN_SSH_KEY') | default('~/.ssh/id_rsa') }}"
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Sovereign infrastructure
|
||||||
|
hosts: sovereign
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- role: common
|
||||||
|
tags: [common, traefik]
|
||||||
|
- role: graylog
|
||||||
|
tags: [graylog, logging]
|
||||||
|
- role: authentik
|
||||||
|
tags: [authentik, auth, identity]
|
||||||
|
- role: minio
|
||||||
|
tags: [minio, storage]
|
||||||
|
- role: nextcloud
|
||||||
|
tags: [nextcloud, files, cloud]
|
||||||
|
- role: stalwart
|
||||||
|
tags: [stalwart, mail, email]
|
||||||
|
- role: roundcube
|
||||||
|
tags: [roundcube, webmail, email]
|
||||||
|
- role: matrix
|
||||||
|
tags: [matrix, chat, element]
|
||||||
|
- role: jitsi
|
||||||
|
tags: [jitsi, video, meet]
|
||||||
|
- role: headscale
|
||||||
|
tags: [headscale, vpn, wireguard]
|
||||||
|
- role: wazuh
|
||||||
|
tags: [wazuh, endpoint, security]
|
||||||
|
- role: vaultwarden
|
||||||
|
tags: [vaultwarden, passwords, vault]
|
||||||
|
- role: forgejo
|
||||||
|
tags: [forgejo, git, vcs]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
collections:
|
||||||
|
- name: community.docker
|
||||||
|
version: ">=3.0.0"
|
||||||
|
- name: community.general
|
||||||
|
version: ">=8.0.0"
|
||||||
|
- name: ansible.posix
|
||||||
|
version: ">=1.5.0"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
authentik_data_dir: "{{ sovereign_base_dir }}/authentik"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart authentik
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ authentik_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
- name: Create Authentik directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ authentik_data_dir }}"
|
||||||
|
- "{{ authentik_data_dir }}/media"
|
||||||
|
- "{{ authentik_data_dir }}/custom-templates"
|
||||||
|
- "{{ authentik_data_dir }}/certs"
|
||||||
|
- "{{ authentik_data_dir }}/postgres"
|
||||||
|
|
||||||
|
- name: Deploy Authentik docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ authentik_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart authentik
|
||||||
|
|
||||||
|
- name: Start Authentik
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ authentik_data_dir }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Wait for Authentik to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:9001/-/health/ready/"
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
register: result
|
||||||
|
until: result.status == 200
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
services:
|
||||||
|
authentik-postgresql:
|
||||||
|
image: docker.io/library/postgres:16-alpine
|
||||||
|
container_name: authentik-postgresql
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: "{{ authentik_db_password }}"
|
||||||
|
POSTGRES_USER: authentik
|
||||||
|
POSTGRES_DB: authentik
|
||||||
|
volumes:
|
||||||
|
- {{ authentik_data_dir }}/postgres:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "authentik-postgresql"
|
||||||
|
|
||||||
|
authentik-redis:
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
container_name: authentik-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "authentik-redis"
|
||||||
|
|
||||||
|
authentik-server:
|
||||||
|
image: ghcr.io/goauthentik/server:{{ authentik_version }}
|
||||||
|
container_name: authentik-server
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: authentik-postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: "{{ authentik_db_password }}"
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
|
AUTHENTIK_SECRET_KEY: "{{ authentik_secret_key }}"
|
||||||
|
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
|
||||||
|
AUTHENTIK_EMAIL__HOST: "{{ smtp_host }}"
|
||||||
|
AUTHENTIK_EMAIL__PORT: "{{ smtp_port }}"
|
||||||
|
AUTHENTIK_EMAIL__USERNAME: "{{ smtp_user }}"
|
||||||
|
AUTHENTIK_EMAIL__PASSWORD: "{{ smtp_password }}"
|
||||||
|
AUTHENTIK_EMAIL__FROM: "{{ smtp_from }}"
|
||||||
|
AUTHENTIK_EMAIL__USE_TLS: "true"
|
||||||
|
volumes:
|
||||||
|
- {{ authentik_data_dir }}/media:/media
|
||||||
|
- {{ authentik_data_dir }}/custom-templates:/templates
|
||||||
|
- {{ authentik_data_dir }}/certs:/certs
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9001:9000"
|
||||||
|
depends_on:
|
||||||
|
- authentik-postgresql
|
||||||
|
- authentik-redis
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.authentik.rule=Host(`{{ authentik_domain }}`)"
|
||||||
|
- "traefik.http.routers.authentik.tls=true"
|
||||||
|
- "traefik.http.routers.authentik.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "authentik-server"
|
||||||
|
|
||||||
|
authentik-worker:
|
||||||
|
image: ghcr.io/goauthentik/server:{{ authentik_version }}
|
||||||
|
container_name: authentik-worker
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_REDIS__HOST: authentik-redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: authentik-postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: "{{ authentik_db_password }}"
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
|
AUTHENTIK_SECRET_KEY: "{{ authentik_secret_key }}"
|
||||||
|
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
|
||||||
|
volumes:
|
||||||
|
- {{ authentik_data_dir }}/media:/media
|
||||||
|
- {{ authentik_data_dir }}/certs:/certs
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
depends_on:
|
||||||
|
- authentik-postgresql
|
||||||
|
- authentik-redis
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "authentik-worker"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
sovereign_network_name: sovereign
|
||||||
|
traefik_version: "v3.1"
|
||||||
|
traefik_data_dir: "{{ sovereign_base_dir }}/traefik"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart traefik
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ traefik_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
- name: Install required packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- apt-transport-https
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- gnupg
|
||||||
|
- lsb-release
|
||||||
|
- python3-pip
|
||||||
|
- python3-docker
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Add Docker GPG key
|
||||||
|
ansible.builtin.apt_key:
|
||||||
|
url: https://download.docker.com/linux/ubuntu/gpg
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Add Docker repository
|
||||||
|
ansible.builtin.apt_repository:
|
||||||
|
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Install Docker
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- docker-ce
|
||||||
|
- docker-ce-cli
|
||||||
|
- containerd.io
|
||||||
|
- docker-compose-plugin
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Enable and start Docker
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: docker
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- name: Create sovereign Docker network
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: "{{ sovereign_network_name }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create Traefik data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ traefik_data_dir }}"
|
||||||
|
- "{{ traefik_data_dir }}/config"
|
||||||
|
|
||||||
|
- name: Create acme.json for Let's Encrypt
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ traefik_data_dir }}/acme.json"
|
||||||
|
state: touch
|
||||||
|
mode: '0600'
|
||||||
|
|
||||||
|
- name: Deploy Traefik docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ traefik_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart traefik
|
||||||
|
|
||||||
|
- name: Start Traefik
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ traefik_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:{{ traefik_version }}
|
||||||
|
container_name: traefik
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- "--api.dashboard=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--providers.docker.network={{ sovereign_network_name }}"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||||
|
- "--entrypoints.websecure.address=:443"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.email={{ traefik_acme_email }}"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
|
||||||
|
- "--log.level=INFO"
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- {{ traefik_data_dir }}/acme.json:/acme.json
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.rule=Host(`{{ traefik_domain }}`)"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.tls=true"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.service=api@internal"
|
||||||
|
- "traefik.http.routers.traefik-dashboard.middlewares=traefik-auth"
|
||||||
|
- "traefik.http.middlewares.traefik-auth.basicauth.users={{ traefik_dashboard_password }}"
|
||||||
|
- "traefik.http.middlewares.authentik.forwardauth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
|
||||||
|
- "traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true"
|
||||||
|
- "traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
|
||||||
|
networks:
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "traefik"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
forgejo_data_dir: "{{ sovereign_base_dir }}/forgejo"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart forgejo
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ forgejo_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
- name: Create Forgejo directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ forgejo_data_dir }}"
|
||||||
|
- "{{ forgejo_data_dir }}/data"
|
||||||
|
- "{{ forgejo_data_dir }}/config"
|
||||||
|
|
||||||
|
- name: Deploy Forgejo docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ forgejo_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart forgejo
|
||||||
|
|
||||||
|
- name: Start Forgejo
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ forgejo_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
services:
|
||||||
|
forgejo-db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: forgejo-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: forgejo
|
||||||
|
POSTGRES_USER: forgejo
|
||||||
|
POSTGRES_PASSWORD: "{{ forgejo_db_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ forgejo_data_dir }}/db:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "forgejo-db"
|
||||||
|
|
||||||
|
forgejo:
|
||||||
|
image: codeberg.org/forgejo/forgejo:{{ forgejo_version }}
|
||||||
|
container_name: forgejo
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- forgejo-db
|
||||||
|
environment:
|
||||||
|
USER_UID: 1000
|
||||||
|
USER_GID: 1000
|
||||||
|
FORGEJO__database__DB_TYPE: postgres
|
||||||
|
FORGEJO__database__HOST: forgejo-db:5432
|
||||||
|
FORGEJO__database__NAME: forgejo
|
||||||
|
FORGEJO__database__USER: forgejo
|
||||||
|
FORGEJO__database__PASSWD: "{{ forgejo_db_password }}"
|
||||||
|
FORGEJO__server__DOMAIN: "{{ forgejo_domain }}"
|
||||||
|
FORGEJO__server__ROOT_URL: "https://{{ forgejo_domain }}"
|
||||||
|
FORGEJO__server__SSH_DOMAIN: "{{ forgejo_domain }}"
|
||||||
|
FORGEJO__server__SSH_PORT: "{{ forgejo_ssh_port }}"
|
||||||
|
FORGEJO__server__SSH_LISTEN_PORT: 22
|
||||||
|
FORGEJO__security__SECRET_KEY: "{{ forgejo_secret_key }}"
|
||||||
|
FORGEJO__security__INTERNAL_TOKEN: "{{ forgejo_internal_token }}"
|
||||||
|
FORGEJO__lfs__JWT_SECRET: "{{ forgejo_lfs_jwt_secret }}"
|
||||||
|
FORGEJO__mailer__ENABLED: "true"
|
||||||
|
FORGEJO__mailer__SMTP_ADDR: "{{ smtp_host }}"
|
||||||
|
FORGEJO__mailer__SMTP_PORT: "{{ smtp_port }}"
|
||||||
|
FORGEJO__mailer__FROM: "{{ smtp_from }}"
|
||||||
|
FORGEJO__mailer__USER: "{{ smtp_user }}"
|
||||||
|
FORGEJO__mailer__PASSWD: "{{ smtp_password }}"
|
||||||
|
FORGEJO__openid__ENABLE_OPENID_SIGNIN: "true"
|
||||||
|
FORGEJO__openid__ENABLE_OPENID_SIGNUP: "false"
|
||||||
|
FORGEJO__oauth2_client__REGISTER_EMAIL_CONFIRM: "false"
|
||||||
|
FORGEJO__oauth2_client__ENABLE_AUTO_REGISTRATION: "true"
|
||||||
|
FORGEJO__log__LEVEL: warn
|
||||||
|
ports:
|
||||||
|
- "{{ forgejo_ssh_port }}:22"
|
||||||
|
volumes:
|
||||||
|
- {{ forgejo_data_dir }}/data:/data
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.forgejo.rule=Host(`{{ forgejo_domain }}`)"
|
||||||
|
- "traefik.http.routers.forgejo.tls=true"
|
||||||
|
- "traefik.http.routers.forgejo.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.forgejo.loadbalancer.server.port=3000"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "forgejo"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
graylog_data_dir: "{{ sovereign_base_dir }}/graylog"
|
||||||
|
opensearch_version: "2.15.0"
|
||||||
|
mongodb_version: "6.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart graylog
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ graylog_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
- name: Create Graylog directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ graylog_data_dir }}"
|
||||||
|
- "{{ graylog_data_dir }}/data"
|
||||||
|
- "{{ graylog_data_dir }}/config"
|
||||||
|
- "{{ graylog_data_dir }}/opensearch"
|
||||||
|
|
||||||
|
- name: Set OpenSearch data directory permissions
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ graylog_data_dir }}/opensearch"
|
||||||
|
owner: "1000"
|
||||||
|
group: "1000"
|
||||||
|
mode: '0775'
|
||||||
|
|
||||||
|
- name: Set vm.max_map_count for OpenSearch
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: vm.max_map_count
|
||||||
|
value: '262144'
|
||||||
|
state: present
|
||||||
|
sysctl_set: true
|
||||||
|
|
||||||
|
- name: Deploy Graylog docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ graylog_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart graylog
|
||||||
|
|
||||||
|
- name: Start Graylog
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ graylog_data_dir }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Wait for Graylog to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:9000/api/system/loglevel"
|
||||||
|
method: GET
|
||||||
|
user: admin
|
||||||
|
password: "{{ graylog_root_password_sha2 }}"
|
||||||
|
force_basic_auth: true
|
||||||
|
status_code: 200
|
||||||
|
register: result
|
||||||
|
until: result.status == 200
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:{{ mongodb_version }}
|
||||||
|
container_name: graylog-mongodb
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- {{ graylog_data_dir }}/data/mongodb:/data/db
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
opensearch:
|
||||||
|
image: opensearchproject/opensearch:{{ opensearch_version }}
|
||||||
|
container_name: graylog-opensearch
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
|
||||||
|
- "bootstrap.memory_lock=true"
|
||||||
|
- "discovery.type=single-node"
|
||||||
|
- "action.auto_create_index=false"
|
||||||
|
- "plugins.security.ssl.http.enabled=false"
|
||||||
|
- "plugins.security.disabled=true"
|
||||||
|
- "OPENSEARCH_INITIAL_ADMIN_PASSWORD=changeme_os_admin"
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
volumes:
|
||||||
|
- {{ graylog_data_dir }}/opensearch:/usr/share/opensearch/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
graylog:
|
||||||
|
image: graylog/graylog:{{ graylog_version }}
|
||||||
|
container_name: graylog
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- mongodb
|
||||||
|
- opensearch
|
||||||
|
environment:
|
||||||
|
GRAYLOG_NODE_ID_FILE: "/usr/share/graylog/data/config/node-id"
|
||||||
|
GRAYLOG_HTTP_BIND_ADDRESS: "0.0.0.0:9000"
|
||||||
|
GRAYLOG_ELASTICSEARCH_HOSTS: "http://opensearch:9200"
|
||||||
|
GRAYLOG_MONGODB_URI: "mongodb://mongodb:27017/graylog"
|
||||||
|
GRAYLOG_PASSWORD_SECRET: "{{ graylog_password_secret }}"
|
||||||
|
GRAYLOG_ROOT_PASSWORD_SHA2: "{{ graylog_root_password_sha2 }}"
|
||||||
|
GRAYLOG_HTTP_EXTERNAL_URI: "https://{{ graylog_domain }}/"
|
||||||
|
GRAYLOG_TRANSPORT_EMAIL_ENABLED: "true"
|
||||||
|
GRAYLOG_TRANSPORT_EMAIL_HOSTNAME: "{{ smtp_host }}"
|
||||||
|
GRAYLOG_TRANSPORT_EMAIL_PORT: "{{ smtp_port }}"
|
||||||
|
GRAYLOG_TRANSPORT_EMAIL_FROM_EMAIL: "{{ smtp_from }}"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9000:9000"
|
||||||
|
- "0.0.0.0:12201:12201/udp" # GELF UDP - must be accessible from all containers
|
||||||
|
volumes:
|
||||||
|
- {{ graylog_data_dir }}/data/graylog:/usr/share/graylog/data
|
||||||
|
- {{ graylog_data_dir }}/config:/usr/share/graylog/data/config
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.graylog.rule=Host(`{{ graylog_domain }}`)"
|
||||||
|
- "traefik.http.routers.graylog.tls=true"
|
||||||
|
- "traefik.http.routers.graylog.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.graylog.loadbalancer.server.port=9000"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
headscale_data_dir: "{{ sovereign_base_dir }}/headscale"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart headscale
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ headscale_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
- name: Create Headscale directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ headscale_data_dir }}"
|
||||||
|
- "{{ headscale_data_dir }}/config"
|
||||||
|
- "{{ headscale_data_dir }}/data"
|
||||||
|
|
||||||
|
- name: Deploy Headscale config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: headscale-config.yaml.j2
|
||||||
|
dest: "{{ headscale_data_dir }}/config/config.yaml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart headscale
|
||||||
|
|
||||||
|
- name: Deploy Headscale docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ headscale_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart headscale
|
||||||
|
|
||||||
|
- name: Start Headscale
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ headscale_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
headscale:
|
||||||
|
image: headscale/headscale:{{ headscale_version }}
|
||||||
|
container_name: headscale
|
||||||
|
restart: unless-stopped
|
||||||
|
command: serve
|
||||||
|
volumes:
|
||||||
|
- {{ headscale_data_dir }}/config:/etc/headscale
|
||||||
|
- {{ headscale_data_dir }}/data:/var/lib/headscale
|
||||||
|
ports:
|
||||||
|
- "{{ wireguard_port }}:{{ wireguard_port }}/udp"
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.headscale.rule=Host(`{{ headscale_domain }}`)"
|
||||||
|
- "traefik.http.routers.headscale.tls=true"
|
||||||
|
- "traefik.http.routers.headscale.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.headscale.loadbalancer.server.port=8080"
|
||||||
|
networks:
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "headscale"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
server_url: "https://{{ headscale_domain }}"
|
||||||
|
listen_addr: 0.0.0.0:8080
|
||||||
|
grpc_listen_addr: 0.0.0.0:50443
|
||||||
|
grpc_allow_insecure: false
|
||||||
|
|
||||||
|
private_key_path: /var/lib/headscale/private.key
|
||||||
|
noise:
|
||||||
|
private_key_path: /var/lib/headscale/noise_private.key
|
||||||
|
|
||||||
|
prefixes:
|
||||||
|
v6: fd7a:115c:a1e0::/48
|
||||||
|
v4: 100.64.0.0/10
|
||||||
|
allocation: sequential
|
||||||
|
|
||||||
|
derp:
|
||||||
|
server:
|
||||||
|
enabled: false
|
||||||
|
urls:
|
||||||
|
- https://controlplane.tailscale.com/derpmap/default
|
||||||
|
auto_update_enabled: true
|
||||||
|
update_frequency: 24h
|
||||||
|
|
||||||
|
disable_check_updates: true
|
||||||
|
ephemeral_node_inactivity_timeout: 30m
|
||||||
|
|
||||||
|
database:
|
||||||
|
type: sqlite
|
||||||
|
sqlite:
|
||||||
|
path: /var/lib/headscale/db.sqlite
|
||||||
|
|
||||||
|
log:
|
||||||
|
format: text
|
||||||
|
level: info
|
||||||
|
|
||||||
|
dns:
|
||||||
|
magic_dns: true
|
||||||
|
base_domain: "{{ base_domain }}"
|
||||||
|
nameservers:
|
||||||
|
global:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 8.8.8.8
|
||||||
|
|
||||||
|
oidc:
|
||||||
|
only_start_if_oidc_is_available: true
|
||||||
|
issuer: "https://{{ authentik_domain }}/application/o/headscale/"
|
||||||
|
client_id: "headscale"
|
||||||
|
client_secret: "changeme_headscale_oidc_secret"
|
||||||
|
scope: ["openid", "profile", "email"]
|
||||||
|
extra_params:
|
||||||
|
domain_hint: "{{ base_domain }}"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
jitsi_data_dir: "{{ sovereign_base_dir }}/jitsi"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart jitsi
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ jitsi_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
- name: Create Jitsi directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ jitsi_data_dir }}"
|
||||||
|
- "{{ jitsi_data_dir }}/web"
|
||||||
|
- "{{ jitsi_data_dir }}/prosody"
|
||||||
|
- "{{ jitsi_data_dir }}/jicofo"
|
||||||
|
- "{{ jitsi_data_dir }}/jvb"
|
||||||
|
|
||||||
|
- name: Deploy Jitsi docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ jitsi_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart jitsi
|
||||||
|
|
||||||
|
- name: Start Jitsi
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ jitsi_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
services:
|
||||||
|
jitsi-web:
|
||||||
|
image: jitsi/web:{{ jitsi_version }}
|
||||||
|
container_name: jitsi-web
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PUBLIC_URL: "https://{{ jitsi_domain }}"
|
||||||
|
XMPP_SERVER: jitsi-prosody
|
||||||
|
XMPP_DOMAIN: meet.jitsi
|
||||||
|
XMPP_AUTH_DOMAIN: auth.meet.jitsi
|
||||||
|
XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi
|
||||||
|
XMPP_MUC_DOMAIN: muc.meet.jitsi
|
||||||
|
XMPP_BOSH_URL_BASE: http://jitsi-prosody:5280
|
||||||
|
XMPP_RECORDER_DOMAIN: recorder.meet.jitsi
|
||||||
|
ENABLE_AUTH: 1
|
||||||
|
ENABLE_GUESTS: 1
|
||||||
|
AUTH_TYPE: jwt
|
||||||
|
JWT_APP_ID: "jitsi"
|
||||||
|
JWT_APP_SECRET: "{{ jitsi_turn_secret }}"
|
||||||
|
TURN_CREDENTIALS: "{{ jitsi_turn_secret }}"
|
||||||
|
LETSENCRYPT_DOMAIN: "{{ jitsi_domain }}"
|
||||||
|
TZ: UTC
|
||||||
|
volumes:
|
||||||
|
- {{ jitsi_data_dir }}/web:/config
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.jitsi.rule=Host(`{{ jitsi_domain }}`)"
|
||||||
|
- "traefik.http.routers.jitsi.tls=true"
|
||||||
|
- "traefik.http.routers.jitsi.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.jitsi.loadbalancer.server.port=80"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "jitsi-web"
|
||||||
|
|
||||||
|
jitsi-prosody:
|
||||||
|
image: jitsi/prosody:{{ jitsi_version }}
|
||||||
|
container_name: jitsi-prosody
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
XMPP_DOMAIN: meet.jitsi
|
||||||
|
XMPP_AUTH_DOMAIN: auth.meet.jitsi
|
||||||
|
XMPP_MUC_DOMAIN: muc.meet.jitsi
|
||||||
|
XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi
|
||||||
|
XMPP_RECORDER_DOMAIN: recorder.meet.jitsi
|
||||||
|
JICOFO_AUTH_USER: focus
|
||||||
|
JICOFO_AUTH_PASSWORD: "{{ jitsi_jicofo_auth_password }}"
|
||||||
|
JVB_AUTH_USER: jvb
|
||||||
|
JVB_AUTH_PASSWORD: "{{ jitsi_jvb_auth_password }}"
|
||||||
|
JIBRI_RECORDER_USER: recorder
|
||||||
|
JIBRI_RECORDER_PASSWORD: "{{ jitsi_jibri_recorder_password }}"
|
||||||
|
JIBRI_XMPP_USER: jibri
|
||||||
|
JIBRI_XMPP_PASSWORD: "{{ jitsi_jibri_xmpp_password }}"
|
||||||
|
JWT_APP_ID: "jitsi"
|
||||||
|
JWT_APP_SECRET: "{{ jitsi_turn_secret }}"
|
||||||
|
ENABLE_AUTH: 1
|
||||||
|
ENABLE_GUESTS: 1
|
||||||
|
AUTH_TYPE: jwt
|
||||||
|
TZ: UTC
|
||||||
|
volumes:
|
||||||
|
- {{ jitsi_data_dir }}/prosody:/config
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "jitsi-prosody"
|
||||||
|
|
||||||
|
jitsi-jicofo:
|
||||||
|
image: jitsi/jicofo:{{ jitsi_version }}
|
||||||
|
container_name: jitsi-jicofo
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- jitsi-prosody
|
||||||
|
environment:
|
||||||
|
XMPP_SERVER: jitsi-prosody
|
||||||
|
XMPP_DOMAIN: meet.jitsi
|
||||||
|
XMPP_AUTH_DOMAIN: auth.meet.jitsi
|
||||||
|
XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi
|
||||||
|
JICOFO_AUTH_USER: focus
|
||||||
|
JICOFO_AUTH_PASSWORD: "{{ jitsi_jicofo_auth_password }}"
|
||||||
|
JVB_BREWERY_MUC: jvbbrewery
|
||||||
|
TZ: UTC
|
||||||
|
volumes:
|
||||||
|
- {{ jitsi_data_dir }}/jicofo:/config
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "jitsi-jicofo"
|
||||||
|
|
||||||
|
jitsi-jvb:
|
||||||
|
image: jitsi/jvb:{{ jitsi_version }}
|
||||||
|
container_name: jitsi-jvb
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- jitsi-prosody
|
||||||
|
environment:
|
||||||
|
XMPP_SERVER: jitsi-prosody
|
||||||
|
XMPP_DOMAIN: meet.jitsi
|
||||||
|
XMPP_AUTH_DOMAIN: auth.meet.jitsi
|
||||||
|
XMPP_INTERNAL_MUC_DOMAIN: internal-muc.meet.jitsi
|
||||||
|
JVB_AUTH_USER: jvb
|
||||||
|
JVB_AUTH_PASSWORD: "{{ jitsi_jvb_auth_password }}"
|
||||||
|
JVB_BREWERY_MUC: jvbbrewery
|
||||||
|
JVB_PORT: 10000
|
||||||
|
JVB_TCP_HARVESTER_DISABLED: "true"
|
||||||
|
TZ: UTC
|
||||||
|
ports:
|
||||||
|
- "10000:10000/udp"
|
||||||
|
volumes:
|
||||||
|
- {{ jitsi_data_dir }}/jvb:/config
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "jitsi-jvb"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
matrix_data_dir: "{{ sovereign_base_dir }}/matrix"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart matrix
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ matrix_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
- name: Create Matrix directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ matrix_data_dir }}"
|
||||||
|
- "{{ matrix_data_dir }}/synapse"
|
||||||
|
- "{{ matrix_data_dir }}/element"
|
||||||
|
|
||||||
|
- name: Generate Synapse config if not present
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: >
|
||||||
|
docker run --rm
|
||||||
|
-v {{ matrix_data_dir }}/synapse:/data
|
||||||
|
-e SYNAPSE_SERVER_NAME={{ matrix_domain }}
|
||||||
|
-e SYNAPSE_REPORT_STATS=no
|
||||||
|
ghcr.io/element-hq/synapse:{{ matrix_version }}
|
||||||
|
generate
|
||||||
|
creates: "{{ matrix_data_dir }}/synapse/homeserver.yaml"
|
||||||
|
|
||||||
|
- name: Deploy Element config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: element-config.json.j2
|
||||||
|
dest: "{{ matrix_data_dir }}/element/config.json"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Deploy Matrix docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ matrix_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart matrix
|
||||||
|
|
||||||
|
- name: Start Matrix
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ matrix_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
services:
|
||||||
|
matrix-db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: matrix-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: synapse
|
||||||
|
POSTGRES_PASSWORD: "{{ matrix_db_password }}"
|
||||||
|
POSTGRES_DB: synapse
|
||||||
|
POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
|
||||||
|
volumes:
|
||||||
|
- {{ matrix_data_dir }}/db:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "matrix-db"
|
||||||
|
|
||||||
|
synapse:
|
||||||
|
image: ghcr.io/element-hq/synapse:{{ matrix_version }}
|
||||||
|
container_name: synapse
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- matrix-db
|
||||||
|
environment:
|
||||||
|
SYNAPSE_CONFIG_PATH: /data/homeserver.yaml
|
||||||
|
volumes:
|
||||||
|
- {{ matrix_data_dir }}/synapse:/data
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.matrix.rule=Host(`{{ matrix_domain }}`)"
|
||||||
|
- "traefik.http.routers.matrix.tls=true"
|
||||||
|
- "traefik.http.routers.matrix.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.matrix.loadbalancer.server.port=8008"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "synapse"
|
||||||
|
|
||||||
|
element:
|
||||||
|
image: vectorim/element-web:latest
|
||||||
|
container_name: element
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- {{ matrix_data_dir }}/element/config.json:/app/config.json:ro
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.element.rule=Host(`{{ element_domain }}`)"
|
||||||
|
- "traefik.http.routers.element.tls=true"
|
||||||
|
- "traefik.http.routers.element.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.element.loadbalancer.server.port=80"
|
||||||
|
networks:
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "element"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"default_server_config": {
|
||||||
|
"m.homeserver": {
|
||||||
|
"base_url": "https://{{ matrix_domain }}",
|
||||||
|
"server_name": "{{ matrix_domain }}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"brand": "Element",
|
||||||
|
"integrations_ui_url": "https://scalar.vector.im/",
|
||||||
|
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||||
|
"bug_report_endpoint_url": "",
|
||||||
|
"default_country_code": "US",
|
||||||
|
"show_labs_settings": false,
|
||||||
|
"features": {},
|
||||||
|
"default_federate": true,
|
||||||
|
"default_theme": "light",
|
||||||
|
"room_directory": {
|
||||||
|
"servers": ["{{ matrix_domain }}"]
|
||||||
|
},
|
||||||
|
"enable_presence_by_hs_url": {
|
||||||
|
"https://{{ matrix_domain }}": false
|
||||||
|
},
|
||||||
|
"setting_defaults": {
|
||||||
|
"breadcrumbs": true
|
||||||
|
},
|
||||||
|
"jitsi": {
|
||||||
|
"preferred_domain": "{{ jitsi_domain }}"
|
||||||
|
},
|
||||||
|
"sso_redirect_options": {
|
||||||
|
"immediate": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
minio_data_dir: "{{ sovereign_base_dir }}/minio"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart minio
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ minio_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
- name: Create MinIO directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ minio_data_dir }}"
|
||||||
|
- "{{ minio_data_dir }}/data"
|
||||||
|
|
||||||
|
- name: Deploy MinIO docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ minio_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart minio
|
||||||
|
|
||||||
|
- name: Start MinIO
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ minio_data_dir }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Wait for MinIO to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:9010/minio/health/live"
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
register: result
|
||||||
|
until: result.status == 200
|
||||||
|
retries: 15
|
||||||
|
delay: 5
|
||||||
|
|
||||||
|
- name: Create Nextcloud bucket in MinIO
|
||||||
|
community.general.minio:
|
||||||
|
endpoint: "http://localhost:9010"
|
||||||
|
access_key: "{{ minio_root_user }}"
|
||||||
|
secret_key: "{{ minio_root_password }}"
|
||||||
|
name: "{{ minio_nextcloud_bucket }}"
|
||||||
|
state: present
|
||||||
|
ignore_errors: true
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: quay.io/minio/minio:{{ minio_version }}
|
||||||
|
container_name: minio
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: "{{ minio_root_user }}"
|
||||||
|
MINIO_ROOT_PASSWORD: "{{ minio_root_password }}"
|
||||||
|
MINIO_BROWSER_REDIRECT_URL: "https://{{ minio_console_domain }}"
|
||||||
|
MINIO_IDENTITY_OPENID_CONFIG_URL: "https://{{ authentik_domain }}/application/o/minio/.well-known/openid-configuration"
|
||||||
|
MINIO_IDENTITY_OPENID_CLIENT_ID: "minio"
|
||||||
|
MINIO_IDENTITY_OPENID_CLIENT_SECRET: "changeme_minio_oidc_secret"
|
||||||
|
MINIO_IDENTITY_OPENID_CLAIM_NAME: "policy"
|
||||||
|
MINIO_IDENTITY_OPENID_REDIRECT_URI: "https://{{ minio_console_domain }}/oauth_callback"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:9010:9000"
|
||||||
|
volumes:
|
||||||
|
- {{ minio_data_dir }}/data:/data
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.minio-api.rule=Host(`{{ minio_domain }}`)"
|
||||||
|
- "traefik.http.routers.minio-api.tls=true"
|
||||||
|
- "traefik.http.routers.minio-api.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.minio-api.service=minio-api"
|
||||||
|
- "traefik.http.services.minio-api.loadbalancer.server.port=9000"
|
||||||
|
- "traefik.http.routers.minio-console.rule=Host(`{{ minio_console_domain }}`)"
|
||||||
|
- "traefik.http.routers.minio-console.tls=true"
|
||||||
|
- "traefik.http.routers.minio-console.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.minio-console.service=minio-console"
|
||||||
|
- "traefik.http.services.minio-console.loadbalancer.server.port=9001"
|
||||||
|
networks:
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "minio"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
nextcloud_data_dir: "{{ sovereign_base_dir }}/nextcloud"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart nextcloud
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ nextcloud_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
- name: Create Nextcloud directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ nextcloud_data_dir }}"
|
||||||
|
- "{{ nextcloud_data_dir }}/data"
|
||||||
|
|
||||||
|
- name: Deploy Nextcloud docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ nextcloud_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart nextcloud
|
||||||
|
|
||||||
|
- name: Start Nextcloud
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ nextcloud_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
services:
|
||||||
|
nextcloud-db:
|
||||||
|
image: mariadb:10.11
|
||||||
|
container_name: nextcloud-db
|
||||||
|
restart: unless-stopped
|
||||||
|
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: "{{ nextcloud_db_root_password }}"
|
||||||
|
MYSQL_DATABASE: nextcloud
|
||||||
|
MYSQL_USER: nextcloud
|
||||||
|
MYSQL_PASSWORD: "{{ nextcloud_db_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ nextcloud_data_dir }}/db:/var/lib/mysql
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "nextcloud-db"
|
||||||
|
|
||||||
|
nextcloud-redis:
|
||||||
|
image: redis:alpine
|
||||||
|
container_name: nextcloud-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
nextcloud:
|
||||||
|
image: nextcloud:{{ nextcloud_version }}
|
||||||
|
container_name: nextcloud
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- nextcloud-db
|
||||||
|
- nextcloud-redis
|
||||||
|
environment:
|
||||||
|
MYSQL_HOST: nextcloud-db
|
||||||
|
MYSQL_DATABASE: nextcloud
|
||||||
|
MYSQL_USER: nextcloud
|
||||||
|
MYSQL_PASSWORD: "{{ nextcloud_db_password }}"
|
||||||
|
REDIS_HOST: nextcloud-redis
|
||||||
|
NEXTCLOUD_ADMIN_USER: "{{ nextcloud_admin_user }}"
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD: "{{ nextcloud_admin_password }}"
|
||||||
|
NEXTCLOUD_TRUSTED_DOMAINS: "{{ nextcloud_domain }}"
|
||||||
|
OVERWRITEPROTOCOL: https
|
||||||
|
OVERWRITECLIURL: "https://{{ nextcloud_domain }}"
|
||||||
|
SMTP_HOST: "{{ smtp_host }}"
|
||||||
|
SMTP_PORT: "{{ smtp_port }}"
|
||||||
|
SMTP_NAME: "{{ smtp_user }}"
|
||||||
|
SMTP_PASSWORD: "{{ smtp_password }}"
|
||||||
|
MAIL_FROM_ADDRESS: "noreply"
|
||||||
|
MAIL_DOMAIN: "{{ base_domain }}"
|
||||||
|
OBJECTSTORE_S3_HOST: minio
|
||||||
|
OBJECTSTORE_S3_PORT: 9000
|
||||||
|
OBJECTSTORE_S3_SSL: "false"
|
||||||
|
OBJECTSTORE_S3_BUCKET: "{{ minio_nextcloud_bucket }}"
|
||||||
|
OBJECTSTORE_S3_KEY: "{{ minio_nextcloud_access_key }}"
|
||||||
|
OBJECTSTORE_S3_SECRET: "{{ minio_nextcloud_secret_key }}"
|
||||||
|
OBJECTSTORE_S3_USEPATH_STYLE: "true"
|
||||||
|
volumes:
|
||||||
|
- {{ nextcloud_data_dir }}/data:/var/www/html
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.nextcloud.rule=Host(`{{ nextcloud_domain }}`)"
|
||||||
|
- "traefik.http.routers.nextcloud.tls=true"
|
||||||
|
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||||
|
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.permanent=true"
|
||||||
|
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.regex=https://(.*)/.well-known/(?:card|cal)dav"
|
||||||
|
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.replacement=https://$${1}/remote.php/dav"
|
||||||
|
- "traefik.http.routers.nextcloud.middlewares=nextcloud-redirect"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "nextcloud"
|
||||||
|
|
||||||
|
nextcloud-cron:
|
||||||
|
image: nextcloud:{{ nextcloud_version }}
|
||||||
|
container_name: nextcloud-cron
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- {{ nextcloud_data_dir }}/data:/var/www/html
|
||||||
|
entrypoint: /cron.sh
|
||||||
|
depends_on:
|
||||||
|
- nextcloud-db
|
||||||
|
- nextcloud-redis
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
roundcube_data_dir: "{{ sovereign_base_dir }}/roundcube"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart roundcube
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ roundcube_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
- name: Create Roundcube directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ roundcube_data_dir }}"
|
||||||
|
|
||||||
|
- name: Deploy Roundcube docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ roundcube_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart roundcube
|
||||||
|
|
||||||
|
- name: Start Roundcube
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ roundcube_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
services:
|
||||||
|
roundcube-db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: roundcube-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: roundcube
|
||||||
|
POSTGRES_USER: roundcube
|
||||||
|
POSTGRES_PASSWORD: "{{ roundcube_db_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ roundcube_data_dir }}/db:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "roundcube-db"
|
||||||
|
|
||||||
|
roundcube:
|
||||||
|
image: roundcube/roundcubemail:{{ roundcube_version }}
|
||||||
|
container_name: roundcube
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- roundcube-db
|
||||||
|
environment:
|
||||||
|
ROUNDCUBEMAIL_DB_TYPE: pgsql
|
||||||
|
ROUNDCUBEMAIL_DB_HOST: roundcube-db
|
||||||
|
ROUNDCUBEMAIL_DB_NAME: roundcube
|
||||||
|
ROUNDCUBEMAIL_DB_USER: roundcube
|
||||||
|
ROUNDCUBEMAIL_DB_PASSWORD: "{{ roundcube_db_password }}"
|
||||||
|
ROUNDCUBEMAIL_DEFAULT_HOST: "ssl://stalwart"
|
||||||
|
ROUNDCUBEMAIL_DEFAULT_PORT: 993
|
||||||
|
ROUNDCUBEMAIL_SMTP_SERVER: "tls://stalwart"
|
||||||
|
ROUNDCUBEMAIL_SMTP_PORT: 587
|
||||||
|
ROUNDCUBEMAIL_DES_KEY: "{{ roundcube_des_key }}"
|
||||||
|
ROUNDCUBEMAIL_PLUGINS: "archive,zipdownload,managesieve,jqueryui"
|
||||||
|
ROUNDCUBEMAIL_SKIN: elastic
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.roundcube.rule=Host(`{{ roundcube_domain }}`)"
|
||||||
|
- "traefik.http.routers.roundcube.tls=true"
|
||||||
|
- "traefik.http.routers.roundcube.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.roundcube.loadbalancer.server.port=80"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "roundcube"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
stalwart_data_dir: "{{ sovereign_base_dir }}/stalwart"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart stalwart
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ stalwart_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
- name: Create Stalwart directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ stalwart_data_dir }}"
|
||||||
|
- "{{ stalwart_data_dir }}/data"
|
||||||
|
|
||||||
|
- name: Deploy Stalwart docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ stalwart_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart stalwart
|
||||||
|
|
||||||
|
- name: Start Stalwart
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ stalwart_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
services:
|
||||||
|
stalwart:
|
||||||
|
image: stalwartlabs/mail-server:{{ stalwart_version }}
|
||||||
|
container_name: stalwart
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- {{ stalwart_data_dir }}/data:/opt/stalwart-mail
|
||||||
|
ports:
|
||||||
|
- "25:25" # SMTP
|
||||||
|
- "465:465" # SMTPS
|
||||||
|
- "587:587" # SMTP submission
|
||||||
|
- "993:993" # IMAPS
|
||||||
|
- "4190:4190" # ManageSieve
|
||||||
|
environment:
|
||||||
|
TZ: UTC
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.stalwart.rule=Host(`{{ stalwart_domain }}`)"
|
||||||
|
- "traefik.http.routers.stalwart.tls=true"
|
||||||
|
- "traefik.http.routers.stalwart.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.stalwart.loadbalancer.server.port=8080"
|
||||||
|
networks:
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "stalwart"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
vaultwarden_data_dir: "{{ sovereign_base_dir }}/vaultwarden"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart vaultwarden
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ vaultwarden_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
- name: Create Vaultwarden directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ vaultwarden_data_dir }}"
|
||||||
|
- "{{ vaultwarden_data_dir }}/data"
|
||||||
|
|
||||||
|
- name: Deploy Vaultwarden docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ vaultwarden_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart vaultwarden
|
||||||
|
|
||||||
|
- name: Start Vaultwarden
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ vaultwarden_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
services:
|
||||||
|
vaultwarden-db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: vaultwarden-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: vaultwarden
|
||||||
|
POSTGRES_USER: vaultwarden
|
||||||
|
POSTGRES_PASSWORD: "{{ vaultwarden_db_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ vaultwarden_data_dir }}/db:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "vaultwarden-db"
|
||||||
|
|
||||||
|
vaultwarden:
|
||||||
|
image: vaultwarden/server:{{ vaultwarden_version }}
|
||||||
|
container_name: vaultwarden
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- vaultwarden-db
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: "postgresql://vaultwarden:{{ vaultwarden_db_password }}@vaultwarden-db/vaultwarden"
|
||||||
|
ADMIN_TOKEN: "{{ vaultwarden_admin_token }}"
|
||||||
|
DOMAIN: "https://{{ vaultwarden_domain }}"
|
||||||
|
SMTP_HOST: "{{ smtp_host }}"
|
||||||
|
SMTP_FROM: "{{ smtp_from }}"
|
||||||
|
SMTP_PORT: "{{ smtp_port }}"
|
||||||
|
SMTP_SECURITY: "{{ smtp_tls }}"
|
||||||
|
SMTP_USERNAME: "{{ smtp_user }}"
|
||||||
|
SMTP_PASSWORD: "{{ smtp_password }}"
|
||||||
|
SIGNUPS_ALLOWED: "false"
|
||||||
|
SSO_ENABLED: "true"
|
||||||
|
SSO_ONLY: "false"
|
||||||
|
SSO_AUTHORITY: "https://{{ authentik_domain }}/application/o/vaultwarden/"
|
||||||
|
SSO_CLIENT_ID: "vaultwarden"
|
||||||
|
SSO_CLIENT_SECRET: "changeme_vaultwarden_oidc_secret"
|
||||||
|
LOG_LEVEL: warn
|
||||||
|
volumes:
|
||||||
|
- {{ vaultwarden_data_dir }}/data:/data
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.vaultwarden.rule=Host(`{{ vaultwarden_domain }}`)"
|
||||||
|
- "traefik.http.routers.vaultwarden.tls=true"
|
||||||
|
- "traefik.http.routers.vaultwarden.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "vaultwarden"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
wazuh_data_dir: "{{ sovereign_base_dir }}/wazuh"
|
||||||
|
wazuh_indexer_memory: "512m"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: restart wazuh
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ wazuh_data_dir }}"
|
||||||
|
state: present
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
- name: Create Wazuh directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- "{{ wazuh_data_dir }}"
|
||||||
|
- "{{ wazuh_data_dir }}/config"
|
||||||
|
|
||||||
|
- name: Set vm.max_map_count for Wazuh indexer (OpenSearch)
|
||||||
|
ansible.posix.sysctl:
|
||||||
|
name: vm.max_map_count
|
||||||
|
value: '262144'
|
||||||
|
state: present
|
||||||
|
sysctl_set: true
|
||||||
|
|
||||||
|
- name: Deploy Wazuh docker-compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ wazuh_data_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart wazuh
|
||||||
|
|
||||||
|
- name: Start Wazuh
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ wazuh_data_dir }}"
|
||||||
|
state: present
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
services:
|
||||||
|
wazuh-manager:
|
||||||
|
image: wazuh/wazuh-manager:{{ wazuh_version }}
|
||||||
|
container_name: wazuh-manager
|
||||||
|
restart: unless-stopped
|
||||||
|
hostname: wazuh.manager
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
nofile:
|
||||||
|
soft: 655360
|
||||||
|
hard: 655360
|
||||||
|
environment:
|
||||||
|
INDEXER_URL: "https://wazuh-indexer:9200"
|
||||||
|
INDEXER_USERNAME: admin
|
||||||
|
INDEXER_PASSWORD: "{{ wazuh_admin_password }}"
|
||||||
|
FILEBEAT_SSL_VERIFICATION_MODE: full
|
||||||
|
SSL_CERTIFICATE_AUTHORITIES: /etc/ssl/root-ca.pem
|
||||||
|
SSL_CERTIFICATE: /etc/ssl/filebeat.pem
|
||||||
|
SSL_KEY: /etc/ssl/filebeat.key
|
||||||
|
API_USERNAME: wazuh-wui
|
||||||
|
API_PASSWORD: "{{ wazuh_api_password }}"
|
||||||
|
ports:
|
||||||
|
- "1514:1514"
|
||||||
|
- "1515:1515"
|
||||||
|
- "514:514/udp"
|
||||||
|
- "55000:55000"
|
||||||
|
volumes:
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-manager-master:/var/ossec/data
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
|
||||||
|
- {{ wazuh_data_dir }}/config:/wazuh-config-mount/etc
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "wazuh-manager"
|
||||||
|
|
||||||
|
wazuh-indexer:
|
||||||
|
image: wazuh/wazuh-indexer:{{ wazuh_version }}
|
||||||
|
container_name: wazuh-indexer
|
||||||
|
restart: unless-stopped
|
||||||
|
hostname: wazuh-indexer
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
nofile:
|
||||||
|
soft: 65536
|
||||||
|
hard: 65536
|
||||||
|
environment:
|
||||||
|
OPENSEARCH_JAVA_OPTS: "-Xms{{ wazuh_indexer_memory }} -Xmx{{ wazuh_indexer_memory }}"
|
||||||
|
volumes:
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-data:/var/lib/wazuh-indexer
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
wazuh-dashboard:
|
||||||
|
image: wazuh/wazuh-dashboard:{{ wazuh_version }}
|
||||||
|
container_name: wazuh-dashboard
|
||||||
|
restart: unless-stopped
|
||||||
|
hostname: wazuh-dashboard
|
||||||
|
depends_on:
|
||||||
|
- wazuh-indexer
|
||||||
|
environment:
|
||||||
|
INDEXER_USERNAME: admin
|
||||||
|
INDEXER_PASSWORD: "{{ wazuh_admin_password }}"
|
||||||
|
WAZUH_API_URL: https://wazuh-manager
|
||||||
|
DASHBOARD_USERNAME: kibanaserver
|
||||||
|
DASHBOARD_PASSWORD: "{{ wazuh_admin_password }}"
|
||||||
|
API_USERNAME: wazuh-wui
|
||||||
|
API_PASSWORD: "{{ wazuh_api_password }}"
|
||||||
|
volumes:
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
|
||||||
|
- {{ wazuh_data_dir }}/wazuh-indexer-certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.wazuh.rule=Host(`{{ wazuh_domain }}`)"
|
||||||
|
- "traefik.http.routers.wazuh.tls=true"
|
||||||
|
- "traefik.http.routers.wazuh.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.wazuh.loadbalancer.server.port=5601"
|
||||||
|
- "traefik.http.services.wazuh.loadbalancer.server.scheme=https"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- {{ sovereign_network_name }}
|
||||||
|
logging:
|
||||||
|
driver: gelf
|
||||||
|
options:
|
||||||
|
gelf-address: "udp://{{ graylog_host }}:{{ graylog_gelf_port }}"
|
||||||
|
tag: "wazuh-dashboard"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
{{ sovereign_network_name }}:
|
||||||
|
external: true
|
||||||
Reference in New Issue
Block a user