diff --git a/ansible/inventory/group_vars/all.yaml b/ansible/inventory/group_vars/all.yaml
index 4c980b8..0c58a59 100644
--- a/ansible/inventory/group_vars/all.yaml
+++ b/ansible/inventory/group_vars/all.yaml
@@ -21,31 +21,62 @@ domain:
services:
crowdsec:
- domain: "crowdsec"
+ domain:
+ internal: "crowdsec"
ports:
https: "8080"
+ dependency:
+ cert: true
bind:
- domain: "bind"
+ domain:
+ internal: "bind"
ports:
dns: "53"
blocky:
- domain: "blocky"
+ domain:
+ internal: "blocky"
ports:
https: "443"
dns: "53"
+ dot: "853"
+ dependency:
+ cert: true
+ kopia:
+ domain:
+ internal: "kopia"
+ ports:
+ https: "51515"
+ dependency:
+ cert: true
postgresql:
- domain: "postgresql"
+ domain:
+ internal: "postgresql"
ports:
tcp: "5432" # postgresql db connection port
subuid: "100998"
+ dependency:
+ cert: true
ldap:
- domain: "ldap"
+ domain:
+ internal: "ldap"
ports:
http: "17170"
ldaps: "6360"
subuid: "100999"
+ dependency:
+ cert: true
+ web: "infra-internal"
+ db: "postgresql"
+ mail:
+ domain:
+ internal: "mail"
+ ports: ""
+ subuid: ""
+ dependency:
+ cert: true
ca:
- domain: "ca"
+ domain:
+ internal: "ca"
ports:
https: "9000"
subuid: "100999"
@@ -54,36 +85,43 @@ services:
http: "9793"
subuid: "165533"
prometheus:
- domain: "prometheus"
+ domain:
+ internal: "prometheus"
ports:
https: "9090"
subuid: "165533"
+ dependency:
+ cert: true
+ web: "infra-internal"
loki:
- domain: "loki"
+ domain:
+ internal: "loki"
ports:
https: "3100"
subuid: "110000"
+ dependency:
+ cert: true
grafana:
- domain: "grafana"
+ domain:
+ internal: "grafana"
ports:
http: "3000"
subuid: "100471"
+ dependency:
+ web: "infra-internal"
+ db: "postgresql"
caddy:
ports:
http: "2080"
https: "2443"
- nas:
- domain: "nas"
- ports:
- https: "5001"
- kopia:
- domain: "nas"
- ports:
- https: "51515"
authelia:
- domain: "authelia"
+ domain:
+ public: "authelia"
ports:
http: "9091"
+ dependency:
+ web: "auth-public"
+ db: "postgresql"
redis:
subuid: "100998"
vaultwarden:
@@ -92,6 +130,9 @@ services:
internal: "vault.app"
ports:
http: "8000"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
gitea:
domain:
public: "gitea"
@@ -99,6 +140,9 @@ services:
ports:
http: "3001"
subuid: "100999"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
immich:
domain:
public: "immich"
@@ -106,6 +150,9 @@ services:
ports:
http: "2283"
redis: "6379"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
immich-ml:
ports:
http: "3003"
@@ -117,6 +164,9 @@ services:
http: "8001"
redis: "6380"
subuid: "100999"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
nextcloud:
domain:
public: "nextcloud"
@@ -125,6 +175,9 @@ services:
http: "8002"
redis: "6382"
subuid: "100032"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
collabora:
domain:
public: "collabora"
@@ -132,6 +185,8 @@ services:
ports:
http: "9980"
subuid: "101000"
+ dependency:
+ web: "app-public"
sure:
domain:
public: "sure"
@@ -140,6 +195,9 @@ services:
http: "3002"
redis: "6383"
subuid: "100999"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
outline:
domain:
public: "outline"
@@ -148,6 +206,9 @@ services:
http: "3004"
redis: "6384"
subuid: "101000"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
memos:
domain:
public: "memos"
@@ -155,6 +216,9 @@ services:
ports:
http: "3005"
subuid: "110000"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
mealie:
domain:
public: "mealie"
@@ -162,6 +226,18 @@ services:
ports:
http: "9001"
subuid: "100910"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
+ homebox:
+ domain:
+ public: "homebox"
+ internal: "homebox.app"
+ ports:
+ http: "7745"
+ dependency:
+ web: "app-public"
+ db: "postgresql"
version:
packages:
@@ -194,8 +270,9 @@ version:
immich: "v2.7.5"
paperless: "2.20.15"
nextcloud: "33.0.5"
- collabora: "25.04.10.3.1"
+ collabora: "26.04.1.4.1"
sure: "0.7.1"
outline: "1.8.1"
memos: "0.29.1"
mealie: "v3.19.2"
+ homebox: "0.26.2"
diff --git a/ansible/inventory/group_vars/hypervisor.yaml b/ansible/inventory/group_vars/hypervisor.yaml
index 3cafb42..19783e4 100644
--- a/ansible/inventory/group_vars/hypervisor.yaml
+++ b/ansible/inventory/group_vars/hypervisor.yaml
@@ -21,13 +21,40 @@ hardware:
bus: "0x00"
slot: "0x02"
function: "0x0"
- hdd:
+ disk:
data:
- hdd0: "WMC6N0E617S8"
- hdd1: "P6HVTL0W"
- hdd2: "P2GH354H"
- hdd3: "P6GJKSMP"
- btrfs:
- label: "DATA"
- level: "raid10"
- mount_point: "{{ node['libvirt_path'] }}/data"
+ serials:
+ - "WMC6N0E617S8"
+ - "P6HVTL0W"
+ - "P2GH354H"
+ - "P6GJKSMP"
+ fs:
+ type: "btrfs"
+ label: "DATA"
+ mount_point: "{{ node['libvirt_path'] }}/disk/data"
+ mount_opts:
+ - "defaults"
+ - "noatime"
+ - "nodatacow"
+ - "degraded"
+ - "nofail"
+ btrfs:
+ data_profile: "raid10"
+ metadata_profile: "raid10"
+ min_devices: 4
+ backup:
+ serials:
+ - "6261S5G4S75H"
+ fs:
+ type: "btrfs"
+ label: "BACKUP"
+ mount_point: "{{ node['libvirt_path'] }}/disk/backup"
+ mount_opts:
+ - "defaults"
+ - "noatime"
+ - "nodatacow"
+ - "nofail"
+ btrfs:
+ data_profile: "single"
+ metadata_profile: "dup"
+ min_devices: 1
diff --git a/ansible/inventory/host_vars/app.yaml b/ansible/inventory/host_vars/app.yaml
index fd5e841..9fb4c48 100644
--- a/ansible/inventory/host_vars/app.yaml
+++ b/ansible/inventory/host_vars/app.yaml
@@ -24,17 +24,8 @@ vm:
storage: 256
data_storage:
name: "vdb"
+ pool: "data"
size: 3.5
lan_mac: "0a:49:6e:4d:03:00"
lan_net: "lan-net"
lan_group: "vlan10-access"
- # PCIe passthrough address
- # result of `lspci | grep -i -e "sata controller" -e "vga"` and parse it.
- # Ex) 04:00.0 > domain: "0x0000", bus: "0x04", slot: "0x00", function: "0x0"
- pass_through:
- igpu:
- address: "0000:00:02.0"
- domain: "0x0000"
- bus: "0x00"
- slot: "0x02"
- function: "0x0"
diff --git a/ansible/inventory/host_vars/auth.yaml b/ansible/inventory/host_vars/auth.yaml
index bbf70f6..50abbff 100644
--- a/ansible/inventory/host_vars/auth.yaml
+++ b/ansible/inventory/host_vars/auth.yaml
@@ -12,12 +12,12 @@ vm:
name: "auth"
cpu: 2
cpu_pin: |
-
-
-
+
+
+
shares: 1024
memory: 2
- storage: 64
+ storage: 32
lan_mac: "0a:49:6e:4d:02:00"
lan_net: "lan-net"
lan_group: "vlan10-access"
diff --git a/ansible/inventory/host_vars/bk.yaml b/ansible/inventory/host_vars/bk.yaml
new file mode 100644
index 0000000..624fc94
--- /dev/null
+++ b/ansible/inventory/host_vars/bk.yaml
@@ -0,0 +1,27 @@
+---
+# Node Factors
+node:
+ name: "bk"
+ group: "svadmins"
+ uid: 2009
+ home_path: "/home/bk"
+ ssh_san: "{{ node['name'] }},{{ node['name'] }}.{{ domain['internal'] }}"
+ local_san: "localhost {{ node['name'] }}.{{ domain['internal'] }}"
+# VM Factors
+vm:
+ name: "bk"
+ cpu: 2
+ cpu_pin: |
+
+
+
+ shares: 512
+ memory: 2
+ storage: 32
+ data_storage:
+ name: "vdb"
+ pool: "backup"
+ size: 3.5
+ lan_mac: "0a:49:6e:4d:09:00"
+ lan_net: "lan-net"
+ lan_group: "vlan10-access"
diff --git a/ansible/inventory/host_vars/console.yaml b/ansible/inventory/host_vars/console.yaml
index f94b01e..7b32ec9 100644
--- a/ansible/inventory/host_vars/console.yaml
+++ b/ansible/inventory/host_vars/console.yaml
@@ -21,6 +21,6 @@ node:
data_path: "{{ node['homelab_path'] }}/data"
config_path: "{{ node['homelab_path'] }}/config"
ssh_san: "{{ node['name'] }},{{ node['name'] }}.{{ domain['internal'] }}"
- ssh_users: "vmm,fw,infra,auth,app"
+ ssh_users: "vmm,fw,bk,infra,auth,app"
# add the hostname of wsl, it is needed to improve the sudo problem
local_san: "localhost {{ node['name'] }} {{ node['name'] }}.{{ domain['internal'] }}"
diff --git a/ansible/inventory/host_vars/fw.yaml b/ansible/inventory/host_vars/fw.yaml
index 690c7f6..a5284a6 100644
--- a/ansible/inventory/host_vars/fw.yaml
+++ b/ansible/inventory/host_vars/fw.yaml
@@ -52,6 +52,8 @@ network4:
vmm:
client: "192.168.1.10"
server: "192.168.10.10"
+ bk:
+ server: "192.168.10.9"
infra:
server: "192.168.10.11"
auth:
@@ -60,8 +62,6 @@ network4:
server: "192.168.10.13"
switch:
client: "192.168.1.2"
- nas:
- client: "192.168.1.11"
printer:
client: "192.168.1.101"
@@ -85,18 +85,14 @@ network6:
vmm:
client: "fd00:1::10"
server: "fd00:10::10"
+ bk:
+ server: "fd00:10::9"
infra:
server: "fd00:10::11"
auth:
server: "fd00:10::12"
app:
server: "fd00:10::13"
- switch:
- client: "fd00:1::2"
- nas:
- client: "fd00:1::11"
- printer:
- client: "fd00:1::101"
# Suricata Factors
# suricata_home_net: '[10.0.0.0/8,172.16.0.0/12,192.168.0.0/16]'
diff --git a/ansible/inventory/host_vars/infra.yaml b/ansible/inventory/host_vars/infra.yaml
index 2d9961a..98b9aba 100644
--- a/ansible/inventory/host_vars/infra.yaml
+++ b/ansible/inventory/host_vars/infra.yaml
@@ -15,11 +15,11 @@ vm:
cpu_pin: |
-
-
-
+
+
+
shares: 2048
- memory: 6
+ memory: 4
storage: 256
lan_mac: "0a:49:6e:4d:01:00"
lan_net: "lan-net"
diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini
index 8fcf9fe..942cee7 100644
--- a/ansible/inventory/hosts.ini
+++ b/ansible/inventory/hosts.ini
@@ -9,6 +9,7 @@ vmm ansible_host=vmm.ilnmors.internal ansible_user=vmm
# --- Virtual Machines ---
[vms]
fw ansible_host=fw.ilnmors.internal ansible_user=fw
+bk ansible_host=bk.ilnmors.internal ansible_user=bk
infra ansible_host=infra.ilnmors.internal ansible_user=infra
auth ansible_host=auth.ilnmors.internal ansible_user=auth
app ansible_host=app.ilnmors.internal ansible_user=app
diff --git a/ansible/playbooks/app/site.yaml b/ansible/playbooks/app/site.yaml
index 6526248..342e565 100644
--- a/ansible/playbooks/app/site.yaml
+++ b/ansible/playbooks/app/site.yaml
@@ -78,6 +78,14 @@
tags: ["init", "resolved"]
tags: ["init", "resolved"]
+ - name: Set timesyncd
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_timesyncd"
+ apply:
+ tags: ["init", "timesyncd"]
+ tags: ["init", "timesyncd"]
+
- name: Update and upgrade apt
ansible.builtin.apt:
upgrade: "dist"
@@ -100,7 +108,7 @@
- name: Set data volume
ansible.builtin.include_role:
- name: "app"
+ name: "common"
tasks_from: "node/set_data_volume"
apply:
tags: ["init", "raid"]
@@ -242,6 +250,14 @@
tags: ["site", "mealie"]
tags: ["site", "mealie"]
+ - name: Set homebox
+ ansible.builtin.include_role:
+ name: "app"
+ tasks_from: "services/set_homebox"
+ apply:
+ tags: ["site", "homebox"]
+ tags: ["site", "homebox"]
+
- name: Flush handlers right now
ansible.builtin.meta: "flush_handlers"
diff --git a/ansible/playbooks/auth/site.yaml b/ansible/playbooks/auth/site.yaml
index fb56629..d5cbc52 100644
--- a/ansible/playbooks/auth/site.yaml
+++ b/ansible/playbooks/auth/site.yaml
@@ -78,6 +78,14 @@
tags: ["init", "resolved"]
tags: ["init", "resolved"]
+ - name: Set timesyncd
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_timesyncd"
+ apply:
+ tags: ["init", "timesyncd"]
+ tags: ["init", "timesyncd"]
+
- name: Update and upgrade apt
ansible.builtin.apt:
upgrade: "dist"
diff --git a/ansible/playbooks/bk/site.yaml b/ansible/playbooks/bk/site.yaml
new file mode 100644
index 0000000..2d2d4a9
--- /dev/null
+++ b/ansible/playbooks/bk/site.yaml
@@ -0,0 +1,163 @@
+---
+- name: Load secret values
+ hosts: "console"
+ gather_facts: false
+ become: false
+ tasks:
+ - name: Load secret from secrets.yaml
+ ansible.builtin.include_role:
+ name: "console"
+ tasks_from: "node/load_secret_vars"
+ apply:
+ tags: ["always"]
+ tags: ["always"]
+
+- name: Site bk
+ hosts: "bk"
+ gather_facts: false
+ become: false
+ pre_tasks:
+ - name: Set become password
+ ansible.builtin.set_fact:
+ ansible_become_pass: "{{ hostvars['console']['sudo']['password']['bk'] }}"
+ no_log: true
+ tags: ["always"]
+
+ tasks:
+ - name: Set timezone
+ community.general.timezone:
+ name: "{{ timezone }}"
+ become: true
+ tags: ["init", "timezone"]
+
+ - name: Deploy root_ca certificate
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/deploy_root_ca"
+ apply:
+ tags: ["init", "root_crt"]
+ tags: ["init", "root_crt"]
+
+ - name: Deploy hosts file
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/deploy_hosts"
+ apply:
+ tags: ["init", "hosts"]
+ tags: ["init", "hosts"]
+
+ - name: Create default directory
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/create_default_dir"
+ apply:
+ tags: ["init", "default_dir"]
+ tags: ["init", "default_dir"]
+
+ - name: Set ssh host
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_ssh_host"
+ apply:
+ tags: ["init", "ssh_host"]
+ tags: ["init", "ssh_host"]
+
+ - name: Set networkd
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_networkd"
+ apply:
+ tags: ["init", "networkd"]
+ tags: ["init", "networkd"]
+
+ - name: Set resolved
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_resolved"
+ apply:
+ tags: ["init", "resolved"]
+ tags: ["init", "resolved"]
+
+ - name: Set timesyncd
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_timesyncd"
+ apply:
+ tags: ["init", "timesyncd"]
+ tags: ["init", "timesyncd"]
+
+ - name: Update and upgrade apt
+ ansible.builtin.apt:
+ upgrade: "dist"
+ update_cache: true
+ cache_valid_time: 3600
+ become: true
+ tags: ["init", "site", "upgrade-packages"]
+
+ - name: Install common packages
+ ansible.builtin.apt:
+ name:
+ - "acl"
+ - "curl"
+ - "jq"
+ - "netcat-openbsd"
+ - "dbus-user-session"
+ state: "present"
+ become: true
+ tags: ["init", "site", "install-packages"]
+
+ - name: Set data volume
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_data_volume"
+ apply:
+ tags: ["init", "raid"]
+ tags: ["init", "raid"]
+
+ - name: Set linger
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_linger"
+ apply:
+ tags: ["init", "linger"]
+ tags: ["init", "linger"]
+
+ - name: Set nftables
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_nftables"
+ apply:
+ tags: ["init", "nftables"]
+ tags: ["init", "nftables"]
+
+ - name: Set crowdsec
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "services/set_crowdsec"
+ apply:
+ tags: ["site", "crowdsec"]
+ tags: ["site", "crowdsec"]
+
+ - name: Set kopia
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "services/set_kopia"
+ apply:
+ tags: ["site", "kopia"]
+ tags: ["site", "kopia"]
+
+ - name: Set rclone
+ ansible.builtin.include_role:
+ name: "bk"
+ tasks_from: "services/set_rclone"
+ apply:
+ tags: ["site", "rclone"]
+ tags: ["site", "rclone"]
+
+ - name: Set alloy
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "services/set_alloy"
+ apply:
+ tags: ["site", "alloy"]
+ tags: ["site", "alloy"]
diff --git a/ansible/playbooks/console/create_cert.yaml b/ansible/playbooks/console/create_cert.yaml
new file mode 100644
index 0000000..2eee4ba
--- /dev/null
+++ b/ansible/playbooks/console/create_cert.yaml
@@ -0,0 +1,223 @@
+---
+- name: Load secret values
+ hosts: "console"
+ gather_facts: false
+ become: false
+ tasks:
+ - name: Load secret from secrets.yaml
+ ansible.builtin.include_role:
+ name: "console"
+ tasks_from: "node/load_secret_vars"
+ apply:
+ tags: ["always"]
+ tags: ["always"]
+
+- name: Site console
+ hosts: "console"
+ gather_facts: false
+ become: false
+ tasks:
+ - name: Create root CA
+ tags: ["never", "root"]
+ block:
+ - name: Clean previous CA temporary directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ state: "absent"
+ no_log: true
+ - name: Create ca directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ state: "directory"
+ mode: "0700"
+ - name: Get root CA password
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console']['ca']['root']['password'] }}
+ dest: "/run/user/{{ node['uid'] }}/ca/root_ca.password"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0400"
+ no_log: true
+ - name: Create root CA
+ ansible.builtin.command: |
+ step certificate create \
+ "{{ domain['internal'] }} Root CA" \
+ /run/user/{{ node['uid'] }}/ca/root_ca.crt \
+ /run/user/{{ node['uid'] }}/ca/root_ca.key \
+ --password-file /run/user/{{ node['uid'] }}/ca/root_ca.password \
+ --profile root-ca \
+ --not-after 87600h
+ changed_when: true
+ no_log: true
+ - name: Update root CA
+ environment:
+ SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
+ ansible.builtin.shell: |
+ set -euo pipefail
+ jq -Rs . "/run/user/{{ node['uid'] }}/ca/root_ca.crt" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["ca"]["root"]["crt"]'
+ jq -Rs . "/run/user/{{ node['uid'] }}/ca/root_ca.key" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["ca"]["root"]["key"]'
+ changed_when: true
+ no_log: true
+ always:
+ - name: Clean temporary files
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ state: "absent"
+ no_log: true
+
+ - name: Get root CA and create intermediate CA
+ tags: ["never", "intermediate"]
+ block:
+ - name: Clean previous CA temporary directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ state: "absent"
+ no_log: true
+ - name: Create ca certificates directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ state: "directory"
+ mode: "0700"
+ - name: Get root key and cert and password
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console']['ca']['root'][item] }}
+ dest: "/run/user/{{ node['uid'] }}/ca/root_ca.{{ item }}"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0400"
+ loop:
+ - "key"
+ - "crt"
+ - "password"
+ no_log: true
+ - name: Get intermediate CA password
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console']['ca']['intermediate']['password'] }}
+ dest: "/run/user/{{ node['uid'] }}/ca/intermediate_ca.password"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0400"
+ no_log: true
+ - name: Create intermediate CA
+ ansible.builtin.command: |
+ step certificate create \
+ "{{ domain['internal'] }} intermediate CA" \
+ /run/user/{{ node['uid'] }}/ca/intermediate_ca.crt \
+ /run/user/{{ node['uid'] }}/ca/intermediate_ca.key \
+ --password-file /run/user/{{ node['uid'] }}/ca/intermediate_ca.password \
+ --profile intermediate-ca \
+ --ca /run/user/{{ node['uid'] }}/ca/root_ca.crt \
+ --ca-key /run/user/{{ node['uid'] }}/ca/root_ca.key \
+ --ca-password-file /run/user/{{ node['uid'] }}/ca/root_ca.password \
+ --not-after 43800h
+ changed_when: true
+ no_log: true
+ - name: Update intermediate CA
+ environment:
+ SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
+ ansible.builtin.shell: |
+ set -euo pipefail
+ jq -Rs . "/run/user/{{ node['uid'] }}/ca/intermediate_ca.crt" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["ca"]["intermediate"]["crt"]'
+ jq -Rs . "/run/user/{{ node['uid'] }}/ca/intermediate_ca.key" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["ca"]["intermediate"]["key"]'
+ changed_when: true
+ no_log: true
+ always:
+ - name: Clean temporary files
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/ca"
+ state: "absent"
+ no_log: true
+
+ - name: Get intermediate CA and create leaf cert
+ tags: ["never", "leaf"]
+ block:
+ - name: Initialize self-cert services list
+ ansible.builtin.set_fact:
+ cert_services: []
+ - name: Set self-cert services list
+ ansible.builtin.set_fact:
+ cert_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.cert', 'defined')
+ | selectattr('value.dependency.cert', 'equalto', true)
+ | map(attribute='key')
+ | list
+ }}
+ - name: Clean previous leaf temporary directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/leaf"
+ state: "absent"
+ no_log: true
+ - name: Create leaf certificates directory
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/leaf"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ state: "directory"
+ mode: "0700"
+ - name: Get intermediate key and cert and password
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console']['ca']['intermediate'][item] }}
+ dest: "/run/user/{{ node['uid'] }}/leaf/intermediate_ca.{{ item }}"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0400"
+ loop:
+ - "key"
+ - "crt"
+ - "password"
+ no_log: true
+ - name: Create leaf certificates
+ ansible.builtin.command: |
+ step certificate create \
+ "{{ services[item]['domain']['internal'] }}.{{ domain['internal'] }}" \
+ /run/user/{{ node['uid'] }}/leaf/{{ item }}.crt \
+ /run/user/{{ node['uid'] }}/leaf/{{ item }}.key \
+ --profile leaf \
+ --san {{ services[item]['domain']['internal'] }}.{{ domain['internal'] }} \
+ --ca /run/user/{{ node['uid'] }}/leaf/intermediate_ca.crt \
+ --ca-key /run/user/{{ node['uid'] }}/leaf/intermediate_ca.key \
+ --ca-password-file /run/user/{{ node['uid'] }}/leaf/intermediate_ca.password \
+ --not-after 21900h \
+ --insecure --no-password
+ loop: "{{ cert_services }}"
+ changed_when: true
+ no_log: true
+ - name: Update leaf keys and certificates
+ environment:
+ SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
+ ansible.builtin.shell: |
+ set -euo pipefail
+ jq -Rs . "/run/user/{{ node['uid'] }}/leaf/{{ item }}.crt" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["{{ item }}"]["crt"]'
+ jq -Rs . "/run/user/{{ node['uid'] }}/leaf/{{ item }}.key" \
+ | sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
+ '["{{ item }}"]["key"]'
+ loop: "{{ cert_services }}"
+ changed_when: true
+ no_log: true
+ always:
+ - name: Clean temporary files
+ ansible.builtin.file:
+ path: "/run/user/{{ node['uid'] }}/leaf"
+ state: "absent"
+ no_log: true
diff --git a/ansible/playbooks/console/site.yaml b/ansible/playbooks/console/site.yaml
index a79afac..1ac3eab 100644
--- a/ansible/playbooks/console/site.yaml
+++ b/ansible/playbooks/console/site.yaml
@@ -108,8 +108,8 @@
ansible.builtin.get_url:
url: "https://cdimage.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2"
dest: "{{ node['data_path'] }}/images/debian-13-generic-amd64.qcow2"
- owner: "console"
- group: "svadmins"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
mode: "0600"
tags: ["init", "site", "cloud-init-image"]
diff --git a/ansible/playbooks/infra/site.yaml b/ansible/playbooks/infra/site.yaml
index a0bd5b7..71ef5db 100644
--- a/ansible/playbooks/infra/site.yaml
+++ b/ansible/playbooks/infra/site.yaml
@@ -78,6 +78,14 @@
tags: ["init", "resolved"]
tags: ["init", "resolved"]
+ - name: Set timesyncd
+ ansible.builtin.include_role:
+ name: "common"
+ tasks_from: "node/set_timesyncd"
+ apply:
+ tags: ["init", "timesyncd"]
+ tags: ["init", "timesyncd"]
+
- name: Update and upgrade apt
ansible.builtin.apt:
upgrade: "dist"
diff --git a/ansible/playbooks/vmm/create_vm.yaml b/ansible/playbooks/vmm/create_vm.yaml
index 4b01eae..edba912 100644
--- a/ansible/playbooks/vmm/create_vm.yaml
+++ b/ansible/playbooks/vmm/create_vm.yaml
@@ -19,6 +19,7 @@
vars:
valid_vm_names:
- "fw"
+ - "bk"
- "infra"
- "auth"
- "app"
diff --git a/ansible/playbooks/vmm/site.yaml b/ansible/playbooks/vmm/site.yaml
index ee28469..4b49a09 100644
--- a/ansible/playbooks/vmm/site.yaml
+++ b/ansible/playbooks/vmm/site.yaml
@@ -104,7 +104,7 @@
- name: Set raid
ansible.builtin.include_role:
name: "vmm"
- tasks_from: "node/set_raid"
+ tasks_from: "node/set_disk"
apply:
tags: ["init", "raid"]
tags: ["init", "raid"]
diff --git a/ansible/roles/app/handlers/main.yaml b/ansible/roles/app/handlers/main.yaml
index f7e9736..4d8fdbb 100644
--- a/ansible/roles/app/handlers/main.yaml
+++ b/ansible/roles/app/handlers/main.yaml
@@ -124,3 +124,14 @@
changed_when: false
listen: "notification_restart_mealie"
ignore_errors: true # noqa: ignore-errors
+
+- name: Restart homebox
+ ansible.builtin.systemd:
+ name: "homebox.service"
+ state: "restarted"
+ enabled: true
+ scope: "user"
+ daemon_reload: true
+ changed_when: false
+ listen: "notification_restart_homebox"
+ ignore_errors: true # noqa: ignore-errors
diff --git a/ansible/roles/app/tasks/services/set_collabora.yaml b/ansible/roles/app/tasks/services/set_collabora.yaml
index a1ae5bd..9fd80e0 100644
--- a/ansible/roles/app/tasks/services/set_collabora.yaml
+++ b/ansible/roles/app/tasks/services/set_collabora.yaml
@@ -1,4 +1,11 @@
---
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/collabora/code"
+ tag: "{{ version['containers']['collabora'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/collabora/collabora.container.j2"
diff --git a/ansible/roles/app/tasks/services/set_gitea.yaml b/ansible/roles/app/tasks/services/set_gitea.yaml
index 4daa3b3..b53fbe9 100644
--- a/ansible/roles/app/tasks/services/set_gitea.yaml
+++ b/ansible/roles/app/tasks/services/set_gitea.yaml
@@ -8,6 +8,7 @@
mode: "0770"
loop:
- "data/containers/gitea"
+ - "data/containers/gitea/data"
- "containers/gitea"
- "containers/gitea/ssl"
become: true
@@ -33,6 +34,13 @@
notify: "notification_restart_gitea"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/gitea/gitea"
+ tag: "{{ version['containers']['gitea'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/gitea/gitea.container.j2"
diff --git a/ansible/roles/app/tasks/services/set_homebox.yaml b/ansible/roles/app/tasks/services/set_homebox.yaml
new file mode 100644
index 0000000..213a2b3
--- /dev/null
+++ b/ansible/roles/app/tasks/services/set_homebox.yaml
@@ -0,0 +1,86 @@
+---
+- name: Create homebox directory
+ ansible.builtin.file:
+ path: "{{ node['home_path'] }}/{{ item }}"
+ state: "directory"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0770"
+ loop:
+ - "data/containers/homebox"
+ - "data/containers/homebox/data"
+ - "containers/homebox"
+ - "containers/homebox/ssl"
+ become: true
+
+- name: Deploy root certificate
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console']['ca']['root']['crt'] }}
+ dest: "{{ node['home_path'] }}/containers/homebox/ssl/{{ root_cert_filename }}"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0440"
+ become: true
+ notify: "notification_restart_homebox"
+ no_log: true
+
+- name: Register secret value to podman secret
+ containers.podman.podman_secret:
+ name: "{{ item.name }}"
+ data: "{{ item.value }}"
+ state: "present"
+ force: true
+ loop:
+ - name: "HBOX_AUTH_API_KEY_PEPPER"
+ value: "{{ hostvars['console']['homebox']['api_secret'] }}"
+ - name: "HBOX_DATABASE_PASSWORD"
+ value: "{{ hostvars['console']['postgresql']['password']['homebox'] }}"
+ - name: "HBOX_OIDC_CLIENT_SECRET"
+ value: "{{ hostvars['console']['homebox']['oidc']['secret'] }}"
+ notify: "notification_restart_homebox"
+ no_log: true
+
+- name: Pull image
+ containers.podman.podman_image:
+ name: "ghcr.io/sysadminsmedia/homebox"
+ tag: "{{ version['containers']['homebox'] }}"
+ state: "present"
+ pull: true
+
+- name: Deploy homebox.container file
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/homebox/homebox.container.j2"
+ dest: "{{ node['home_path'] }}/.config/containers/systemd/homebox.container"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0644"
+ notify: "notification_restart_homebox"
+
+- name: Enable homebox.service
+ ansible.builtin.systemd:
+ name: "homebox.service"
+ state: "started"
+ enabled: true
+ daemon_reload: true
+ scope: "user"
+
+- name: Check container archive images
+ ansible.builtin.stat:
+ path: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
+ register: container_archive_images
+
+- name: Save container archive images
+ containers.podman.podman_save:
+ image:
+ - "ghcr.io/sysadminsmedia/homebox:{{ version['containers']['homebox'] }}"
+ dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
+ format: "oci-archive"
+ force: false
+ when: not container_archive_images.stat.exists
+
+- name: Fetch container archive images
+ ansible.builtin.fetch:
+ src: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
+ dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
+ flat: true
diff --git a/ansible/roles/app/tasks/services/set_immich.yaml b/ansible/roles/app/tasks/services/set_immich.yaml
index 3630863..ef1d696 100644
--- a/ansible/roles/app/tasks/services/set_immich.yaml
+++ b/ansible/roles/app/tasks/services/set_immich.yaml
@@ -60,6 +60,7 @@
mode: "0770"
loop:
- "data/containers/immich"
+ - "data/containers/immich/data"
- "containers/immich"
- "containers/immich/ssl"
- "containers/immich/ml"
@@ -85,6 +86,22 @@
notify: "notification_restart_immich"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "{{ item.image }}"
+ tag: "{{ item.tag }}"
+ state: "present"
+ pull: true
+ loop:
+ - name: "immich_ml"
+ image: "ghcr.io/immich-app/immich-machine-learning"
+ tag: "{{ version['containers']['immich'] }}-openvino"
+ - name: "immich"
+ image: "ghcr.io/immich-app/immich-server"
+ tag: "{{ version['containers']['immich'] }}"
+ loop_control:
+ label: "{{ item.name }}"
+
- name: Deploy immich.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/immich/immich.container.j2"
@@ -123,14 +140,17 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "ghcr.io/immich-app/immich-machine-learning:{{ version['containers']['immich'] }}-openvino"
+ - name: "immich_ml"
+ image: "ghcr.io/immich-app/immich-machine-learning:{{ version['containers']['immich'] }}-openvino"
file: "ghcr.io_immich-app_immich-machine-learning_{{ version['containers']['immich'] }}-openvino"
- - image: "ghcr.io/immich-app/immich-server:{{ version['containers']['immich'] }}"
+ - name: "immich"
+ image: "ghcr.io/immich-app/immich-server:{{ version['containers']['immich'] }}"
file: "ghcr.io_immich-app_immich-server_{{ version['containers']['immich'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
diff --git a/ansible/roles/app/tasks/services/set_mealie.yaml b/ansible/roles/app/tasks/services/set_mealie.yaml
index b44ce3c..c9539b5 100644
--- a/ansible/roles/app/tasks/services/set_mealie.yaml
+++ b/ansible/roles/app/tasks/services/set_mealie.yaml
@@ -39,6 +39,13 @@
notify: "notification_restart_mealie"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "ghcr.io/mealie-recipes/mealie"
+ tag: "{{ version['containers']['mealie'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy mealie.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/mealie/mealie.container.j2"
diff --git a/ansible/roles/app/tasks/services/set_memos.yaml b/ansible/roles/app/tasks/services/set_memos.yaml
index cb10d6c..fffc9fb 100644
--- a/ansible/roles/app/tasks/services/set_memos.yaml
+++ b/ansible/roles/app/tasks/services/set_memos.yaml
@@ -29,13 +29,20 @@
containers.podman.podman_secret:
name: "MEMOS_DSN"
data: "postgresql://memos:{{ hostvars['console']['postgresql']['password']['memos'] | urlencode | replace('/', '%2F') }}\
- @{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/memos_db?sslmode=verify-full&\
+ @{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/memos_db?sslmode=verify-full&\
sslrootcert=/etc/ssl/memos/{{ root_cert_filename }}"
state: "present"
force: true
no_log: true
notify: "notification_restart_memos"
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/neosmemo/memos"
+ tag: "{{ version['containers']['memos'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy memos.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/memos/memos.container.j2"
diff --git a/ansible/roles/app/tasks/services/set_nextcloud.yaml b/ansible/roles/app/tasks/services/set_nextcloud.yaml
index 7fbecda..2a4a774 100644
--- a/ansible/roles/app/tasks/services/set_nextcloud.yaml
+++ b/ansible/roles/app/tasks/services/set_nextcloud.yaml
@@ -90,7 +90,7 @@
NEXTCLOUD_UPDATE: "1"
NEXTCLOUD_ADMIN_USER: "{{ hostvars['console']['nextcloud']['admin']['id'] }}"
NEXTCLOUD_ADMIN_PASSWORD: "{{ hostvars['console']['nextcloud']['admin']['password'] }}"
- POSTGRES_HOST: "{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
+ POSTGRES_HOST: "{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
POSTGRES_DB: "nextcloud_db"
POSTGRES_USER: "nextcloud"
POSTGRES_PASSWORD: "{{ hostvars['console']['postgresql']['password']['nextcloud'] }}"
@@ -139,6 +139,13 @@
- "upload.ini"
notify: "notification_restart_nextcloud"
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/library/nextcloud"
+ tag: "{{ version['containers']['nextcloud'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy nextcloud.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/nextcloud/nextcloud.container.j2"
@@ -179,12 +186,14 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}"
+ - name: "nextcloud"
+ image: "docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}"
file: "docker.io_library_nextcloud_{{ version['containers']['nextcloud'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
diff --git a/ansible/roles/app/tasks/services/set_outline.yaml b/ansible/roles/app/tasks/services/set_outline.yaml
index 3e7690e..4f1975c 100644
--- a/ansible/roles/app/tasks/services/set_outline.yaml
+++ b/ansible/roles/app/tasks/services/set_outline.yaml
@@ -101,6 +101,13 @@
notify: "notification_restart_outline"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/outlinewiki/outline"
+ tag: "{{ version['containers']['outline'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy outline.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/outline/outline.container.j2"
@@ -122,12 +129,14 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "docker.io/outlinewiki/outline:{{ version['containers']['outline'] }}"
+ - name: "outline"
+ image: "docker.io/outlinewiki/outline:{{ version['containers']['outline'] }}"
file: "docker.io_outlinewiki_outline_{{ version['containers']['outline'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
diff --git a/ansible/roles/app/tasks/services/set_paperless.yaml b/ansible/roles/app/tasks/services/set_paperless.yaml
index c135461..372697a 100644
--- a/ansible/roles/app/tasks/services/set_paperless.yaml
+++ b/ansible/roles/app/tasks/services/set_paperless.yaml
@@ -67,6 +67,8 @@
owner: "{{ ansible_user }}"
group: "{{ node['group'] }}"
mode: "0640"
+ register: "is_paperless_containerfile"
+ notify: "notification_restart_paperless"
- name: Deploy root certificate
ansible.builtin.copy:
@@ -87,6 +89,7 @@
tag: "{{ version['containers']['paperless'] }}"
state: "build"
path: "{{ node['home_path'] }}/containers/paperless/build"
+ force: "{{ is_paperless_containerfile.changed }}"
- name: Prune paperless dangling images
containers.podman.podman_prune:
@@ -116,7 +119,7 @@
"client_id": "paperless",
"secret": "{{ hostvars['console']['paperless']['oidc']['secret'] }}",
"settings": {
- "server_url": "https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/.well-known/openid-configuration",
+ "server_url": "https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration",
"token_auth_method": "client_secret_post"
}
}
@@ -147,12 +150,14 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "{{ domain['internal'] }}/{{ node['name'] }}/paperless-ngx:{{ version['containers']['paperless'] }}"
+ - name: "paperless"
+ image: "{{ domain['internal'] }}/{{ node['name'] }}/paperless-ngx:{{ version['containers']['paperless'] }}"
file: "{{ domain['internal'] }}_{{ node['name'] }}_paperless-ngx_{{ version['containers']['paperless'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
@@ -161,11 +166,11 @@
- "{{ item.item.image }}"
dest: "{{ node['home_path'] }}/archives/containers/{{ item.item.file }}.tar"
format: "oci-archive"
- force: false
+ force: "{{ is_paperless_containerfile.changed }}"
loop: "{{ container_archive_images.results }}"
loop_control:
label: "{{ item.item.file }}"
- when: not item.stat.exists
+ when: not item.stat.exists or (item.item.name == 'paperless' and is_paperless_containerfile.changed)
- name: Fetch container archive images
ansible.builtin.fetch:
diff --git a/ansible/roles/app/tasks/services/set_sure.yaml b/ansible/roles/app/tasks/services/set_sure.yaml
index 9f2fd49..32873cd 100644
--- a/ansible/roles/app/tasks/services/set_sure.yaml
+++ b/ansible/roles/app/tasks/services/set_sure.yaml
@@ -86,6 +86,13 @@
notify: "notification_restart_sure"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "ghcr.io/we-promise/sure"
+ tag: "{{ version['containers']['sure'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy sure.container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/sure/{{ item }}.j2"
@@ -113,12 +120,14 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "ghcr.io/we-promise/sure:{{ version['containers']['sure'] }}"
+ - name: "sure"
+ image: "ghcr.io/we-promise/sure:{{ version['containers']['sure'] }}"
file: "ghcr.io_we-promise_sure_{{ version['containers']['sure'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
diff --git a/ansible/roles/app/tasks/services/set_vaultwarden.yaml b/ansible/roles/app/tasks/services/set_vaultwarden.yaml
index cdef9df..e5affba 100644
--- a/ansible/roles/app/tasks/services/set_vaultwarden.yaml
+++ b/ansible/roles/app/tasks/services/set_vaultwarden.yaml
@@ -8,6 +8,7 @@
mode: "0770"
loop:
- "data/containers/vaultwarden"
+ - "data/containers/vaultwarden/data"
- "containers/vaultwarden"
- "containers/vaultwarden/ssl"
@@ -34,11 +35,18 @@
value: "{{ hostvars['console']['vaultwarden']['admin']['hash'] }}"
- name: "VW_DATABASE_URL"
value: "postgresql://vaultwarden:{{ hostvars['console']['postgresql']['password']['vaultwarden'] | urlencode | replace('/', '%2F') }}\
- @{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/vaultwarden_db?sslmode=verify-full&\
+ @{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/vaultwarden_db?sslmode=verify-full&\
sslrootcert=/etc/ssl/vaultwarden/{{ root_cert_filename }}"
notify: "notification_restart_vaultwarden"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/vaultwarden/server"
+ tag: "{{ version['containers']['vaultwarden'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/vaultwarden/vaultwarden.container.j2"
diff --git a/ansible/roles/auth/tasks/services/set_authelia.yaml b/ansible/roles/auth/tasks/services/set_authelia.yaml
index f735cc8..077e97f 100644
--- a/ansible/roles/auth/tasks/services/set_authelia.yaml
+++ b/ansible/roles/auth/tasks/services/set_authelia.yaml
@@ -60,6 +60,13 @@
notify: "notification_restart_authelia"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/authelia/authelia"
+ tag: "{{ version['containers']['authelia'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/auth/authelia/authelia.container.j2"
diff --git a/ansible/roles/bk/tasks/services/set_rclone.yaml b/ansible/roles/bk/tasks/services/set_rclone.yaml
new file mode 100644
index 0000000..1a8c77c
--- /dev/null
+++ b/ansible/roles/bk/tasks/services/set_rclone.yaml
@@ -0,0 +1,54 @@
+---
+- name: Check rclone installation
+ ansible.builtin.shell: |
+ command -v rclone
+ changed_when: false
+ failed_when: false
+ register: "is_rclone_installed"
+ ignore_errors: true
+
+- name: Install rclone
+ ansible.builtin.apt:
+ name:
+ - "rclone"
+ state: "present"
+ become: true
+ when: is_rclone_installed.rc != 0
+
+- name: Create rclone config directory
+ ansible.builtin.file:
+ path: "/etc/secrets/{{ node['uid'] }}/rclone"
+ state: "directory"
+ owner: "{{ ansible_user }}"
+ group: "root"
+ mode: "0700"
+ become: true
+
+- name: Deploy rclone config
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/bk/rclone/config/rclone.config.j2"
+ dest: "/etc/secrets/{{ node['uid'] }}/rclone/rclone.config"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0600"
+ no_log: true
+
+- name: Deploy rclone backup service files
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/bk/rclone/{{ item }}.j2"
+ dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0644"
+ validate: "/usr/bin/systemd-analyze verify %s"
+ loop:
+ - "rclone.service"
+ - "rclone.timer"
+
+- name: Enable rclone timer
+ ansible.builtin.systemd:
+ name: "rclone.timer"
+ state: "started"
+ enabled: true
+ scope: "user"
+ daemon_reload: true
diff --git a/ansible/roles/common/handlers/main.yaml b/ansible/roles/common/handlers/main.yaml
index c254c8f..90daacd 100644
--- a/ansible/roles/common/handlers/main.yaml
+++ b/ansible/roles/common/handlers/main.yaml
@@ -99,3 +99,14 @@
changed_when: false
listen: "notification_restart_alloy"
ignore_errors: true # noqa: ignore-errors
+
+- name: Restart kopia server
+ ansible.builtin.systemd:
+ name: "kopia-server.service"
+ state: "restarted"
+ enabled: true
+ scope: "user"
+ daemon_reload: true
+ changed_when: false
+ listen: "notification_restart_kopia_server"
+ ignore_errors: true # noqa: ignore-errors
diff --git a/ansible/roles/app/tasks/node/set_data_volume.yaml b/ansible/roles/common/tasks/node/set_data_volume.yaml
similarity index 62%
rename from ansible/roles/app/tasks/node/set_data_volume.yaml
rename to ansible/roles/common/tasks/node/set_data_volume.yaml
index bb42766..75500e5 100644
--- a/ansible/roles/app/tasks/node/set_data_volume.yaml
+++ b/ansible/roles/common/tasks/node/set_data_volume.yaml
@@ -1,16 +1,16 @@
---
-- name: Check app data volume filesystem already exists
- ansible.builtin.command:
- cmd: "blkid /dev/{{ vm['data_storage']['name'] }}"
- register: is_app_data
+- name: Check data volume filesystem already exists
+ ansible.builtin.command: |
+ blkid /dev/{{ vm['data_storage']['name'] }}
+ register: is_volume
changed_when: false
failed_when: false
become: true
-- name: Create ext4 filesystem on app data raw
- ansible.builtin.command:
- cmd: "mkfs.ext4 -F /dev/{{ vm['data_storage']['name'] }}"
- when: is_app_data.rc != 0
+- name: Create ext4 filesystem on data raw
+ ansible.builtin.command: |
+ mkfs.ext4 -F /dev/{{ vm['data_storage']['name'] }}
+ when: is_volume.rc != 0
changed_when: true
become: true
@@ -22,7 +22,7 @@
group: "{{ node['group'] }}"
mode: "0770"
-- name: Mount app data volume
+- name: Mount data volume
ansible.posix.mount:
path: "{{ node['home_path'] }}/data"
src: "/dev/{{ vm['data_storage']['name'] }}"
@@ -31,7 +31,7 @@
fstype: "ext4"
become: true
-- name: Set app data volume path permissions
+- name: Set data volume path permissions
ansible.builtin.file:
path: "{{ node['home_path'] }}/data"
state: "directory"
diff --git a/ansible/roles/common/tasks/node/set_timesyncd.yaml b/ansible/roles/common/tasks/node/set_timesyncd.yaml
index 6b78325..d376bdb 100644
--- a/ansible/roles/common/tasks/node/set_timesyncd.yaml
+++ b/ansible/roles/common/tasks/node/set_timesyncd.yaml
@@ -9,8 +9,8 @@
become: true
- name: Deploy timesyncd.conf.d/local-ntp.conf
- ansible.builtin.copy:
- src: "{{ hostvars['console']['node']['config_path'] }}/node/common/timesyncd/local-ntp.conf"
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/node/common/timesyncd/local-ntp.conf.j2"
dest: "/etc/systemd/timesyncd.conf.d/local-ntp.conf"
owner: "root"
group: "systemd-timesync"
diff --git a/ansible/roles/common/tasks/services/set_alloy.yaml b/ansible/roles/common/tasks/services/set_alloy.yaml
index 732d7ad..f02eb89 100644
--- a/ansible/roles/common/tasks/services/set_alloy.yaml
+++ b/ansible/roles/common/tasks/services/set_alloy.yaml
@@ -1,5 +1,5 @@
---
-- name: Gather ystem facts (hardware)
+- name: Gather system facts (hardware)
ansible.builtin.setup:
gather_subset:
- hardware
@@ -78,7 +78,7 @@
- "{{ node['home_path'] }}"
- "{{ node['home_path'] }}/data"
become: true
- when: node['name'] == "app"
+ when: node['name'] in ["bk", "app"]
- name: Enable alloy service
ansible.builtin.systemd:
@@ -88,9 +88,16 @@
daemon_reload: true
become: true
+- name: Check alloy.deb on console
+ delegate_to: "console"
+ ansible.builtin.stat:
+ path: "{{ hostvars['console']['node']['data_path'] }}/bin/alloy-{{ version['packages']['alloy'] }}.deb"
+ register: is_console_alloy_deb
+
- name: Fetch deb bin file
ansible.builtin.fetch:
src: "/var/cache/apt/archives/alloy-{{ version['packages']['alloy'] }}.deb"
dest: "{{ hostvars['console']['node']['data_path'] }}/bin/"
flat: true
+ when: not is_console_alloy_deb.stat.exists
become: true
diff --git a/ansible/roles/common/tasks/services/set_caddy.yaml b/ansible/roles/common/tasks/services/set_caddy.yaml
index b32b9c9..c5d02de 100644
--- a/ansible/roles/common/tasks/services/set_caddy.yaml
+++ b/ansible/roles/common/tasks/services/set_caddy.yaml
@@ -1,5 +1,48 @@
---
+- name: Initialize Caddy services list
+ ansible.builtin.set_fact:
+ caddy_services: []
+
# infra, auth, app (vmm, fw has no podman in it)
+- name: Set Caddy infra services list
+ ansible.builtin.set_fact:
+ caddy_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.web', 'defined')
+ | selectattr('value.dependency.web', 'in', ['infra-internal', 'infra-public'])
+ | map(attribute='key')
+ | list
+ }}
+ when: node['name'] == 'infra'
+
+- name: Set Caddy auth services list
+ ansible.builtin.set_fact:
+ caddy_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.web', 'defined')
+ | selectattr('value.dependency.web', 'in', ['auth-public', 'infra-public', 'app-public'])
+ | map(attribute='key')
+ | list
+ }}
+ when: node['name'] == 'auth'
+
+- name: Set Caddy app services list
+ ansible.builtin.set_fact:
+ caddy_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.web', 'defined')
+ | selectattr('value.dependency.web', 'in', ['app-internal', 'app-public'])
+ | map(attribute='key')
+ | list
+ }}
+ when: node['name'] == 'app'
+
- name: Create caddy directory
ansible.builtin.file:
path: "{{ node['home_path'] }}/containers/{{ item }}"
@@ -50,6 +93,8 @@
owner: "{{ ansible_user }}"
group: "{{ node['group'] }}"
mode: "0640"
+ register: "is_caddy_containerfile"
+ notify: "notification_restart_caddy"
- name: Deploy root crt for build
ansible.builtin.copy:
@@ -58,6 +103,8 @@
owner: "{{ ansible_user }}"
group: "{{ node['group'] }}"
mode: "0640"
+ register: "is_caddy_root_crt"
+ notify: "notification_restart_caddy"
no_log: true
- name: Build caddy container image
@@ -67,6 +114,7 @@
tag: "{{ version['containers']['caddy'] }}"
state: "build"
path: "{{ node['home_path'] }}/containers/caddy/build"
+ force: "{{ is_caddy_root_crt.changed or is_caddy_containerfile.changed }}"
- name: Prune caddy dangling images
containers.podman.podman_prune:
@@ -74,7 +122,7 @@
- name: Deploy caddyfile
ansible.builtin.template:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/common/caddy/etc/{{ node['name'] }}/Caddyfile.j2"
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/common/caddy/etc/Caddyfile.j2"
dest: "{{ node['home_path'] }}/containers/caddy/etc/Caddyfile"
owner: "{{ ansible_user }}"
group: "{{ node['group'] }}"
@@ -109,8 +157,8 @@
- "{{ domain['internal'] }}/{{ node['name'] }}/caddy:{{ version['containers']['caddy'] }}"
dest: "{{ node['home_path'] }}/archives/containers/{{ domain['internal'] }}_{{ node['name'] }}_caddy_{{ version['containers']['caddy'] }}.tar"
format: "oci-archive"
- force: false
- when: not container_archive_images.stat.exists
+ force: "{{ is_caddy_root_crt.changed or is_caddy_containerfile.changed }}"
+ when: not container_archive_images.stat.exists or is_caddy_root_crt.changed or is_caddy_containerfile.changed
- name: Fetch container archive images
ansible.builtin.fetch:
diff --git a/ansible/roles/common/tasks/services/set_crowdsec.yaml b/ansible/roles/common/tasks/services/set_crowdsec.yaml
index 23f3c51..eef946d 100644
--- a/ansible/roles/common/tasks/services/set_crowdsec.yaml
+++ b/ansible/roles/common/tasks/services/set_crowdsec.yaml
@@ -120,8 +120,8 @@
no_log: true
- name: Get existing machines list
- ansible.builtin.command:
- cmd: "cscli machines list -o json"
+ ansible.builtin.command: |
+ cscli machines list -o json
become: true
changed_when: false
register: "existing_crowdsec_machines_list"
@@ -132,27 +132,27 @@
- name: Set goal machines' name
ansible.builtin.set_fact:
- machines_name: ["fw", "vmm", "infra", "auth", "app"]
+ machines_name: ["fw", "vmm", "bk", "infra", "auth", "app"]
no_log: true
- name: Prune unknown (random) machines
- ansible.builtin.command:
- cmd: "cscli machines delete {{ item }}"
+ ansible.builtin.command: |
+ cscli machines delete {{ item }}
loop: "{{ existing_machines_name | difference(machines_name) }}"
become: true
changed_when: true
- name: Register crowdsec machines to LAPI server
- ansible.builtin.command:
- cmd: "cscli machines add {{ item }} --password {{ hostvars['console']['crowdsec']['machine'][item] }} --force -f /dev/null"
+ ansible.builtin.command: |
+ cscli machines add {{ item }} --password {{ hostvars['console']['crowdsec']['machine'][item] }} --force -f /dev/null
loop: "{{ machines_name }}"
become: true
changed_when: false
no_log: true
- name: Get existing bouncers list
- ansible.builtin.command:
- cmd: "cscli bouncers list -o json"
+ ansible.builtin.command: |
+ cscli bouncers list -o json
become: true
register: "existing_crowdsec_bouncers_list"
changed_when: false
@@ -162,8 +162,8 @@
existing_bouncers_name: "{{ existing_crowdsec_bouncers_list.stdout | from_json | map(attribute='name') | list }}"
- name: Flush bouncers
- ansible.builtin.command:
- cmd: "cscli bouncers delete {{ item }}"
+ ansible.builtin.command: |
+ cscli bouncers delete {{ item }}
loop: "{{ existing_bouncers_name }}"
become: true
changed_when: true
@@ -173,8 +173,8 @@
bouncers_name: ["fw", "caddy"]
- name: Register Firewall Bouncer to LAPI
- ansible.builtin.command:
- cmd: "cscli bouncers add {{ item }}-bouncer -k {{ hostvars['console']['crowdsec']['bouncer'][item] }}"
+ ansible.builtin.command: |
+ cscli bouncers add {{ item }}-bouncer -k {{ hostvars['console']['crowdsec']['bouncer'][item] }}
loop: "{{ bouncers_name }}"
become: true
changed_when: true
@@ -185,8 +185,8 @@
when: node['name'] in acquisd_list
block:
- name: Install crowdsec collection
- ansible.builtin.command:
- cmd: "cscli collections install {{ item }}"
+ ansible.builtin.command: |
+ cscli collections install {{ item }}
loop: "{{ acquisd_list[node['name']]['collection'] }}"
become: true
changed_when: "'overwrite' not in is_collection_installed.stderr"
@@ -196,8 +196,8 @@
register: "is_collection_installed"
- name: Install crowdsec parser
- ansible.builtin.command:
- cmd: "cscli parsers install {{ item }}"
+ ansible.builtin.command: |
+ cscli parsers install {{ item }}
loop: "{{ acquisd_list[node['name']]['parser'] }}"
become: true
changed_when: "'overwrite' not in is_parser_installed.stderr"
diff --git a/ansible/roles/common/tasks/services/set_kopia.yaml b/ansible/roles/common/tasks/services/set_kopia.yaml
index 41c8875..5a568ca 100644
--- a/ansible/roles/common/tasks/services/set_kopia.yaml
+++ b/ansible/roles/common/tasks/services/set_kopia.yaml
@@ -5,50 +5,288 @@
- hardware
become: true
-- name: Set console kopia
- when: node['name'] == 'console'
+- name: Set backup kopia repository server
+ when: node['name'] == "bk"
block:
- - name: Download kopia
+ - name: Download kopia deb file (x86_64)
ansible.builtin.get_url:
url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
- kopia_{{ version['packages']['kopia'] }}_linux_{{ item }}.deb"
- dest: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-{{ item }}.deb"
- owner: "{{ ansible_user }}"
- group: "{{ node['group'] }}"
- mode: "0600"
- loop:
- - "amd64"
- - "arm64"
-
- - name: Install kopia (x86_64)
- ansible.builtin.apt:
- deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-amd64.deb"
- state: "present"
+ kopia_{{ version['packages']['kopia'] }}_linux_amd64.deb"
+ dest: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
+ owner: "root"
+ group: "root"
+ mode: "0644"
become: true
when: ansible_facts['architecture'] == "x86_64"
- - name: Install kopia (aarch64)
- ansible.builtin.apt:
- deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-arm64.deb"
- state: "present"
+ - name: Download kopia deb file (aarch64)
+ ansible.builtin.get_url:
+ url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
+ kopia_{{ version['packages']['kopia'] }}_linux_arm64.deb"
+ dest: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
+ owner: "root"
+ group: "root"
+ mode: "0644"
become: true
when: ansible_facts['architecture'] == "aarch64"
- - name: Connect console kopia server
- environment:
- KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users']['console'] }}"
- ansible.builtin.shell: |
- /usr/bin/kopia repository connect server \
- --url=https://{{ services['kopia']['domain'] }}.{{ domain['internal'] }}:{{ services['kopia']['ports']['https'] }} \
- --override-username=console \
- --override-hostname=console.{{ domain['internal'] }}
- changed_when: false
- failed_when: is_kopia_connected.rc != 0
- register: "is_kopia_connected"
+ - name: Create kopia directory
+ ansible.builtin.file:
+ path: "{{ item.name }}"
+ state: "directory"
+ owner: "{{ ansible_user }}"
+ group: "root"
+ mode: "{{ item.mode }}"
+ loop:
+ - name: "/etc/kopia"
+ mode: "0700"
+ - name: "/etc/kopia/ssl"
+ mode: "0700"
+ - name: "/var/cache/kopia"
+ mode: "0700"
+ become: true
no_log: true
-- name: Set infra/app kopia
- when: node['name'] in ['infra', 'app']
+ - name: Install kopia
+ ansible.builtin.apt:
+ deb: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
+ state: "present"
+ become: true
+
+ - name: Deploy kopia env
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/kopia.env.j2"
+ dest: "/etc/secrets/{{ node['uid'] }}/kopia.env"
+ owner: "{{ ansible_user }}"
+ group: "root"
+ mode: "0400"
+ become: true
+ notify: "notification_restart_kopia_server"
+ no_log: true
+
+ - name: Deploy kopia certificate and key
+ ansible.builtin.copy:
+ content: |
+ {{ item.value }}
+ dest: "/etc/kopia/ssl/{{ item.name }}"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "{{ item.mode }}"
+ loop:
+ - name: "kopia.crt"
+ value: |
+ {{ hostvars['console']['kopia']['crt'] | trim }}
+ {{ hostvars['console']['ca']['intermediate']['crt'] }}
+ mode: "0440"
+ - name: "kopia.key"
+ value: "{{ hostvars['console']['kopia']['key'] }}"
+ mode: "0400"
+ notify: "notification_restart_kopia_server"
+ no_log: true
+
+ - name: Check repository existance
+ ansible.builtin.stat:
+ path: "{{ node['home_path'] }}/data/kopia/repository"
+ register: "is_kopia_repository"
+
+ - name: Create repository directory
+ ansible.builtin.file:
+ path: "{{ node['home_path'] }}/data/kopia/repository"
+ state: "directory"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0770"
+ when: not is_kopia_repository.stat.exists
+
+ - name: Create kopia repository
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia repository create filesystem \
+ --path="{{ node['home_path'] }}/data/kopia/repository" \
+ --description="ilnmors.internal kopia repository" \
+ --create-only
+ when: not is_kopia_repository.stat.exists
+ changed_when: true
+ register: "is_repository_created"
+ no_log: true
+
+ - name: Connect to kopia repository
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia repository connect filesystem \
+ --path="{{ node['home_path'] }}/data/kopia/repository" \
+ --override-username="il" \
+ --override-hostname="{{ node['name'] }}.{{ domain['internal'] }}" \
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_created.rc == 0
+ changed_when: true
+ register: "is_repository_connected"
+ no_log: true
+
+ - name: Create kopia user
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia server users add \
+ --user-password {{ item.password | quote }} \
+ {{ item.name }}
+ loop:
+ - name: "console@console.ilnmors.internal"
+ password: "{{ hostvars['console']['kopia']['users']['console'] }}"
+ - name: "infra@infra.ilnmors.internal"
+ password: "{{ hostvars['console']['kopia']['users']['infra'] }}"
+ - name: "app@app.ilnmors.internal"
+ password: "{{ hostvars['console']['kopia']['users']['app'] }}"
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ register: "is_user_created"
+ no_log: true
+
+ - name: Set kopia console ACL
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia server acl add \
+ --user console@console.ilnmors.internal \
+ --target {{ item }} \
+ --access FULL
+ loop:
+ - "type=snapshot"
+ - "type=policy"
+ - "type=user"
+ - "type=acl"
+ - "type=content"
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ no_log: true
+
+ - name: Set kopia infra ACL
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia server acl add \
+ --user infra@infra.ilnmors.internal \
+ --target {{ item.target }} \
+ --access {{ item.access }}
+ loop:
+ - target: "type=snapshot"
+ access: "FULL"
+ - target: "type=policy"
+ access: "READ"
+ - target: "type=policy,username=infra,hostname=infra.ilnmors.internal"
+ access: "FULL"
+ - target: "type=content"
+ access: "APPEND"
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ no_log: true
+
+ - name: Set kopia app ACL
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia server acl add \
+ --user app@app.ilnmors.internal \
+ --target {{ item.target }} \
+ --access {{ item.access }}
+ loop:
+ - target: "type=snapshot"
+ access: "FULL"
+ - target: "type=policy"
+ access: "READ"
+ - target: "type=policy,username=app,hostname=app.ilnmors.internal"
+ access: "FULL"
+ - target: "type=content"
+ access: "APPEND"
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ no_log: true
+
+ - name: Set kopia policy
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia policy set \
+ {{ item.content }}
+ loop:
+ - content: |
+ --global \
+ --compression=zstd
+ - content: |
+ infra@infra.ilnmors.internal \
+ --compression=zstd \
+ --keep-latest=10 \
+ --keep-hourly=0 \
+ --keep-daily=14 \
+ --keep-weekly=4 \
+ --keep-monthly=6 \
+ --keep-annual=1
+ - content: |
+ app@app.ilnmors.internal \
+ --compression=none \
+ --keep-latest=10 \
+ --keep-hourly=0 \
+ --keep-daily=14 \
+ --keep-weekly=4 \
+ --keep-monthly=6 \
+ --keep-annual=1
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ no_log: true
+
+ - name: Set kopia parameters
+ ansible.builtin.shell: |
+ set -a
+ . /etc/secrets/{{ node['uid'] }}/kopia.env
+ set +a
+ /usr/bin/kopia repository set-parameters \
+ --max-pack-size-mb=100
+ when:
+ - not is_kopia_repository.stat.exists
+ - is_repository_connected.rc == 0
+ changed_when: true
+ no_log: true
+
+ - name: Deploy kopia servcer service file
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/kopia-server.service.j2"
+ dest: "{{ node['home_path'] }}/.config/systemd/user/kopia-server.service"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0644"
+ validate: "/usr/bin/systemd-analyze verify %s"
+ become: true
+
+ - name: Enable kopia server service
+ ansible.builtin.systemd:
+ name: "kopia-server.service"
+ state: "started"
+ enabled: true
+ scope: "user"
+ daemon_reload: true
+
+- name: Set infra/app backup kopia
+ when: node['name'] in ["infra", "app"]
block:
- name: Set kopia uid
ansible.builtin.set_fact:
@@ -127,7 +365,7 @@
become: true
no_log: true
- - name: Deploy kopia service files
+ - name: Deploy kopia backup service files
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/{{ item }}.j2"
dest: "/etc/systemd/system/{{ item }}"
@@ -140,10 +378,52 @@
- "kopia-backup.timer"
become: true
- - name: Enable auto kopia rules update
+ - name: Enable Kopia backup timer
ansible.builtin.systemd:
name: "kopia-backup.timer"
state: "started"
enabled: true
daemon_reload: true
become: true
+
+- name: Set console kopia
+ when: node['name'] == "console"
+ block:
+ - name: Download kopia
+ ansible.builtin.get_url:
+ url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
+ kopia_{{ version['packages']['kopia'] }}_linux_{{ item }}.deb"
+ dest: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-{{ item }}.deb"
+ owner: "{{ ansible_user }}"
+ group: "{{ node['group'] }}"
+ mode: "0600"
+ loop:
+ - "amd64"
+ - "arm64"
+
+ - name: Install kopia (x86_64)
+ ansible.builtin.apt:
+ deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-amd64.deb"
+ state: "present"
+ become: true
+ when: ansible_facts['architecture'] == "x86_64"
+
+ - name: Install kopia (aarch64)
+ ansible.builtin.apt:
+ deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-arm64.deb"
+ state: "present"
+ become: true
+ when: ansible_facts['architecture'] == "aarch64"
+
+ - name: Connect console kopia server
+ environment:
+ KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users']['console'] }}"
+ ansible.builtin.shell: |
+ /usr/bin/kopia repository connect server \
+ --url=https://{{ services['kopia']['domain']['internal'] }}.{{ domain['internal'] }}:443 \
+ --override-username=console \
+ --override-hostname=console.{{ domain['internal'] }}
+ changed_when: false
+ failed_when: is_kopia_connected.rc != 0
+ register: "is_kopia_connected"
+ no_log: true
diff --git a/ansible/roles/console/tasks/node/load_secret_vars.yaml b/ansible/roles/console/tasks/node/load_secret_vars.yaml
index 3380b7c..93c6024 100644
--- a/ansible/roles/console/tasks/node/load_secret_vars.yaml
+++ b/ansible/roles/console/tasks/node/load_secret_vars.yaml
@@ -16,7 +16,7 @@
environment:
SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
ansible.builtin.command: |
- sops -d --output-type yaml {{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml
+ sops -d --output-type yaml "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml"
changed_when: false
register: "decrypted_secrets"
run_once: true
diff --git a/ansible/roles/infra/tasks/services/set_ca_server.yaml b/ansible/roles/infra/tasks/services/set_ca_server.yaml
index 967c266..69f0916 100644
--- a/ansible/roles/infra/tasks/services/set_ca_server.yaml
+++ b/ansible/roles/infra/tasks/services/set_ca_server.yaml
@@ -24,16 +24,20 @@
notify: "notification_restart_ca"
no_log: true
-- name: Deploy ca config files
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/smallstep/step-ca"
+ tag: "{{ version['containers']['step'] }}"
+ state: "present"
+ pull: true
+
+- name: Deploy ca config file
ansible.builtin.template:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ca/config/{{ item }}.j2"
- dest: "{{ node['home_path'] }}/containers/ca/config/{{ item }}"
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ca/config/ca.json.j2"
+ dest: "{{ node['home_path'] }}/containers/ca/config/ca.json"
owner: "{{ services['ca']['subuid'] }}"
group: "{{ node['group'] }}"
mode: "0400"
- loop:
- - "ca.json"
- - "defaults.json"
become: true
notify: "notification_restart_ca"
diff --git a/ansible/roles/infra/tasks/services/set_grafana.yaml b/ansible/roles/infra/tasks/services/set_grafana.yaml
index 744ac21..f24b07d 100644
--- a/ansible/roles/infra/tasks/services/set_grafana.yaml
+++ b/ansible/roles/infra/tasks/services/set_grafana.yaml
@@ -68,6 +68,13 @@
become: true
notify: "notification_restart_grafana"
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/grafana/grafana"
+ tag: "{{ version['containers']['grafana'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/grafana/grafana.container.j2"
diff --git a/ansible/roles/infra/tasks/services/set_ldap.yaml b/ansible/roles/infra/tasks/services/set_ldap.yaml
index 52d78af..1f2e2cb 100644
--- a/ansible/roles/infra/tasks/services/set_ldap.yaml
+++ b/ansible/roles/infra/tasks/services/set_ldap.yaml
@@ -46,7 +46,8 @@
# urlencode doesn't fix `/` as `%2F`. It needs replace
- name: "LLDAP_DATABASE_URL"
value: "postgres://ldap:{{ hostvars['console']['postgresql']['password']['ldap'] | urlencode | replace('/', '%2F') }}\
- @{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/ldap_db?sslmode=verify-full&sslrootcert=/etc/ssl/ldap/{{ root_cert_filename }}"
+ @{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/\
+ ldap_db?sslmode=verify-full&sslrootcert=/etc/ssl/ldap/{{ root_cert_filename }}"
- name: "LLDAP_KEY_SEED"
value: "{{ hostvars['console']['ldap']['seed_key'] }}"
- name: "LLDAP_JWT_SECRET"
@@ -93,6 +94,13 @@
name: "LLDAP_LDAP_USER_PASSWORD"
state: "absent"
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/lldap/lldap"
+ tag: "{{ version['containers']['ldap'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ldap/ldap.container.j2"
diff --git a/ansible/roles/infra/tasks/services/set_loki.yaml b/ansible/roles/infra/tasks/services/set_loki.yaml
index 9910872..e070aa8 100644
--- a/ansible/roles/infra/tasks/services/set_loki.yaml
+++ b/ansible/roles/infra/tasks/services/set_loki.yaml
@@ -48,6 +48,13 @@
notify: "notification_restart_loki"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/grafana/loki"
+ tag: "{{ version['containers']['loki'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/loki/loki.container.j2"
diff --git a/ansible/roles/infra/tasks/services/set_postgresql.yaml b/ansible/roles/infra/tasks/services/set_postgresql.yaml
index e956fb9..ccf872b 100644
--- a/ansible/roles/infra/tasks/services/set_postgresql.yaml
+++ b/ansible/roles/infra/tasks/services/set_postgresql.yaml
@@ -1,19 +1,19 @@
---
+- name: Initialize connected services list
+ ansible.builtin.set_fact:
+ connected_services: []
+
- name: Set connected services list
ansible.builtin.set_fact:
- connected_services:
- - "ldap"
- - "grafana"
- - "authelia"
- - "vaultwarden"
- - "gitea"
- - "immich"
- - "paperless"
- - "nextcloud"
- - "sure"
- - "outline"
- - "memos"
- - "mealie"
+ connected_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.db', 'defined')
+ | selectattr('value.dependency.db', 'equalto', 'postgresql')
+ | map(attribute='key')
+ | list
+ }}
- name: Create postgresql directory
ansible.builtin.file:
@@ -39,6 +39,8 @@
owner: "{{ ansible_user }}"
group: "{{ node['group'] }}"
mode: "0640"
+ register: "is_postgresql_containerfile"
+ notify: "notification_restart_postgresql"
- name: Build postgresql container image
containers.podman.podman_image:
@@ -47,6 +49,7 @@
tag: "pg{{ version['containers']['postgresql'] }}-vectorchord{{ version['containers']['vectorchord'] }}"
state: "build"
path: "{{ node['home_path'] }}/containers/postgresql/build"
+ force: "{{ is_postgresql_containerfile.changed }}"
- name: Prune postgresql dangling images
containers.podman.podman_prune:
@@ -96,16 +99,33 @@
become: true
register: "is_postgresql_init"
+- name: Check init directory empty
+ ansible.builtin.find:
+ path: "{{ node['home_path'] }}/containers/postgresql/init/"
+ file_type: "any"
+ patterns:
+ - "*.sql"
+ become: true
+ register: "is_init_dir_empty"
+
+- name: Check pg_cluster.sql on console
+ delegate_to: "console"
+ ansible.builtin.stat:
+ path: "{{ hostvars['console']['node']['data_path'] }}/sql/postgresql/pg_cluster.sql"
+ register: is_console_pg_cluster_sql
+
- name: Prepare initiating DB
when:
- not is_postgresql_init.stat.exists
+ - is_init_dir_empty.matched == 0
+ - is_console_pg_cluster_sql.stat.exists
- (connected_services | default([]) | length) > 0
become: true
block:
# `init/pg_cluster.sql` should be fetched from postgresql's backup directory before running initiating
- name: Deploy init cluster sql file
ansible.builtin.copy:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/postgresql/init/pg_cluster.sql"
+ src: "{{ hostvars['console']['node']['data_path'] }}/sql/postgresql/pg_cluster.sql"
dest: "{{ node['home_path'] }}/containers/postgresql/init/00_pg_cluster.sql"
owner: "{{ services['postgresql']['subuid'] }}"
group: "{{ node['group'] }}"
@@ -113,7 +133,7 @@
- name: Deploy restoring data sql files
ansible.builtin.copy:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/postgresql/init/pg_{{ item }}.sql"
+ src: "{{ hostvars['console']['node']['data_path'] }}/sql/postgresql/pg_{{ item }}.sql"
dest: "{{ node['home_path'] }}/containers/postgresql/init/{{ '%02d' | format(index_num + 1) }}_pg_{{ item }}.sql"
owner: "{{ services['postgresql']['subuid'] }}"
group: "{{ node['group'] }}"
@@ -192,8 +212,8 @@
{{ domain['internal'] }}_{{ node['name'] }}_postgres_\
pg{{ version['containers']['postgresql'] }}-vectorchord{{ version['containers']['vectorchord'] }}.tar"
format: "oci-archive"
- force: false
- when: not container_archive_images.stat.exists
+ force: "{{ is_postgresql_containerfile.changed }}"
+ when: not container_archive_images.stat.exists or is_postgresql_containerfile.changed
- name: Fetch container archive images
ansible.builtin.fetch:
diff --git a/ansible/roles/infra/tasks/services/set_prometheus.yaml b/ansible/roles/infra/tasks/services/set_prometheus.yaml
index 95df464..1e6094b 100644
--- a/ansible/roles/infra/tasks/services/set_prometheus.yaml
+++ b/ansible/roles/infra/tasks/services/set_prometheus.yaml
@@ -52,6 +52,13 @@
notify: "notification_restart_prometheus"
no_log: true
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/prom/prometheus"
+ tag: "{{ version['containers']['prometheus'] }}"
+ state: "present"
+ pull: true
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/prometheus/prometheus.container.j2"
diff --git a/ansible/roles/infra/tasks/services/set_x509-exporter.yaml b/ansible/roles/infra/tasks/services/set_x509-exporter.yaml
index a1496aa..9989483 100644
--- a/ansible/roles/infra/tasks/services/set_x509-exporter.yaml
+++ b/ansible/roles/infra/tasks/services/set_x509-exporter.yaml
@@ -1,4 +1,20 @@
---
+- name: Initialize self-cert services list
+ ansible.builtin.set_fact:
+ cert_services: []
+
+- name: Set self-cert services list
+ ansible.builtin.set_fact:
+ cert_services: >-
+ {{
+ services
+ | dict2items
+ | selectattr('value.dependency.cert', 'defined')
+ | selectattr('value.dependency.cert', 'equalto', true)
+ | map(attribute='key')
+ | list
+ }}
+
- name: Create x509-exporter directory
ansible.builtin.file:
path: "{{ node['home_path'] }}/containers/{{ item }}"
@@ -22,7 +38,7 @@
become: true
notify: "notification_restart_x509-exporter"
-- name: Deploy certificates
+- name: Deploy CA certificates
ansible.builtin.copy:
content: |
{{ item.value }}
@@ -35,23 +51,31 @@
value: "{{ hostvars['console']['ca']['root']['crt'] }}"
- name: "intermediate.crt"
value: "{{ hostvars['console']['ca']['intermediate']['crt'] }}"
- - name: "crowdsec.crt"
- value: "{{ hostvars['console']['crowdsec']['crt'] }}"
- - name: "blocky.crt"
- value: "{{ hostvars['console']['blocky']['crt'] }}"
- - name: "postgresql.crt"
- value: "{{ hostvars['console']['postgresql']['crt'] }}"
- - name: "ldap.crt"
- value: "{{ hostvars['console']['ldap']['crt'] }}"
- - name: "prometheus.crt"
- value: "{{ hostvars['console']['prometheus']['crt'] }}"
- - name: "loki.crt"
- value: "{{ hostvars['console']['loki']['crt'] }}"
- - name: "dsm.crt"
- value: "{{ hostvars['console']['dsm']['crt'] }}"
become: true
+ notify: "notification_restart_x509-exporter"
no_log: true
+- name: Deploy leaf certificates
+ ansible.builtin.copy:
+ content: |
+ {{ hostvars['console'][item]['crt'] }}
+ dest: "{{ node['home_path'] }}/containers/x509-exporter/certs/{{ item }}.crt"
+ owner: "{{ services['x509-exporter']['subuid'] }}"
+ group: "{{ node['group'] }}"
+ mode: "0440"
+ loop: "{{ cert_services }}"
+ become: true
+ notify: "notification_restart_x509-exporter"
+ no_log: true
+
+- name: Pull image
+ containers.podman.podman_image:
+ name: "docker.io/enix/x509-certificate-exporter"
+ tag: "{{ version['containers']['x509-exporter'] }}"
+ state: "present"
+ pull: true
+
+
- name: Deploy container file
ansible.builtin.template:
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/x509-exporter/x509-exporter.container.j2"
diff --git a/ansible/roles/vmm/tasks/node/set_disk.yaml b/ansible/roles/vmm/tasks/node/set_disk.yaml
new file mode 100644
index 0000000..a2d6b08
--- /dev/null
+++ b/ansible/roles/vmm/tasks/node/set_disk.yaml
@@ -0,0 +1,179 @@
+---
+- name: Check btrfs installation
+ ansible.builtin.shell: |
+ command -v btrfs
+ become: true # btrfs is located in /usr/sbin, which means root permission is needed.
+ changed_when: false
+ failed_when: false
+ register: "is_btrfs_installed"
+
+- name: Install btrfs
+ ansible.builtin.apt:
+ name: "btrfs-progs"
+ state: "present"
+ become: true
+ when: is_btrfs_installed.rc != 0
+
+- name: Mount data disk
+ block:
+ - name: Set hard data disk path
+ ansible.builtin.shell: |
+ set -o pipefail
+ ls -1 /dev/disk/by-id/ata-* | \
+ grep -F -e "{{ hardware['disk']['data']['serials'] | join('" -e "') }}" | \
+ grep -vE -- '-part[0-9]+$' | \
+ sort
+ changed_when: false
+ register: "data_disk_path"
+
+ - name: Check vmm_hdd filesystem already exists
+ ansible.builtin.command: |
+ blkid -L {{ hardware['disk']['data']['fs']['label'] }}
+ become: true
+ changed_when: false
+ failed_when: false
+ register: "is_data_disk_fs"
+
+ - name: Check disk number
+ ansible.builtin.fail:
+ msg: "Below 4 disks for RAID10, found {{ data_disk_path.stdout_lines | length }}"
+ when: (data_disk_path.stdout_lines | length) < hardware['disk']['data']['fs']['btrfs']['min_devices']
+
+ - name: Set btrfs raid10 volume
+ ansible.builtin.shell: |
+ mkfs.btrfs -f \
+ -L {{ hardware['disk']['data']['fs']['label'] }} \
+ -d {{ hardware['disk']['data']['fs']['btrfs']['data_profile'] }} \
+ -m {{ hardware['disk']['data']['fs']['btrfs']['metadata_profile'] }} \
+ {{ data_disk_path.stdout_lines | join(' ') }}
+ become: true
+ when:
+ - is_data_disk_fs.rc != 0
+ - (data_disk_path.stdout_lines | length) >= hardware['disk']['data']['fs']['btrfs']['min_devices']
+ changed_when: is_mkfs.rc == 0
+ register: "is_mkfs"
+
+ - name: Create mount volume
+ ansible.builtin.file:
+ path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
+ state: "directory"
+ owner: "root"
+ group: "root"
+ mode: "0711"
+ become: true
+
+ - name: Mount btrfs raid10 volume
+ ansible.posix.mount:
+ path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
+ src: "LABEL={{ hardware['disk']['data']['fs']['label'] }}"
+ state: "mounted"
+ fstype: "{{ hardware['disk']['data']['fs']['type'] }}"
+ opts: "{{ hardware['disk']['data']['fs']['mount_opts'] | join(',') }}"
+ become: true
+
+ - name: Set mounted btrfs volume permissions
+ ansible.builtin.file:
+ path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
+ state: "directory"
+ owner: "root"
+ group: "root"
+ mode: "0711"
+ become: true
+
+- name: Mount backup disk
+ block:
+ - name: Set backup disk path
+ ansible.builtin.shell: |
+ set -o pipefail
+ ls -1 /dev/disk/by-id/ata-* | \
+ grep -F -e "{{ hardware['disk']['backup']['serials'] | join('" -e "') }}" | \
+ grep -vE -- '-part[0-9]+$' | \
+ sort
+ changed_when: false
+ register: "backup_disk_path"
+
+ - name: Check vmm_hdd filesystem already exists
+ ansible.builtin.command: |
+ blkid -L {{ hardware['disk']['backup']['fs']['label'] }}
+ become: true
+ changed_when: false
+ failed_when: false
+ register: "is_backup_disk_fs"
+
+ - name: Set btrfs volume
+ ansible.builtin.shell: |
+ mkfs.btrfs -f \
+ -L {{ hardware['disk']['backup']['fs']['label'] }} \
+ -d {{ hardware['disk']['backup']['fs']['btrfs']['data_profile'] }} \
+ -m {{ hardware['disk']['backup']['fs']['btrfs']['metadata_profile'] }} \
+ {{ backup_disk_path.stdout_lines | join(' ') }}
+ become: true
+ when:
+ - is_backup_disk_fs.rc != 0
+ - (backup_disk_path.stdout_lines | length) >= hardware['disk']['backup']['fs']['btrfs']['min_devices']
+ changed_when: is_mkfs.rc == 0
+ register: "is_mkfs"
+
+ - name: Create mount volume
+ ansible.builtin.file:
+ path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
+ state: "directory"
+ owner: "root"
+ group: "root"
+ mode: "0711"
+ become: true
+
+ - name: Mount btrfs volume
+ ansible.posix.mount:
+ path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
+ src: "LABEL={{ hardware['disk']['backup']['fs']['label'] }}"
+ state: "mounted"
+ fstype: "{{ hardware['disk']['backup']['fs']['type'] }}"
+ opts: "{{ hardware['disk']['backup']['fs']['mount_opts'] | join(',') }}"
+ become: true
+
+ - name: Set mounted btrfs volume permissions
+ ansible.builtin.file:
+ path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
+ state: "directory"
+ owner: "root"
+ group: "root"
+ mode: "0711"
+ become: true
+
+- name: Verify data disk is mounted
+ ansible.builtin.command: |
+ mountpoint -q {{ hardware['disk']['data']['fs']['mount_point'] }}
+ become: true
+ changed_when: false
+
+- name: Verify backup disk is mounted
+ ansible.builtin.command: |
+ mountpoint -q {{ hardware['disk']['backup']['fs']['mount_point'] }}
+ become: true
+ changed_when: false
+
+- name: Deploy btrfs scrub service and timer
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/btrfs/btrfs-scrub-{{ item }}.j2"
+ dest: "/etc/systemd/system/btrfs-scrub-{{ item }}"
+ owner: "root"
+ group: "root"
+ mode: "0644"
+ loop:
+ - "data.service"
+ - "data.timer"
+ - "backup.service"
+ - "backup.timer"
+ become: true
+
+- name: Enable auto btrfs scrub
+ ansible.builtin.systemd:
+ name: "btrfs-scrub-{{ item }}.timer"
+ state: "started"
+ enabled: true
+ daemon_reload: true
+ loop:
+ - "data"
+ - "backup"
+ become: true
diff --git a/ansible/roles/vmm/tasks/node/set_libvirt.yaml b/ansible/roles/vmm/tasks/node/set_libvirt.yaml
index f3ca54c..bf57366 100644
--- a/ansible/roles/vmm/tasks/node/set_libvirt.yaml
+++ b/ansible/roles/vmm/tasks/node/set_libvirt.yaml
@@ -13,7 +13,9 @@
loop:
- "images"
- "seeds"
- - "data"
+ - "disk"
+ - "disk/data"
+ - "disk/backup"
register: "is_libvirt_dir"
- name: Create libvirt directory
@@ -26,7 +28,6 @@
loop: "{{ is_libvirt_dir.results }}"
when: not item.stat.exists
become: true
- no_log: true
- name: Set LIBVIRT_DEFAULT_URI
ansible.builtin.lineinfile:
@@ -74,6 +75,7 @@
- "images-pool"
- "seeds-pool"
- "data-pool"
+ - "backup-pool"
- name: Start virtual storage pool
community.libvirt.virt_pool:
@@ -84,6 +86,7 @@
- "images-pool"
- "seeds-pool"
- "data-pool"
+ - "backup-pool"
- name: Autostart virtual storage pool
community.libvirt.virt_pool:
@@ -94,3 +97,4 @@
- "images-pool"
- "seeds-pool"
- "data-pool"
+ - "backup-pool"
diff --git a/ansible/roles/vmm/tasks/node/set_raid.yaml b/ansible/roles/vmm/tasks/node/set_raid.yaml
deleted file mode 100644
index c4f0ccb..0000000
--- a/ansible/roles/vmm/tasks/node/set_raid.yaml
+++ /dev/null
@@ -1,100 +0,0 @@
----
-- name: Check btrfs installation
- ansible.builtin.shell: |
- command -v btrfs
- become: true # btrfs is located in /usr/sbin, which means root permission is needed.
- changed_when: false
- failed_when: false
- register: "is_btrfs_installed"
- ignore_errors: true
-
-- name: Install btrfs
- ansible.builtin.apt:
- name: "btrfs-progs"
- state: "present"
- become: true
- when: is_btrfs_installed.rc != 0
-
-- name: Set hard disk path
- ansible.builtin.shell: |
- set -o pipefail
- ls -1 /dev/disk/by-id/ata-* | \
- grep -F -e "{{ hardware['hdd']['data'].values() | join('" -e "') }}" | \
- grep -vE -- '-part[0-9]+$' | \
- sort
- changed_when: false
- register: "hdd_path_list"
-
-- name: Check vmm_hdd filesystem already exists
- ansible.builtin.command: |
- blkid -L {{ hardware['btrfs']['label'] }}
- register: is_vmm_data
- changed_when: false
- failed_when: false
- become: true
-
-- name: Check disk number
- ansible.builtin.fail:
- msg: "Below 4 disks for RAID10, found {{ hdd_path_list.stdout_lines | length }}"
- when: (hdd_path_list.stdout_lines | length) < 4
-
-- name: Set btrfs raid10 volume
- ansible.builtin.shell: |
- mkfs.btrfs -f \
- -L {{ hardware['btrfs']['label'] }} \
- -d {{ hardware['btrfs']['level'] }} \
- -m {{ hardware['btrfs']['level'] }} \
- {{ hdd_path_list.stdout_lines | join(' ') }}
- become: true
- when:
- - is_vmm_data.rc != 0
- - (hdd_path_list.stdout_lines | length) >= 4
- changed_when: is_mkfs.rc == 0
- register: "is_mkfs"
-
-- name: Create mount volume
- ansible.builtin.file:
- path: "{{ hardware['btrfs']['mount_point'] }}"
- state: "directory"
- owner: "root"
- group: "root"
- mode: "0711"
- become: true
-
-- name: Mount btrfs raid10 volume
- ansible.posix.mount:
- path: "{{ hardware['btrfs']['mount_point'] }}"
- src: "LABEL={{ hardware['btrfs']['label'] }}"
- state: "mounted"
- fstype: "btrfs"
- opts: "defaults,noatime,nodatacow,degraded,nofail"
- become: true
-
-- name: Set mounted btrfs volume permissions
- ansible.builtin.file:
- path: "{{ hardware['btrfs']['mount_point'] }}"
- state: "directory"
- owner: "root"
- group: "root"
- mode: "0711"
- become: true
-
-- name: Deploy btrfs scrub service and timer
- ansible.builtin.template:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/btrfs/{{ item }}.j2"
- dest: "/etc/systemd/system/{{ item }}"
- owner: "root"
- group: "root"
- mode: "0644"
- loop:
- - "btrfs-scrub.service"
- - "btrfs-scrub.timer"
- become: true
-
-- name: Enable auto btrfs scrub
- ansible.builtin.systemd:
- name: "btrfs-scrub.timer"
- state: "started"
- enabled: true
- daemon_reload: true
- become: true
diff --git a/ansible/roles/vmm/tasks/vm/create_seed.yaml b/ansible/roles/vmm/tasks/vm/create_seed.yaml
index f5c2135..277062a 100644
--- a/ansible/roles/vmm/tasks/vm/create_seed.yaml
+++ b/ansible/roles/vmm/tasks/vm/create_seed.yaml
@@ -49,8 +49,7 @@
register: "is_seediso"
- name: Create seed.iso
- ansible.builtin.shell:
- cmd: |
+ ansible.builtin.shell: |
cloud-localds -N {{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/network-config \
{{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/seed.iso \
{{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/user-data \
diff --git a/ansible/roles/vmm/tasks/vm/deploy_vm_init.yaml b/ansible/roles/vmm/tasks/vm/deploy_vm_init.yaml
index 0536c3d..103d7cd 100644
--- a/ansible/roles/vmm/tasks/vm/deploy_vm_init.yaml
+++ b/ansible/roles/vmm/tasks/vm/deploy_vm_init.yaml
@@ -28,8 +28,8 @@
become: true
- name: Check deployed cloud-init file info
- ansible.builtin.command:
- cmd: "qemu-img info {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 --output json"
+ ansible.builtin.command: |
+ qemu-img info {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 --output json
changed_when: false
failed_when:
- deployed_cloudfile_info.rc != 0
@@ -37,29 +37,29 @@
register: "deployed_cloudfile_info"
- name: Resize deployed cloud-init file
- ansible.builtin.command:
- cmd: "qemu-img resize {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 {{ hostvars[target_vm]['vm']['storage'] }}G"
+ ansible.builtin.command: |
+ qemu-img resize {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 {{ hostvars[target_vm]['vm']['storage'] }}G
when:
- deployed_cloudfile_info.rc == 0
- (deployed_cloudfile_info.stdout | from_json)['virtual-size'] < (hostvars[target_vm]['vm']['storage'] | int * 1024 * 1024 * 1024)
changed_when: true
-- name: Check app data raw image
+- name: Check bk/app raw image
ansible.builtin.stat:
- path: "{{ hardware['btrfs']['mount_point'] }}/{{ target_vm }}.raw"
+ path: "{{ hardware['disk'][hostvars[target_vm]['vm']['data_storage']['pool']]['fs']['mount_point'] }}/{{ target_vm }}.raw"
get_checksum: false
get_mime: false
get_attributes: false
- when: target_vm == "app"
+ when: target_vm in ["bk", "app"]
register: "is_app_data"
-- name: Create app data raw image
- ansible.builtin.command:
- # 3.5T
- cmd: "qemu-img create -f raw {{ hardware['btrfs']['mount_point'] }}/{{ target_vm }}.raw {{ hostvars[target_vm]['vm']['data_storage']['size'] }}T"
+- name: Create bk/app raw image
+ ansible.builtin.command: |
+ qemu-img create -f raw {{ hardware['disk'][hostvars[target_vm]['vm']['data_storage']['pool']]['fs']['mount_point'] }}/{{ target_vm }}.raw \
+ {{ hostvars[target_vm]['vm']['data_storage']['size'] }}T
become: true
when:
- - target_vm == "app"
+ - target_vm in ["bk", "app"]
- not is_app_data.stat.exists
changed_when: true
diff --git a/ansible/roles/vmm/tasks/vm/register_vm.yaml b/ansible/roles/vmm/tasks/vm/register_vm.yaml
index 1d0f6af..5456b6b 100644
--- a/ansible/roles/vmm/tasks/vm/register_vm.yaml
+++ b/ansible/roles/vmm/tasks/vm/register_vm.yaml
@@ -8,11 +8,11 @@
command: define
- name: Deploy VM systemd file
- ansible.builtin.copy:
- src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/libvirt/services/{{ target_vm }}.service"
+ ansible.builtin.template:
+ src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/libvirt/services/{{ target_vm }}.service.j2"
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ target_vm }}.service"
owner: "{{ ansible_user }}"
- group: "svadmins"
+ group: "{{ node['group'] }}"
mode: "0400"
- name: Register VM service
diff --git a/config/node/bk/nftables.conf.j2 b/config/node/bk/nftables.conf.j2
new file mode 100644
index 0000000..5b403ba
--- /dev/null
+++ b/config/node/bk/nftables.conf.j2
@@ -0,0 +1,48 @@
+#!/usr/sbin/nft -f
+flush ruleset
+
+define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
+define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
+define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
+define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
+define HOSTS4_INFRA = {{ hostvars['fw']['network4']['infra']['server'] }}
+define HOSTS6_INFRA = {{ hostvars['fw']['network6']['infra']['server'] }}
+define HOSTS4_APP = {{ hostvars['fw']['network4']['app']['server'] }}
+define HOSTS6_APP = {{ hostvars['fw']['network6']['app']['server'] }}
+define PORTS_SSH = 22
+define PORTS_HTTPS = 443
+define PORTS_KOPIA = {{ services['kopia']['ports']['https'] }}
+
+table inet nat {
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ tcp dport $PORTS_HTTPS dnat to :$PORTS_KOPIA comment "dnat https ports to $PORTS_KOPIA"
+ }
+ chain postrouting {
+
+ }
+ chain output {
+ type nat hook output priority dstnat; policy accept;
+ oifname "lo" tcp dport $PORTS_HTTPS dnat to :$PORTS_KOPIA comment "dnat https ports to $PORTS_KOPIA out of LOCALHOST"
+ }
+}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 0; policy drop;
+ ct state invalid drop comment "deny invalid connection"
+ ct state established, related accept comment "allow all connection already existing"
+ iifname "lo" accept comment "allow local connection: BK > BK"
+ meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection: BK"
+ ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > BK"
+ ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > BK"
+ ip saddr { $HOSTS4_CONSOLE, $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_KOPIA ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: > BK"
+ ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_KOPIA ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: > BK"
+ }
+ chain forward {
+ type filter hook forward priority 0; policy drop;
+ }
+ chain output {
+ type filter hook output priority 0; policy accept;
+ }
+}
diff --git a/config/node/common/hosts.j2 b/config/node/common/hosts.j2
index 2d07a90..4d06e61 100644
--- a/config/node/common/hosts.j2
+++ b/config/node/common/hosts.j2
@@ -4,6 +4,7 @@
{% if node['name'] == 'console' %}
# Hosts IPv4
{{ hostvars['fw']['network4']['firewall']['server'] }} fw.{{ domain['internal'] }}
+{{ hostvars['fw']['network4']['bk']['server'] }} bk.{{ domain['internal'] }} kopia.{{ domain['internal'] }}
{{ hostvars['fw']['network4']['vmm']['client'] }} init.vmm.{{ domain['internal'] }}
{{ hostvars['fw']['network4']['vmm']['server'] }} vmm.{{ domain['internal'] }}
{{ hostvars['fw']['network4']['infra']['server'] }} infra.{{ domain['internal'] }}
@@ -11,14 +12,12 @@
{{ hostvars['fw']['network4']['app']['server'] }} app.{{ domain['internal'] }}
# Hosts IPv6
{{ hostvars['fw']['network6']['firewall']['server'] }} fw.{{ domain['internal'] }}
+{{ hostvars['fw']['network6']['bk']['server'] }} bk.{{ domain['internal'] }} kopia.{{ domain['internal'] }}
{{ hostvars['fw']['network6']['vmm']['client'] }} init.vmm.{{ domain['internal'] }}
{{ hostvars['fw']['network6']['vmm']['server'] }} vmm.{{ domain['internal'] }}
{{ hostvars['fw']['network6']['infra']['server'] }} infra.{{ domain['internal'] }}
{{ hostvars['fw']['network6']['auth']['server'] }} auth.{{ domain['internal'] }}
{{ hostvars['fw']['network6']['app']['server'] }} app.{{ domain['internal'] }}
-# kopia repository
-{{ hostvars['fw']['network4']['nas']['client'] }} nas.{{ domain['internal'] }}
-{{ hostvars['fw']['network6']['nas']['client'] }} nas.{{ domain['internal'] }}
{% else %}
# IPv4
# Crowdsec, blocky, bind(fw)
diff --git a/config/node/common/resolved/global.conf.j2 b/config/node/common/resolved/global.conf.j2
index 8c1bfbc..4f855aa 100644
--- a/config/node/common/resolved/global.conf.j2
+++ b/config/node/common/resolved/global.conf.j2
@@ -1,6 +1,6 @@
[Resolve]
-{% if node['name'] in ['vmm', 'fw'] %}
+{% if node['name'] in ["vmm", "fw"] %}
DNS=1.1.1.2 1.0.0.2
DNS=2606:4700:4700::1112 2606:4700:4700::1002
{% endif %}
-cache=false
+Cache=false
diff --git a/config/node/common/timesyncd/local-ntp.conf b/config/node/common/timesyncd/local-ntp.conf.j2
similarity index 100%
rename from config/node/common/timesyncd/local-ntp.conf
rename to config/node/common/timesyncd/local-ntp.conf.j2
diff --git a/config/node/fw/nftables.conf.j2 b/config/node/fw/nftables.conf.j2
index dc9299b..e2c6161 100644
--- a/config/node/fw/nftables.conf.j2
+++ b/config/node/fw/nftables.conf.j2
@@ -26,10 +26,11 @@ define HOSTS4_BLOCKY = {{ hostvars['fw']['network4']['blocky']['server'] }}
define HOSTS4_BIND = {{ hostvars['fw']['network4']['bind']['server'] }}
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
define HOSTS4_VMM = { {{ hostvars['fw']['network4']['vmm'].values() | join(', ') }} }
+define HOSTS4_BK = {{ hostvars['fw']['network4']['bk']['server'] }}
define HOSTS4_INFRA = {{ hostvars['fw']['network4']['infra']['server'] }}
define HOSTS4_AUTH = {{ hostvars['fw']['network4']['auth']['server'] }}
define HOSTS4_APP = {{ hostvars['fw']['network4']['app']['server'] }}
-define HOSTS4_NAS = {{ hostvars['fw']['network4']['nas']['client'] }}
+define HOSTS4_SWITCH = {{ hostvars['fw']['network4']['switch']['client'] }}
define HOSTS4_PRINTER = {{ hostvars['fw']['network4']['printer']['client'] }}
define HOSTS6_FW = { {{ hostvars['fw']['network6']['firewall'].values() | join(', ') }} }
@@ -37,10 +38,10 @@ define HOSTS6_BLOCKY = {{ hostvars['fw']['network6']['blocky']['server'] }}
define HOSTS6_BIND = {{ hostvars['fw']['network6']['bind']['server'] }}
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
define HOSTS6_VMM = { {{ hostvars['fw']['network6']['vmm'].values() | join(', ') }} }
+define HOSTS6_BK = {{ hostvars['fw']['network6']['bk']['server'] }}
define HOSTS6_INFRA = {{ hostvars['fw']['network6']['infra']['server'] }}
define HOSTS6_AUTH = {{ hostvars['fw']['network6']['auth']['server'] }}
define HOSTS6_APP = {{ hostvars['fw']['network6']['app']['server'] }}
-define HOSTS6_NAS = {{ hostvars['fw']['network6']['nas']['client'] }}
define PORTS_SSH = 22
define PORTS_WEB = { 80, 443 }
@@ -50,7 +51,6 @@ define PORTS_NTP = 123
define PORTS_VPN = 11290
define PORTS_CROWDSEC = 8080
define PORTS_NAS = { 5000, 5001 }
-define PORTS_KOPIA = 51515
table inet nat {
chain prerouting {
@@ -114,12 +114,12 @@ table inet filter {
iifname "lo" accept comment "allow local connection: FW > FW"
udp dport $PORTS_VPN accept comment "allow vpn connection: > FW"
iifname { $IF_CLIENT, $IF_SERVER, $IF_USER, $IF_WG } meta l4proto { icmp, icmpv6 } accept comment "allow icmp, icmpv6 connection: CLIENT/SERVER/USER/WG > FW"
- iifname { $IF_CLIENT, $IF_SERVER, $IF_WG } udp dport $PORTS_NTP accept comment "allow ntp connection: CLIENT/SERVER/USER/WG > FW"
+ iifname { $IF_CLIENT, $IF_SERVER, $IF_WG } udp dport $PORTS_NTP accept comment "allow ntp connection: CLIENT/SERVER/WG > FW"
# Global chain contains "WAN !> :SSH_PORT"
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW"
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW"
- ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv4 crowdsec lapi connection: SERVER > FW"
- ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv6 crowdsec lapi connection: SERVER > FW"
+ ip saddr { $HOSTS4_VMM, $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv4 crowdsec lapi connection: SERVER > FW"
+ ip6 saddr { $HOSTS6_VMM, $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv6 crowdsec lapi connection: SERVER > FW"
# Global chain contains "WAN !> :DNS_PORT"
ip daddr $HOSTS4_BLOCKY udp dport $PORTS_DNS accept comment "allow ipv4 udp dns connection: !WAN > SERVER BLOCKY(FW)"
ip daddr $HOSTS4_BLOCKY tcp dport $PORTS_DNS accept comment "allow ipv4 tcp dns connection: !WAN > SERVER BLOCKY(FW)"
@@ -140,15 +140,12 @@ table inet filter {
# SSH connection
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW >"
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW >"
- # Reverse proxy (WAN)
+ # Reverse proxy for all
oifname $IF_SERVER ip daddr $HOSTS4_AUTH tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: > FW > SERVER AUTH"
oifname $IF_SERVER ip6 daddr $HOSTS6_AUTH tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: > FW > SERVER AUTH"
- # Reverse proxy (SERVER)
- oifname $IF_SERVER ip saddr $HOSTS4_CONSOLE ip daddr { $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: CONSOLE > FW > SERVER INFRA/APP"
- oifname $IF_SERVER ip6 saddr $HOSTS6_CONSOLE ip6 daddr { $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: CONSOLE > FW > SERVER INFRA/APP"
- # Kopia/NAS Console > NAS
- oifname $IF_CLIENT ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv4 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
- oifname $IF_CLIENT ip6 saddr $HOSTS6_CONSOLE ip6 daddr $HOSTS6_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv6 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
+ # Reverse proxy (SERVER) and Kopia (SERVER) for CONSOLE
+ oifname $IF_SERVER ip saddr $HOSTS4_CONSOLE ip daddr { $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: CONSOLE > FW > SERVER BK/INFRA/APP"
+ oifname $IF_SERVER ip6 saddr $HOSTS6_CONSOLE ip6 daddr { $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: CONSOLE > FW > SERVER BK/INFRA/APP"
# Printer
oifname $IF_CLIENT ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_PRINTER accept comment "allow ipv4 printer connection: CONSOLE > FW > PRINTER"
@@ -162,19 +159,13 @@ table inet filter {
return
}
chain client {
- oifname $IF_WAN ip saddr { $HOSTS4_CONSOLE, $HOSTS4_NAS } accept comment "allow ipv4 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
- oifname $IF_WAN ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_NAS } accept comment "allow ipv6 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
+ oifname $IF_WAN ip saddr { $HOSTS4_PRINTER, $HOSTS4_SWITCH } drop comment "deny ipv4 internet connection: CLIENT PRINTER/SWITCH !> FW > WAN"
+ oifname $IF_WAN accept comment "allow internet connection: CLIENT > FW > WAN"
return
}
chain server {
- # reverse proxy AUTH > NAS
- oifname $IF_CLIENT ip saddr $HOSTS4_AUTH ip daddr $HOSTS4_NAS tcp dport $PORTS_NAS accept comment "allow ipv4 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
- oifname $IF_CLIENT ip6 saddr $HOSTS6_AUTH ip6 daddr $HOSTS6_NAS tcp dport $PORTS_NAS accept comment "allow ipv6 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
- # Kopia INFRA, APP > NAS
- oifname $IF_CLIENT ip saddr { $HOSTS4_INFRA, $HOSTS4_APP } ip daddr $HOSTS4_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv4 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
- oifname $IF_CLIENT ip6 saddr { $HOSTS6_INFRA, $HOSTS6_APP } ip6 daddr $HOSTS6_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv6 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
- oifname $IF_WAN ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } accept comment "allow ipv4 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
- oifname $IF_WAN ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } accept comment "allow ipv6 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
+ oifname $IF_WAN ip saddr { $HOSTS4_VMM, $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } accept comment "allow ipv4 internet connection: SERVER VMM/BK/INFRA/AUTH/APP > FW > WAN"
+ oifname $IF_WAN ip6 saddr { $HOSTS6_VMM, $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } accept comment "allow ipv6 internet connection: SERVER VMM/BK/INFRA/AUTH/APP > FW > WAN"
return
}
chain user {
diff --git a/config/secrets/secrets.yaml b/config/secrets/secrets.yaml
index ca3f812..f48568f 100644
--- a/config/secrets/secrets.yaml
+++ b/config/secrets/secrets.yaml
@@ -7,11 +7,13 @@ sudo:
console: ENC[AES256_GCM,data:RdvzU4VOU+ww1OVvLanD9KbCYom/yPHQ1DdjUBfG6l9nPHEapYqqvHpr6Oi3nDRfc2n5cR4R40i0DHCh01Eo,iv:X8RxKloim0jsDj8U/aY+rHARtrlTrvwNMqMcTmdPfes=,tag:eaMrWFdyU9jifh3SvBrE+A==,type:str]
vmm: ENC[AES256_GCM,data:CqEAeHMgRkmsFYFGOyHic2TGYXlw/1VO4mMAaPSHqzGDoW6u6Gz29uho9EY=,iv:5fc0LkIQ/gVFTK7YEjnmA5ye2EEyh5/61VvTVarGOQA=,tag:yLwK2HchZvGZBFL4ZnxNaw==,type:str]
fw: ENC[AES256_GCM,data:Iz9zt+M+ug6vxzjMAdGuSBSQ16+JrrXpfbsWUpoA184JEV+nC0xZi4eawLI=,iv:4lbQCgFdo5WzY5vFbn9dbkLN6iCoJNJ/5UXw74qOv7s=,tag:eCRh07yL5/D3Kzh6xgmDWg==,type:str]
+ bk: ENC[AES256_GCM,data:mtpcOaoQzQzweKZG9toTXJ1C2wujyakkEP2axKCNXizKcQX575G42Ye3glU=,iv:SUZJFQbuxUoSB/fyk8NZZplCLG49dIFtnYqcxbXoJsg=,tag:Yy8yF/CwqLZP1cyOrTPJCA==,type:str]
infra: ENC[AES256_GCM,data:2KEo16JyMbcySxkPUA1qvQZP5YnfKlT/lJS8FnFWSoXEL508dwiWslSDPfI=,iv:xLah1BYaNuMlSWUufhdWupzPaXbLVgVwVfXO7dKSCcY=,tag:wqkJdWNf2h5ecSBDf3T8xg==,type:str]
auth: ENC[AES256_GCM,data:Gv73925NEyxQEXmVC3YImOfzj99ZVDH+Jt3iEl0yEN69E/1VeqH67uG5kyQ=,iv:+Dd4kY0nDZIBnB+Ft7e8GD1v9a9NjRjU/QnwnXJLJ/w=,tag:X/hOwq1fxHPPhp5VtENWbw==,type:str]
app: ENC[AES256_GCM,data:/e7LF628qBL1+dPtfqV0myEp9MYBx4s1R6LG+HD9P/7LSsF2qG4eUl885GE=,iv:oU23xu+QTtYbT9/7Z8Q+CrCrpOJXs+Cgstvf8RASEZc=,tag:AvYzJuTKFt+dHm/uca+TGg==,type:str]
hash:
fw: ENC[AES256_GCM,data:cI7ZkkxkNypzTRtChxC0HVp0YxwUHXDlcs+Mm1A2OxuGekr4t2IoXnF3OieQVB8LfjH14iJDhBAQxAjww9O3dsaKy1QQx8zCZ5IabDmBfLEsdhJVGHxTBw6PJHzhlW4+1QAYnxXcWqH6Tg==,iv:s/A8I30BP4PYBf+5lBxBXySx2atYn1MYdclA1Cb/VOY=,tag:tKBs1udztZV0T3/UfAiL5A==,type:str]
+ bk: ENC[AES256_GCM,data:tdZOY/Cyj0leqPpRqOpoudTLW00RQpzREz9gZ+wvwhcKR2tPA7IrDSSaJTt5EOYrfInwBL1x/Zq+JZ4b9+VWW/9+f8JWN0AW8IuCv+5aZ8b2/TKFM95P9a95n+JpkriwPp9Ca0ZQ8BdqpQ==,iv:NCXVJP0ZYQwNo7BmIeyKnHSIcQuUpQmccFLFRYZ+a1k=,tag:avOW/Xyy1tGSJbtp2vlvnw==,type:str]
infra: ENC[AES256_GCM,data:Ifk0g0CZOIzyTeTgSVlOj5J0TsIBNQTtZYsM+MNsZ/BGhNb/NADotrBRwpgK7Lts13TQ9eNZtcm4VgWVyWVIcM2HJ+1hAKMHcgHsOlaZNZa3vbiGS/X6xvD01vFeNWC1P0A7GDsvNS0B0A==,iv:PbwSvKNl4EmLBJ/la3ePx7hzJodtLGn57XvgM3X3xtc=,tag:Qahp1EARyRqmWr2BZ/pLJw==,type:str]
auth: ENC[AES256_GCM,data:ezk7MNsSRkF/dI8YhKB9CX+M8j876cRCkDqx64mZPaYNIWD7/tpbwqSTuTvoFsGJ9ikh3ZbNA4n3qMxMSsWstckHfcSgjUF56Bz9lCRvNqNCk/tDyj5aqxeHPXrbad4lwrgl0dPNFuPqxg==,iv:JEJnP+HnaxaLWpgsVmsLuTcxTMIA28l/ESCDnJcM1oQ=,tag:flDCxuD3L5IEfAX5BGu+YA==,type:str]
app: ENC[AES256_GCM,data:xRr+kc1cvB2BK6DhQZQ21TvsgIgAxAJlWVMM7fbFTn9HObUIuz+a9MROGnduHKe8dp5bOkL97jlwZvk4qT8n51rYp4YvgKU/CQ7n89MqQO248hJp2MRMRWmom9Gh6HlzY4IHeMhceb/oYQ==,iv:BG4tPfwp5Qa9/H0h517fHjaE/ZIMy4vnAAQ4Fvqj2H8=,tag:meE8ZxXB8E4Pi/bS4dKMZA==,type:str]
@@ -25,8 +27,8 @@ ca:
crt: ENC[AES256_GCM,data:t+yAyGjsbGUFfa/3wKqAHVgV15trtFrFHXRgBN5y1iJNXvqsHzdt4OO07o/d8lT2bh/UXZEHQDmx0VW+gKSouVzr+ZF2ENgXAW+d1cWWup7cLW+oC2LOf22gP3js53dGNS4+qRhPTi5M7XZztsAJgaI3+LAiDMoxoZn8jZZ2OKOB2038w8ZHCDGMUmvCMXJkk5u4o9zf8qLggdPk/MoAtQ4g4/5Q/gJsf5v6+ufZbSXnWWfwtBce7FStb3Bg06RIGG3LtDGzBxvMFpDJe3z0bidJtOlYyAJhOZF/knOTUwVlEt/Jhd9KoxRKYCMETj0eKO88bIyxZx9gmli7OuETWRyK+A8Y7xAdAoZxgeDJZjX4kcPsMy3vkGKSGRKDg+FMwX/PGwUDQmG+UyfmGqZUyc5fJWHKI8eY55jZoHR2U47tRvV3DcRlvfq8x1Ror1aMtaHfAYcTtxmhQxaWTBhpEQDMSBfMS85UMtNATQd9FXaIh3L6NB1hXCEa/3Tb03ULjkV9Ij92l041CdVUGhRbgz7iC7gy2aGap8fK4PopuqPeEsz306S1Mc1+FLrBz0Y4+545k+cNcEueKRXkColtdsTGU0JhftF3tXxynmx8W0kGKfG3o12VAN4Q8+yYPvE4XtTNVoJtzPeC+ksCem+w57gIAP+PbSdmnaEjsM/GrfTfGzJzcuCUKVDtSl8jh3B8f7f6dk0GSXftMnofdHlSXcAq3rG8oHoqCzS+k/VMz8o22uqcVHTiE0HKVK9h0jghDkkEYcGyiBsLPMlUxmkBmE8uwA==,iv:FyUTqDvjMajaHljcwnQZ9usEaL46hpvGOjNvIVUTMEA=,tag:K3h0hZfr0yjVhxpaG6bi3Q==,type:str]
password: ENC[AES256_GCM,data:ElXnqYyR9qAiBjPqR0HVsMcknp/qqCsBbs1zLfRVqYHSX68RkNVDWOWhrIo=,iv:xiBAV2J52aQbaA9VxdUvjiYg7JTnQyeuBukTFfDCjig=,tag:lZXVek8TSTcNtcu5VyUMUQ==,type:str]
intermediate:
- key: ENC[AES256_GCM,data:xZB2VgzLgTleX/E27lie9Cy0Ham6iGZtSfmw/wfOqH/h/HBv754uYV5XPQyenj6Mst06WiiNl/gvzCZjNAoLiKPkGWvpWZeUjeclsb3QuWjIIArarjcOaA1XX0wxsizfAZ79FU4qjY+alJlN2EnWgiyYIq/bCdhMorYi9nn3z63Q2CetzDpMILfacv4aUzIqu6iX9sgJ4cwpzlAdl0vs7Q4jUZ1eNu00zb9Lbf3NSFUuafzDNSn4FFJ5H4nFqC/okLtFjfMrWv+XPXKR/EqA77cS2gW0g8bGtpZX51cNGYlIMdXj9Coet5tgj+UG4KzJSMoTFdiXHdR1jFAvmYUcFbX1wtbGtIqK3vKcVT1UBtkxQnj8dURzuetyj21qABR6WfPXVOfgIQrTdG4bUZEw1LZbEYd8w6L57NE=,iv:nspy2dXUIGvuyTkETzMxmeEPh0u4saxc5jHfsUMC93M=,tag:v7mMF2+asasRwqIyTSlgQQ==,type:str]
- crt: ENC[AES256_GCM,data:4RrGKeUS+9oZN08WINaW61C7yGs6Atu/vA/w9GNGhC21wMWHoB3FXl6sxDkNAO+qZn0YhINXW6MF6VvmPh0Lu2nQ5wdLlhsgFat1fXrWcatqvHoD08Q6pWSVTXwN9ZLM038ucOj26Xs4C2mBCl2wddII59YzCKRcXIYoK7GWF3m3x5uWY+sP+8IZ2fQiHEaITFX1hg9tNItmWoRh7gCQ15yec6KTOuM9Ph2HI32oP1Lm4h3fW2SvIcgJqHcFObtequGFXpvZbSedesdR3v+gNVSr5oTVsEGoGwyALt/gGpK3zptTDsavARzsQPUXu3+QILyuNYHXP653g+VnSLMwEMuFdeQJaBeG4TF0Zo76dPuy8lPSawhGK1BJsEgUb++23q87nW/O5UdJsUJ7gIejrQQpH266nq8cw1Thyskypk0TrsMdrTWwOniWOLSUVf+5GZi9mLqNse89Qe9xyJlvocTdpZg7Bl9kDVFjLRO2IC8+r7NqD8PeOjxT8ojJNYXG3iDbdqyQtHtpETjLUN4ZHCo8EOdGIBAqnutV0gAxnKIcran86gtk6QIeYL62x0AgkDDEClCrQMZEOIMbhzPMml+4Y0SdcoA8DErrFiPeufDxak5gNLRJxOT/okOBi5/QK4deJ2Cbx0lSxB79d69Ol9OAKUNW855o/lcGD+Tx3bNXYzN+EaFmpku3Sv8Bvl3QloVQ4832w0bbwcqEoviuB8hDMqsmWXZS8D+cqL9uYZVObRJS8rR8QGPfPkSPy8NePWsuR1vznlyBT35eyRcKwVp+qweDIjHHgAIcSvSAVPoQ3EYT01WCpRPsiTIxh4IbLIYeqImFrb6Vn7S6tMmv3E3eCnuL/LfxiV1t3Q==,iv:bUDkP5wRWEqi9n9QEN9ETHFeWdAiEk8GUwTD4X7asRA=,tag:xYYYPlGQfhcK97tSPtM7dQ==,type:str]
+ key: ENC[AES256_GCM,data:DmzFVd4v7eAMXaTKXCJRJUq5efPOIndVUiuUxHZgS6mqkF3TfC9eaaf1E+cuaLqtjifGjc+j5AuTbNs8S76EV3sB+j9H5e+hiVSsECnrEYMFeOyWTS8Tr2CUjZUWlmvAKFYdqWnR7J9bMyaJwyxJKXSkgAocUQ5Ctd/Fyjacod2H5FTuzaS5XdWTEH1rOFv3lYZSqejjCUXASvbk5v2xEygHi6Y9vBUx8XGHiZs5QGhWAfEN/FJlozmhTOsDrzx37ozZTKnTECYEZZhGuM6oKmPWlSijsZVymFrh2LxSzYGJj5Cr9s6DJsraOuHS4A6K2gxhUNXFF7LSjnUOZxnCq9tleAUUsAwKrFfBaZA+74if2kvNouVo5T9EHnkb2zAbW4K5PFrteqMI+cvzxbsO0iOQkO5sCr+B0XE=,iv:Ip8BUzd/eNeYclMet4MlRhTaQ8Z8i3/nwFmFNp4SjHM=,tag:Ac+cCufRry7vDtKwdeItYQ==,type:str]
+ crt: ENC[AES256_GCM,data:nVzxH8m9/ShlGpfFZjbmP2ViRmm7b15rjXbG7ODwqiiGZE0peXiNs6LimTUZw2H69iEyI77eakW7hGjQbre9T97R1QKwmaQzSb1UNi+bj37B8KncxXxXxoKzCKa0Ebz//caA5xJTcuC8e9VwYwZUzuUJL24OP2QRUHClqZ7RYchyNjiK0ooig1nKqEg/nTpReg6Hz8aoIBBVkOxpOKjF3nFJXMZ96ID5caWU5mWdeO8s/gmAzcpr3HYAhV2HC4urybiP5/+N/jLc84JbnjQJu+5o5EJjkl/8zNrjaJxDr1WRduM2RlH6Gr6LcKiMfi6BVl5gu/W66c+ZjhGXED/uZ6IqRXcuasKe2hTW/QtBtLt+nEwzzkIj0fr+SY1FPjjlqX6tLyF9L1XI6n7bQWydljli4Bavnn5PX1cCwddfyuot5R4Zow4Y9xrEqT7e0dgnwRu/LEDdX2hpVmehK5ysrPyVFkg0GO7WwrqLbs8dGDGuz/cTXiL+LOygitPguSpmnJcBOQYxR3orPYTIk6uJOiV0X4tc1vt3iz5fg5K6OFLM7s+qV71IRXCJ1zLCY/1o4Vi6ADdkpBUheK1VY2QSH6ZftZk6Ti/Hgr+WcPSVzjrvQSqfUakXaB4o5Gbi5Px1jNzqE7/iTbpUYDMNohA91WqEnFu6Bl2OB5lZIo3uBCzzAa/1h/DogOMEwyUa+RQd88U2sDuPATTxnGJIjVYRbFqqFEf4WN1tYFOGA4dMx8mjpJAOOUxbjIJdeMFmErjVGC+ZNf362xO6kWHWcYPwspCNYEnso9+UAPnAPwUakwc8p4ak9oBVGDmXVHCa0hAiK7Hv7prKjcmzZlnnP2DYEy3lmwuCVADm,iv:tHC5Ss9zbm3Uy5leWj4oOcvCBoFXzCUjy0YnQl8TIN0=,tag:WgCzCTwWzuOTRLQpga5g1Q==,type:str]
password: ENC[AES256_GCM,data:aijMXt3hTo19xVChh1gplU8sUQjmX4Y+dSjS69Kw2cEqmEJB/pelihLH96c=,iv:zP1yDLGsbL0sxJq2PF+qe3c8rNT7Knz6vKaGwMVB2xs=,tag:Oazypz0OfAYI/eptqgaINw==,type:str]
acme_key: ENC[AES256_GCM,data:vir3SKMdU8FsZ3fBNoSMrev3vreFG4Vsex7R4hIR7Ty68x9wqsO/YpJSNkw=,iv:e7AqVbmCOkVIaje6xF8QzISU0E3JfyU4GM7/361ybdc=,tag:HC/kMa/jmVqBwCsvR31WHQ==,type:str]
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
@@ -58,6 +60,8 @@ wireguard:
#
#ENC[AES256_GCM,data:+kiy17Z7q3EiPgo4Ykk=,iv:vOi54XHHLNIO9U0ybpU9Cn68Ymj5W4vtQ2OhTkGAmRo=,tag:h3wdCo5UfNGlHqMpeeBf/A==,type:comment]
kopia:
+ key: ENC[AES256_GCM,data:7hdg6CoaIWPmfabk1ANXwn6VfpgGNpHsICeuxYfyiMsTiXF7PYIIl/gVY+bmkwIYUwTJ7Otip9eFKN56bej1qKSw0ukR1ZAB4mVGgazXPMBYoPkFTGE0mPWQbZVtlWlvIW25e6WpLkD7h0D3d+kV4GLK2vSHyNDfGZOQrU2qgd1PM0jgI2/HVcEYOIZ5k8QBDZ4rQjlt6pSkQUs2vO+NJxtqFziH89ONz05EYBpQnhsMC1zUQuiMKC+C0HCtVlRKiHBK0n+35mvxNDfUopX7GwycGenzC4ZZ4ExpfRkqDtZRmKU=,iv:4kI2bbCkq8R+zf8+RYBeC+78+4Rz3bLH5YMnuCFsrUA=,tag:i2YEcZoOhgcNP/LkGeja/g==,type:str]
+ crt: ENC[AES256_GCM,data:8BtSrcSFuJebJIKmLZPx1dspN+IqKAF76ulSZnN3t5PsSnD7sVNem/2wrLqILnH1M++ojzrqH6Y6/YRPPSuWITXgYQjKVmdE4k4C6hSSdsUYxzNgyT9VQRSr2BfVWFXrFWFTHDNQ8zBxA6dbSXm97TbqX85CKKutCB6wmvfIwmyrpfb3bKkJCh6orl+xobHKAKnSx1vyuzFljQc+7nvQwGq3sEiZSswjfS7Mdx+MfDfj0Ge6Fpbfck1mGKmj0MTFHUYGSKMWEShwk9fWBYjhzoDt2fDGRR4EIG9AIC7lO1JHDTjOIjePK0HD5EoOEUEKpXy/iDl8lzVbFudiUFRtg7X73hq05dFV8cb1BXFhjaxv55NrYiTNg6K18h+x5gouiCaGYbSd2CazkiQst2CXlRpNGuqnfEthRTYHZHwO33mI/4S53sZA2rhVD8gj/PheS4uP4aHztLOFBK3yLV4QnjkeUKtkG5SCOd46xg1+rbHrPl8ExWOQAqTJ/2m0GeBcAI+K2jZDdyJpATEWrvdW44jAytEQuzgACIUs8gOMdnEY8f1ck/JqG6OstTnataqvTnYOoKDa4RwrrzjXTP07WCQpBHShSYLFuEf1XhdZSfrFMqAhJjvCTvAvJkfzfC51u4/7wDLiyswtFIEc6rTMZTVXqWsb0Ca8xwsH+4yKUdsBAyWnhwq2ySzfg7ogxS7L9GMKe4b3y4+cmznleafZgq4UdPelT4coEiEFvDOXO/wzEwxzzo875Pqmm28TlTUDQSSDGq3UlGA758YH0UYA0457qjOFSF2kZqVde6KILxVAmu3kO390WXJbLCBd91euwOUvvgGWuu4Iz4PYjhQVXX9DcAHT7tXFGJLzexLjh/vSwYNniy+TgnkDeW7Ivr+mJW3gp8dHTk4Zp/LfeFUi4bnvAcetoAbo7czEGTNVHY6ob3Lw42vWvUk=,iv:d4UcuKoG/ysu0hl8hDPjOD4oDMkboG34Ul2Yh4TM7DY=,tag:tibe0jmza3V/gi2HXqkr9Q==,type:str]
repository: ENC[AES256_GCM,data:16V50bVVtecbF+TJcXHCx46ZPGNMgAhUOA0YbZHVTsCrOWQvTvcK2k8Iq3E=,iv:/wNbrE5GaFiQPNEp8wZ0JehbXkmah/gPm5ywNE6WVVM=,tag:vW82KTKtJ44++tqXON/SYw==,type:str]
users:
console: ENC[AES256_GCM,data:v1QY7h6vMmzYq/PTmnLg3M5Iwc/Ljr/1M3nJGuUJMfPN2ATY+GIMUyhYu+0=,iv:32c4YrZfTiu7sv/c9tDItmAE8G1lvc1sm6JD1GRkYr0=,tag:kj1a32+bMUsRdusadoXDvg==,type:str]
@@ -66,15 +70,26 @@ kopia:
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
+#ENC[AES256_GCM,data:OK1SKcHWst0rO4MCrEU/,iv:1z4/DaZoVTfQtM/dtKUNHjMmv0UDYayyYwv2yoE1YXQ=,tag:2emhffuIuwdlP/xUYk4bbA==,type:comment]
+rclone:
+ google_drive:
+ oidc:
+ id: ENC[AES256_GCM,data:Z4LnW6WMwBbVf1n1sD6GWCQXUSuPe3PcKhSb3aJ7UhtzCaD9DUNn5m/2f+WaTbkv6EhrCDeGrQBnfxoSGvniE8VZ2BltSeDu,iv:CjcP+E4wyOWcghjcSHGPhbKcxfTD97uhVzRTUJVq75U=,tag:TpCr3eApSE2MsanJ5pu72w==,type:str]
+ secret: ENC[AES256_GCM,data:n81fc7PwTP9BSxjplwlf+A7tXhwkToHv6lDuav+fleBMC1o=,iv:ndFJpWINRVCL7wcZZ8KjEgs1YPgR6wtWig+3VR4Okgo=,tag:HGOTF4i5mhA4mr4Xnf0UTA==,type:str]
+ refresh_token: ENC[AES256_GCM,data:EEE8ExDhoBqPNM/t+q07ng0UYTU2AGNJEWL3ydZ5A10yOrHrdjMC0YtblQzlsA6tdkLCemaUZQXz9kEIHfTQr901AQALkfb5C9OoEnlXz579OXhDnuv9BJUi7tv+Hny5z5DEeVm/Fw==,iv:LyTHhKqzmO530zFqB0+dKlgi+/NEE/WaJw1CdMTLFls=,tag:nJVszyqv3kEQ7ehlBDe44w==,type:str]
+#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
+#
+#
#ENC[AES256_GCM,data:gfsEXIOqhoTsiCI4uDjDeEY=,iv:SfJwBdIFY8Z4Nt2CxjuSY8PYKebQvKcg9n2xL3w7rsU=,tag:yrTNPBjrvnxydGK2X32Zlg==,type:comment]
crowdsec:
- key: ENC[AES256_GCM,data:C7bMfJikh20PFQTe7UtP48SDUlSKKDMOul7dt9USZIVKq7LLBJV83vqbOc3xbteqPzwIYqBEndfqypSevpy/cLAPstQXL634fQGbel6trqbCApq/xjucUvnaqRKyUjk/TH3oRP9qXG8XDsgQ1o+I4b4E1alxLljMPN12wd2KIHfDGp+TURcC9DkK+NESIyQMLQg40cBaps1HcxXvg7FB1oJImM6AjqP9iybDfgkCaNAqUHxLyCHJI4rdYFflALHFkorl8jaQTazqWfuSu70x8j5tUJREksOS8arN3YIwXp4UGHQ=,iv:sbF2ZD6xS3Z3EYc6/5m3oKMghkR1q/IDzVwBX0OuTTI=,tag:NIuO8x3rP47oE/Y0EiNOvw==,type:str]
- crt: ENC[AES256_GCM,data:0Olvh8chXMx0tri9NeiWhka/bl5XRwdAQf55EwhVa2kTedETOBIjdgDqdsXhoREhannWK/1cXcxP7vpvRFMt5e06FsmPh8mSuuyRboVs9ys5p8KPYQcnlOZxfBU1J6DzE8Zq/tOf9cpdlcUVpPJ038tI7cokqhBvPGZIR2Q4/2BKWQnL8d0GvQoEfXOpNw63qQDynSvaSs/asfZf7yeYH6v3Tc4tNRBB5nl8sCq8GjTvm4xleRWax9qS0oroB/uY7S+5OCGLtJFo0A4eweOcEwWuqvpGqsOgs6s8bToeaSmPOUgsCQ2abiMtBWnyCxMxMCFNB+79lpByasf1iGRWlrhjQeUpIoWWAWU6oUbd4pMRy+j+rKV1/Cq4wF7cc7kSTh8BlFAK3Yr8DIDppiUUo53utPAl179ZkycNUzHY5Auh/jA9ZU1UZRbtIOBlIN6mVr/Y53EzigtVYlZRQ6aaQFutM8jGBnegfPhp3m+XY2WanYk1GKKj46Wh11g1YqIWVYpk5hlR1RdQoPsgZPf0yChblbdfQ14iRJqw/0pVPBvX6bKS6P2OaDHpCIBSpTE98VSEjXTkK0XU0Mu5YzyUWxIe5/BoRiF9gRFGHEDWwFWprTuFk3eUEaEZ9qoyWr0igmX73Be7y8Bre0jX1xSMjepSLV/0dSUnimhfAvT1TlhwNlxq+FGR0ZMsu8QmbYp1CqLcH93rQxoloHIs2T1+KfKAENwsjm2PshdqmOOoUkzANUmdilYCelkbXyUKXkLqFb8qnSV0jK6hG/ZVeXTzZPnODJ9Tow9bXKdxOwk16XpuMSHjCoIol2E0yD/0YKVBHAnYuz/Uz8Dl/ko//3+OaDD4TudV/nRyy4Ge4JI/kckiovMLma4dJSmADgOAXa+Ao+3N/vfUMF1F1DyRXUXsqHMygtlZZpGiswabq/MrjEvBPomzFWUmu9clWiPJ,iv:SQrBnbzApJscyGuNPE40uKsUdQCf4W73uUwanfyCGbU=,tag:KK+a0tLB+mmn4YWl5Yc0tQ==,type:str]
+ key: ENC[AES256_GCM,data:50i2yh0vkAhAb1tYsU5ijd+QSkCQ/w3Mv4hHubixCmUBx/zR8YwkLCnCdSd+UMTYvm51KvIxN4FsNj0nrbfqBJ6pSoC0UXrxgF4cGRWC+dNtEJyDO+J7yFwp+8lYMO5TqTSqYwxu0RpqEbe5V9p4uYruFwfVY79f3+KGt3nOsktPIw/rpdvD8mlpM48ANi30813miwpAhn/x54QVj21deHxWuzauYI+wmOIPZKgLkLNokX50oq9SCJntuuYLaR8S4B9ji3BPEOS0CX6aanm8Mu4Pl6hnGcmyEXhvlYZWgohp3fI=,iv:0oKtj/PUAznINv3t6K0iJec7/ytqYF218p3XBIZOLZ0=,tag:V4wywnJeEZsf01l2f3LVJQ==,type:str]
+ crt: ENC[AES256_GCM,data:zcnyni/BcXXx+/9F0tBnSqffJhumnv/ob8kNRVdyhx1KU5arwPzhlBh98BBl6dTOy9Eo/pz9UiEmuPs46IqE1QGFb3bmzloq92pxOrkQwxwTPL9WROAHbd148fHmHVa2NC7VBpVuuM5t/3os6vJzdPgYHZC1k23SKKjCHAorqiIDso3ZBHfVJ12fZnEnnIWh/wWyvw4ap3plmkEHZC6zHfMBvH/IAFN6Fzzn9nNmOB54f0xT4cYcActH/lpVxDx3l5KOkM5aKXKbTxzSPUugm2X3rSKZlBgfqPBfA9dWUBqK7bfKIgYETdadP/1K2vJmscnNLPJ4DlZe9R9p/i8hdmx9Ls2xeIk6TOMxpnQ/iXKu2mSVD2L6A8cbid5kTjGEqcl8osQCsyOV8dR68beBFHdQlt/PvJjTKIAGilZPk9U+W9p70RaA9ibQU/WJJxrZvMgpJEMdbq5WLeu2c/TYXWEKyfNrpU3kLgzln+6bBEXEPk1MYWUfQJHqsWeXQzMpALGGNUPys0oaAKvFBlaEEetK8dk7tUcU4M2N6Sxn5+lLE/wSa4ZMMEFDdLEvxbfB7OyChUEzn5fXYZayEAmBgSJlWBkhbXLocfASjzluF4mrBHtSKbIZOnpFtB/mHubgeMZlWVD4FwYwkzoBuLz3quLq1zhBVvJTQDfL5lu3d6CQlGiv/Hl10Fy4Ne9QJ1bpfBaj6Ih+0WuYwtFfjwQdKvO4CZ1C5Fy4E9GiSxRQnixjG3JD/7JwnnmQriPyaWpiYumhwqrVktHcUHu3n7zWBb3P+UFMw0+JsOWaEjU3eg9m/S/z3y0eN8bd//a0fbPuBiakLODaSHbEK6ooKyc7qDzhuQMYBgdxHgC7iBhtMDiqZ2VHVaSigagE3494ObxFXq7Nc/ymWoIjhVoz0hKQ85eQosyiusCjThxT70DaAUOWvDJkDjPP+M123I3UjKT3Lg==,iv:+4LUsHW3T9cdqOQZXq9eEb3gH1VHCXts0jyBV+HMiIU=,tag:+E9sWyUYhzTYwv6f/3KAMA==,type:str]
bouncer:
fw: ENC[AES256_GCM,data:wplc8z6YNuQi7bN6r27wSOmx7alVDWUBgU+pgvnH0exmRhHCHjbS9zX+4P0=,iv:fbBg0AlqOtbKgYjbiSPopJ0QwEryAEXfcc+YaUWI6xI=,tag:Ul5+MwKZyMevBIyvZH/hAQ==,type:str]
caddy: ENC[AES256_GCM,data:fRyTH9/7OZ7oaz2n3o7DtXJCnH5l89fGSZtM3FH8sWzw8Iqj14t/qXsX5Vs=,iv:YQbozgWTmU+facWKeC+2ab2fvm47CwLbrprRiWKDRyg=,tag:Ki3hGXPJ4lWMXJYaDF0kaA==,type:str]
machine:
vmm: ENC[AES256_GCM,data:CF49CU6iwC8LiUMPaGMFMNGjF0n9gpSplnGkkJNk14qEkvYFTgfoUPqc964=,iv:Qi6cTieniO++EltyUkabXqsPAEb0AEmdR1ramlisthI=,tag:G85rEh6STS9pDr1zbuNUdg==,type:str]
+ bk: ENC[AES256_GCM,data:+paUsZrY/lPv6xTcPMCeTOL4aIpTsnNHo1jVL6LyXky8UyDtsrt5xr6xQ0g=,iv:oI4BoR40rZN3jHFCx3jANdyVMAeO2Kt4EonUdIixveo=,tag:x/sHdgx7S0Aus0+QiopEyw==,type:str]
fw: ENC[AES256_GCM,data:uA3AfA394F8b0a2jGjU8ABHvKGNTsZM0O1woQc7gLdHte5Cn8SgfuyNgWu0=,iv:TCZ4NwJuTVPAbiWn6QWM7cRta2uXODHb/41Q1qslJsU=,tag:A7fGrietJuxyEUik3eVZLQ==,type:str]
infra: ENC[AES256_GCM,data:rNpo77YAdoRedzJonScaT6Fhr18+T6u6/bKEzC7PYOIzEpuKh/MqzIS6Np4=,iv:D8QND39D2eqBG0USHhcc2UCxpTSuGn4SCpTCOBO0RAE=,tag:1X8IK8DNsD2m6DdtxMQTyA==,type:str]
auth: ENC[AES256_GCM,data:neUWugEoUU+LrXijmUjd6063pvtyMuvBhiLtKR0BdAqkl126LN776x4cibs=,iv:OSu3S3AQNqk0PRR2kITKgLcniEsNhrNbpPIix3UIwDw=,tag:5OpA77ayasIQAYx7tYFD9Q==,type:str]
@@ -97,15 +112,15 @@ bind:
#
#ENC[AES256_GCM,data:FNnIRyidUh2urEgGgM85,iv:w6Z7/VLY9BtH4CNqchc/3GkWb4ez2Nb0TxdZF6RdND4=,tag:14vEc2qpBoOApdnci8ZTug==,type:comment]
blocky:
- key: ENC[AES256_GCM,data:3hIpfdbwUzIvFhhVOl9TYoLvVLtFS0jdKSC9FGT2dSmYJP9f0qqrKEtH9+52GF3YUXvf0fkPoqAxxDf3iNh2ynAS7PMBOth3LS5mnY+NpRCZuod8PkyQOWCzkAeVla/JeAD3n3da4f8layWHY47u37XgeojQpyijCWKifEnpbjJdXVBKi440mSaFaORgDJkvSMRGcgF1o1HWz8/YricUIfv3xniQA3Ke8gg4/L9gHHFAqAZiKUBDDppHzuY5ua82FDWTgipPtoNdi+9xyeTmNdunrVAF3OrHwkNQqfLJrGOfrhU=,iv:TGbO2lfqjnsu6ZzcO5qAeQKSgE5qr2lQZi+3YuAlAGs=,tag:tE8bTnPpBXwDXYyB9YsOPA==,type:str]
- crt: ENC[AES256_GCM,data:vvT9evMqMW8isY3N0tvQCW0XFWIW98vVz0aO0o3habCbLJlB5wjF6TMA1u1xbJ9zQWX8kHTt62BxBngCHXtKFnnVN2q1hNFK/sGFpAJz/WXD/sJW8kHOAv00dwGl2/r1josB9hFmn52omxpryY2h3ZTgqLxoCpzYPoB1LvJzPKo0bS4ig+/qYbAyPe9pNbTmPzGjXutoGbOKXKAQvfZg0YNsR/nbdd0Y5eEdHL+0syH2wEZZ1ZBBNxnd9wiEmRoQHDDkDJ6VHAWfcgZcuX47jKak6LFBAOfj2lVIza78o7MSQsCT1M5DJMZu/K5mV9jJhftljnZ8MB9rX3rFcApHnFX9luLn5b7pHRwieWCNHM71gy3wHS9DFZXjYRpFqFTiXmAxtKxgL3wDIu7M3Ajrc1o1JMlsWMGVUa/InfF73NIMJMKrAPgSWXb4JgwF9HmGjbO5GiSAjRXvuFFmQBArvA7NRn6XFaRyHsig8T/5nQ4t+E0C1HjCkzMFVnUwq5C/3aEJij+cv2YaT5jVTZ5tvX/x0lykMLxd5Psy2Mqvw1++NjS1eOBmg/4q0Pero6zOl+s83fyoSCiXD+K8XHHe24M2IBITABC/Wf4L4yNrwE5S8qn7M6vbFZns1C4BpnIUqbtGeMbAx5reM30nXTWO9pI8Xl5zAPrb4gd7zdl5c6HLge3k8wdNqw2kBD/z4EDCNCPar3g4f1XMhcA1aB3FrHuLvHOkCkCmNbvZ4D4+Nams8HDQ7aNNStshLGt2Rdh8fzQ/KlQslJvgk0oLupnGuZzNWP+TO4tuR4DC/pfX9Uw3+1SDeeTFH/X4iaoSJJxqwC0D3pTvu4SUXilZ+MBE+mDEkB+PbNTuyuFkbUi9OyRFy3W175Mbr9BAdlSIAd70SpUiARqn7k3S5twV5pomxYyOaK+cuAJub/Gp8I0Y102P2rNqcASmA/Ocnogp,iv:m3r2kOi1XUVzLcKo/x9gWT22IDrnOlDYFaGxY2wd6Oo=,tag:6qOgMHBC4mrOTRJ61jhGAQ==,type:str]
+ key: ENC[AES256_GCM,data:6VmmgxShlwwDdfYIr5TOX7uBmnNCambqFVJ8E1FalRUBVr+HFt9cUdVror78UyPwmH6beNI94EC2R06zQmNVxhaSYtt2Ise825jbx2zthm6sP6jVK1PpU33bF9+5VSoDU448ZvQRDyW9bv8Gz1MeKMthzn6LAkg1lE1sZ5lp45QRal3IUw44SXa/pxdc7tn+VcYRMQ3a1oVUTR2kBnqLUw7OdzIZpu9PUcCoVyN28fJmlZnIx23wOfDsCb31VpbDpj9vylVZpqX+clNmwNuh0HcxUdXF6U849XOou/c3bK3WbwE=,iv:V3IiC1Po5+nZmpUsFdcw1aUiPteBXJ9vWJztR4wi+/4=,tag:ucJhuIfnS14bfPixjAB6oQ==,type:str]
+ crt: ENC[AES256_GCM,data:9pxHw0OkY3i3qPPsJnSYgU+u6lDFtboDKpRr4mOgInAmKyMmOB4AOBoQ7KVXzJnS4crzNs96ipYmt+n813VOL2R4G6WVXtuvNra4leSZ5gvtVy4qNQHK7IUSeOu1iqGyMF++bvT9Q6mHBiN/QwylIWJu7LJULn57o2Rfl6akH2zlzgevK2gYC76dji1e9y1jhRY3VnwEhWgOYftDie4Em1StYn2xi4GcO1OuW9lcCggVTi1TruddcoIV9AYbjV3Y30RAKtZiYXnOTvOmsYm0Ea31955k2owxNM+NGwQDs94iZ1c0MG4cV+cxe8aT5xY5+n7ZmKQVsFAlkC+3aHqKxKzr/LUiFAXYoERoU3n/fAGuuP6OPsGMRZTyW1Y9VEsNzpzANWDw3V4QS/6PXqPWxHkW/UbazNu+BD0lfMEUAG6nYx7mAi70LOYwsKqT7pdIs9i7fC5G51cD41keDFnkxfQpBlrMWydravM08Oqj3sgrjnaY5JIdkrwH0g5P6P9d9fhc24iq6VnTC1CxzMU1W5hRHTEebMlJ6DvfGxgS6xTLWbFgzZi1BLY2meU6C0NVkbjIcRd0BQMfo10gS1LDFLZhpr1yqFr7QuGIYi0m+CIE6cGQXJCyzrOt7tQFedKlpy2o0yejdFEHmsx95bNdMvMsXNcw61r0QdrpKaWPShmKtpCWh7oFB8M9XnwzxI4ZKDWnAnP+j2Qp39pKK4mS/lNFqCwJ0mIhE5d4GjDlHA/NkhKYop17ZmxPORsKJ6kB5DSLx4VNTIcQoScH6+X3YU9cx82Betky4VzaGCp9DVZv65tA1dvJqdhROc1xtYr+5ooRc9PrQ4vvKE3rNn5XSR5CqM+udDh5x4okNrF7L9qkL4Z7kmHM51CPpuQl/HavKfsClBNUPcJPz3GtaPB8BvFlUh2NW3mrP6AeRZu90qq5nffMeVwkTcNgpVXv,iv:hjyOmwysUjIyopOeDo6qdD5MrUCnA2byPL5PizqqZCs=,tag:seg+fIrhd5dYrf2jCMloDQ==,type:str]
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
#ENC[AES256_GCM,data:xUxguG12uiQAzJGMXaaqdgTfCw==,iv:kh2nqSVtBXaAhEywAdDPbbG0p2ljX4mtjVKYXCNL20c=,tag:XGaBtxPBHSaLRYZa97+kmw==,type:comment]
postgresql:
- key: ENC[AES256_GCM,data:XCBWU7Y/BG5kOeKqmNpqwyjePWrMzXUW2RUc+d3r8kfTMqVT2Hxe3Hh8qSCilsZOKoeEfraDKCMKBLmmaX/WGXtjnhOF87Y43i11jDPeMv4g0b3f3oh+ekckxG43pFpPUR8/IW3xB3otTdrp7Sw93xh1s6BcYVutL+opOVLwdB6JNlnx6ZAi+ppjmlHxinEa1UpnOkLC0JNIyp0i5xp5KMizNs4iNcduI3eWWZmj1z/lW1Q7dkH6rPIjtNQt0Ce8wpdsuJvPaZHHAZZ31KkSj/6n/sNhSQsgAvJNYBIsqZRG5lw=,iv:/1keHEeQzFuxaZD/Pw51IBIaBy3J/5fK7BcgF+A41Mc=,tag:Cx2AX0sPTwkmHODbuZNu3A==,type:str]
- crt: ENC[AES256_GCM,data:cnvAtbrzS3xpa+RQKhSO72xsPLAiloQZrbUL5asql6Zf2B4aNzepfZa9vlTObd4pG/nw1lIFIY4N1oh+L22j9snDXRX4BX5tANJBCiZrnqhvfDkT97xaK/86D9J6kyWmIYjlQ6bXBkvDhDII0eqigV3A/NDl8V9YApGHyAMuryWB69I4wjvVnlok2HSOgZxq0F/3Epp4hk8BuUTNvAcSeIAfpWePVHYtHRk0X3IT3KhR+Q16Ahm3fqDXFkAhs86NBaCl+kEFunGLyBqxecU8uYuU7gmofISqSDytI5ZGVt+oygHSkcQKrW/NBxY2yYs++8m5N0sLPfmtE8NFIMktpjHrUGEKnZmdUEjg7sFFRGhvpGyo77x8TPC3bD1rZJVgDwYCmKjyCO3VT9jPonV66rVOq5S8svm4pQlaT+BDPZXIqDQn4UHD7grKOdUA+zgvdBuVsUnngR/D34cPPm0Y2x4CLPmz4PBGZQu5Q4sCU+8vq/n8kNX1z2T1K/d40YBPlSunOZIZk6H5XMoy4Njftty2sIjraVy7udYEwqmUwfm9XlYqBa6QeofoxY7BaUrRjVUIcPrKLUZ13qddOoPV//gLtEDwcD37kyLw5ZbPKVdR/5rU48ENvP1UPFC47HDyhtA9/FzYweEZ1jEXSuxr6r5xJVcH5/2eyhW3Eo6ewwWeT26oVPj0zm6faeY6WVPXJX3fhMwNonAtTHzkfZCfFlDgizMtSMsMadzzTut8rlziEea9cuMS0EacIdzafoZgQsYq2ZrRhsYDbQNGAE/DzK3Hkrtp8eqJDNyRyCIsn1+B0A0ci8hADSHPS3q4tQD2JPb5zj6/0PNt0oIIBRcYuXgJW1nathtP718i3Hhi+cmqvZtza7XKUkxNYNYLO9hGnVTNY+mHD8HW94QdAQ8ikfF8tSBv0N4/ebyVIkaS9Nes8MyOQJbzfGhmmpeuo8jineQsf6w=,iv:6gXqS7C8lypzUvjExURswSwnUXG1bTC2+BxUkK0D36w=,tag:cd6URiL6TxM8GxyYirvYDw==,type:str]
+ key: ENC[AES256_GCM,data:Q7B1R5FaFG5sTFE33vKPCxTEE1QaA3uaICSVjWfUKkJPGfqOsvl7JIkwDN2O3UOy6IGXnxlAVUoN3DtH1H55jDDrR0miJHpuEkHn8hSAh2V9iiFjI+DtuliiBdXyQVwlKj3nlAD7stUTBE5oofAYaj43Ijv5BdslcnNOTaFaFo0UvbnehcBAkMnv9YyExto9dCw2ZzOexQs4Lzo2yybCNiTG9t1kJC1LyVcmjxMOSCcay4L+6o02/fJXJ4R/W7EYUYfjWIf8FeC/HVkPsU5TvxA7/uRFUUYro/1hOGkLfPGWDtw=,iv:T84T1dKJD7GPWNz+gPvzWsnebaw7cMjIWimQiIBixmY=,tag:NEvucfSk/ApdGZYB2LbLjA==,type:str]
+ crt: ENC[AES256_GCM,data:JK3XeegWuX8Yr6jiskiQGLpT3tLmVFboCIUmpaikEiV3HXy3dsqeBwONoQO7AB06TWbG9UPKaPbXkMrnARESR560OvSkw8cCLqZSdEyYjvapEbhB68cmLM1ldETQfMWP6O4HXjZQStU2cj3jP7IDmCUiDPfOKosH9dFLpXDyafg5BayDkDjYk57TGhUIg48HGlQfgyGr2xqty/cdLAjVrOHbjJq9hoLHnPyz7Uv5AnqnGZmaRupFHRX2GojAJxJHu7aFacjfg9QeH5KwnfzZeY6umXb/Vq1cIEJdN2v8T9MvDODgweATaBup0LC3kLR2FuhyTn6fdjzFhXQPVCcYsUTYOaVctQm0HfGLRsR5Co63Um04dMHSslhvyx95JNyF/sn/Q2WwJ6famAo8ckdtGFuqX69K/ksI3I5hk2EIwp6DLTUH1LRHa8VoZl089adsLS/fiDGSfUFbzdY/Ki+J5MJHdoRsr0crQv2UXIpqjr68B4jfRBshk4IooJHTrDO/erg+NhC/S4thfPNibsEglowjbbYnz0vtr6pzchtNU/S5BUsL7uYh7vUv+ik/D8/tyLoboVN8dRd+wyCCpNX1sfwubPdobcvdtAjT51liv76VSTDKqY6hkEVuYQeqC5vTAL6xaD53IK/y5yVtwo99wAjj9gpXKw3Q76yAnJiWtd0xZzE7Gly4eKifTDK1zre5KnHmdI4ctktPX6a4w17TXuklQfAyBJWs/416vSYD5FEXFs1C8asPEBslO8DbAna0uGp591r/IBxPi6ulUd5RiQzeVRiEXKvAUFKf+wp/gjbBM1iQ6zVhTe2j+rmg5/AiqpSDFPbz4fAoo0fcjnwT+Y4WMVoaWKF2ml/fzoqB5Ot59TnNfDpwOuhZsImnbKTBL/WDG6B3AqXZozoP2TbJ5sqIm4We0uqAQ71MrfE2IaDvgukrbidcxq5ovxdmimgTSjYM93c=,iv:Ho10WtdWiwxMQqkW3LZcmCce/fCxqtK1L41yG0DPdmY=,tag:zf5yOLzGG1CxlJI/S3ppWg==,type:str]
#ENC[AES256_GCM,data:Zu3CNVkCUlW6BKGh/rhTTqrGv/7H2BG7,iv:vW4cAVvla/Ya0S89DTvo9k3do9517F+AHMLb36Ey19A=,tag:neDpBA97R77p88Im92xn8w==,type:comment]
password:
postgres: ENC[AES256_GCM,data:XlpsKT0/3VgNesMdifvHlYZ2dh7mlMEnxi0MJpQZiQ+1tZ0/3zMxQ7+vwec=,iv:akcPRmDZQfFLxelG7V87UnNB8ez28PPLCmY1MYfzStU=,tag:14jvIKP7Htfh+/oMwLYC2Q==,type:str]
@@ -122,13 +137,14 @@ postgresql:
outline: ENC[AES256_GCM,data:0eJFCfHgS4olWXHOnUPixs4Dl5PoxJa+2H1mk3YgC4GUv+nX8gTPmzKTMVM=,iv:HGxX7aLODUc2nVLC8YXdet9qphU/wxMapWhk93YmHDM=,tag:6/2uckW/a24LgVFRH6E85Q==,type:str]
memos: ENC[AES256_GCM,data:BaNTnZFZH4oMTnDkgrf2/fMTkO43rc9bSsgnDWrHJ/Z6+MZdMitpIMkrMN4=,iv:JsG3B0YweZYO96MW9NmoSsIG++gFq+jRUsozwJtWl3M=,tag:orLTUiW0inOJdD4YSp4baQ==,type:str]
mealie: ENC[AES256_GCM,data:XbYHQv6HBWCXUBRmcbQZN5Y1Gw+V+Wra28Mp+m+ZGl8VRXsKMu5507vGHQM=,iv:zp4ZarqG9KshiBV8F8UksfI2QXmXHwqPw631r/5bYy8=,tag:jvsvXrUsCvpQGIbLV9jTYQ==,type:str]
+ homebox: ENC[AES256_GCM,data:EhNnltOBwLai5vEMt7Dih5Ug6h3ojrdbwhq4Vr0tg/p/0nqI9L7O/Le0B4w=,iv:14oyl916t0inr+W/lztQCjYiSQ0vIIwC9NmbezDuvvY=,tag:IiXZd3NU+dUvDrHpxJXFew==,type:str]
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
#ENC[AES256_GCM,data:VuOcF5INAvCNDvXhcAc=,iv:zdTFTKaII606RjjDJbdUyv8jGba8abL7lJNTsPH5C74=,tag:cYSefZHKIuvHmAzoxierQg==,type:comment]
ldap:
- key: ENC[AES256_GCM,data:OCje8b2x62vVQDV2DXvy28UxY9IIMtRoSLyXVFwNe+sRWA5prW67Vp0XcwwL00nP6hagkXGNRxy0eXx0VYXiktQBeQQe7TC5bUpzJlDCyGmi9BsbDhzShSoSM0v/TxX4UYZ16PbdVxyEIxlD5J/SpbQdg/VvVA6oJgLU4SfZCYmKRZ/gC3I4cKGzFJAT7NLAnC74/Wngz2nE6ipzXiQaDHnSuitLHF/RGoAgE5XyelyXag5wGaB8EAUgmuM8woI5g7RES9885bPOdt/Q1MUNNmEz7jIBH4AVGo8stxRioYmAcZ0=,iv:6Fi0DyvzmrQN+OVclRFZZyXCW8v1nfizj0saGkV7qTY=,tag:AkMtsUaRIgxNKZG1oYPTTg==,type:str]
- crt: ENC[AES256_GCM,data:1SJlTokgS71mW3rEQG1fTLs1cp1Mraww58stg87Bf2PryFsKw88va4HB+bsKzkCRgykQoj8iDSqM7tc7Wze1HWz+bgFTgIqluRQpZtbcmfYVlqefdIUcJPAntqe/eEaA8Hj3ozTNMlKFspv13vPwjSJHGrHcektwlcEI58+S3lhu/IrIfdxryBm97E2UQczznRE3zuP3MiBYUV0oj9Bcm8KWDKqa3DLwudp5wwyw/OG6DGg48isEvNxaMJhuEkiMwMNR+zZXgAvYcYteMaW0p1UXNFHzxMpOWshU1zYL6U9vZkKfpVMoMoTPW3+SO+vxlJVafevStEipUFd48XmOo31uMQH9zWh/hbLM8j/fiTaW+kY89XwkQ9ZUOx8+YXgcfBb04FAbtLEXMbC/eF0meVdjAHv0TEBPF1a/F4m9Kqv1GkJ4RA8jHKFng7vWsRGl7WhmxrCxjrJrYu9ptP7iMvbaaqMWG1YOSwwZUe2HvrM7WTlJxeRukwvW3rOglAUdFODJhsWbATpobuu716fKLqDcprKa+vA5l7VMghqLf7tWRGXmT3O3RgTGDwqjokx0q0+4ib10cgzrRCkwuTBDiLYRdxd2eZFWumLOlKKQyVAMJ9YZmUnH2VNULazcN7Tznpqm3vdA8pC6Em7ELTxYTUvkaye27jRVyilkZvoX8oLiWyEpMpPAajoVntmPnGTF5ppChQ0EmyuFXlv0tsU3K+bxmM5VYVNy4S+1cMOvEwGDuSGJ9nZfS0BFm8NXDp+BbEIAa/DVc6yOjVEwi1Wh0khxbplkW9feWfkLqrdlxF2khNOTePIyEDMzs5/CRq+kzLy0U+7BeyX28jleRpeAQL6nlOZ6Ha3AyQUhxC1/KVOK/kgAlGVi0gyaxZy0yuF4whFKN7+oXB+CrJoCyX3mjrOVqQIOeNIK6tLac3hW/cATu43uDQ==,iv:BmdsX6o02n/ekhnTQrpTUgM3lqXCyQNYtMbexI1Ziho=,tag:7AI4lOFSXDxR7n1zoqcE1g==,type:str]
+ key: ENC[AES256_GCM,data:PwQ/AtsQbbM454iM0wpUjGRfxyxNY5lGDARv/XOdk0yMCHRsf9qHKaW37EwcqNe+MVTJH+sx8lHDdxRYF1gO1yj6kasEIbMeo9cIaGQHvey5dYdber/qUkcjuAXyhSZGSUXI3PR1CuAsiqNUEruh/eKyDZAvHTTY0Rc5jk4HLFzPqqBjBOMkA6VQXJ2I+v4s8W0T8/JEQ5l6avwYbaaInIIY+uPV+sY0mBczAuaHLyeA3V7VQNTxQ9lUgdfH/TpgBn9EBH2wWqIGk2zQ6XmVrmOarCo/+JqwLQVEyY5TTrNuBto=,iv:iYzoRXjH8NjPnX5nBhU2gTQXOekXMirjTGhmpGt3YAs=,tag:IxwtGNXx1i54Jnhn1aZx3w==,type:str]
+ crt: ENC[AES256_GCM,data:ulOZOUV23qfU2RATrXYFKPnPNW2vHShJe3O90XXoSA4bkUBA5Jz8uuAzCiVOZfx/Ni2uG6y5pP2x4ZnJADSrkfHD5P5IF3iUWWSgRo4NDDCY00r+fuPFP5DpOhwHl4LzdiHl8SBJ6YWBbhtT8sXVXFgmQIFLppuUD7WzJ4U2c251vF6G7Q0XemlkkNFq4fbkClTwogUyTRs2Dj0e187uilDkfCBS83oxMU5pB5tBvaFbLxaJmtNpaFRp0U2fgJqJrM7avZJeNUDr1hHttAw/TnANNK3X3mgFAruluTUGTS0dt8KPUlaUCf00I0t1F6l+cNktaTlnUtcp/HdWf0Rtg+tYBfFNgsGl3iB2z1utpab+6WsI2+LZYGezOLKojbFeYGNmVLkSucCSVAtuj48fqKFeObdLcBjihXilI151ie4m5BR+37h1Laob64C/n8lhNSm8QpTuIipV/3koyBKwIimMYYO8j8sHGQNJpdDuZXmYCEiXsdXZH2tFngWtlJ+39yV+GCjhKRYPkAWFKw+EtTSnPposC8fHPMLMZnB1hpsVmSy6VBDuZ2Qq96H+njgzWXIwhWcZteTyxp2fS6dNSG3zTYD2cp9qVrA4KhTlAjVojXdlRAv5Ayob9R89hD3WNKexe3QD/Nj1Hva7GyjEHqHijodYDNXCWsMgXdgItgwUz28vh+H8o5sSHCsfUDM2s7Y4w1rmKOkD4XpxTcyGM5zrNBacvhS1FzuDFYZ8BnN+STaQ1pvscVGtrys6EtXDBfrWbrIFnIhMGSp/GGUMhrT30gPV5VmzUqixRJzpKvYF1ljr8ybRu9Sf4xaprQNeFTTWq2KXonwK8JonbZJNwQQ6oDbp7AyuQD4EJD8GoXJUAy9H5TjnpjJsZH+RsTR6O19K+O45HQCqvZpEHfUUXu022VqrjmzRHnmB4bJKgb+BqE6YpQ==,iv:Vh9eqEun0E73s57RV53rHbjP5AWXn4NPjlEPwVDQ5VY=,tag:fxpzhMHk8Jmb60GHOHnYvw==,type:str]
seed_key: ENC[AES256_GCM,data:q6kodsHzwDuf0UHPSk9VbEI9pCwePJWcA7o6dQiZqyM=,iv:EbozH0UpLThEXjmWkNhkpHQxabH/K3/lJ8xki3lLGZo=,tag:rKO8csevxpH5kzzFWQoang==,type:str]
jwt_secret: ENC[AES256_GCM,data:AfPcqKAwdsHfiYHrZ6yKqOxD93gBcLEvZ4N3M8nhWMQ=,iv:awfSXZbc7Tzg8sRqUkp71TXivLb663ZjaxNkskE1Heg=,tag:e541/ejk7x+GOhJeoUPMGA==,type:str]
#ENC[AES256_GCM,data:/5Po+8hjJg74ZBepaNWTzZy7JrTjiwo2DNFT76hZTUFKEdchNd4sfdy3tbVwL5y9QPC/kC3kvBZL2oA0+WzcUmd51Ht4/xS6CnUCpodBrSWNHu4H+ohdmz/jMplREeJVWAFHuTZROqB9v3hw3rYJ5Gb+5XROAuzT4pKfrPoJ1B+ysGUpuvybhrC1O5Tg6IPs5fvIiR3yExGcIFuywZBiiA==,iv:gupWDnXb2TD1N8GhHwpiYuz0sDciLX8V0ww9cFKtFNI=,tag:7eDx5RZOrNXOUshvdijV5w==,type:comment]
@@ -145,17 +161,24 @@ ldap:
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
+#ENC[AES256_GCM,data:6RVyF1gPUfKEvkV3RQ==,iv:0MTKlm5kE0kZi3E013Kk/Wo642BizBRmcHXR+Zwf/W8=,tag:SaQJ7lvFUuALxXWf41C24A==,type:comment]
+mail:
+ key: ENC[AES256_GCM,data:2iT93HHmX3eCTtKb8/C5mI2uEwdck7R6TCXoLuWprfs6KMza8mwd+qDeYGauUHUojEplmopycWup1cVWyQRN2B3udxd7nR9YXcdL0ZNvjmEcjRKDicHEhIw3DVb7N5GuGkFDhc4dEx4gen5Lwu3c+b2hpL58fvZNmrldKV1Qs2jnyi4LcFxEaldPNAiJJA5CYC3M/FFrEDw+Zh1VP6rliz0wYvEoqsIanKgDs5sVkSw7IT9iBidg8EagPrlSEcYJOSHlNVJU2a28P45az0G1drw4BWiXASmCWk6CNr2WT26vz24=,iv:8h45V8wA83AHrej7ajzV3z3KUS2eu0fegjPJk7l8YoQ=,tag:kD+QVBEur6xSI0iLEthWeg==,type:str]
+ crt: ENC[AES256_GCM,data:v1nr+IQowiph7eRyENALTAXHt7NPoEdbyBcb3lVxUp9Ga6nGs7IPSyzMTfc3Am4cZ/6kRpXJG30cjINWpfhFkruS6SCPqMUcsxkVw6oLArbN62wV4umws6xh0pQNajTGY8ZNhya4RudWSLAtmIlbI0aneJKxrypPQKXeX+nML48TLcV8PicAhr4gyEk967IaHLCPK3GAuDwrD/b5NsaU3sVb5bHwcSsUKUBzdAYdHTDwsuOVwbrYT0egQ+Bcn44bY/EWw8SbIa90A+iqU6R4G9V2+/eHCSdqaNX27Yp+h3YgRJH+NqItiMlgeJ99bjvYjdSaOucmUE9gcUt7BFHpEuCI6nBGduFu/PEsFd1vNB/jKjLidN/wjcHHXXfmLy1vw8ut8ns9cl3Ufyk2VcwTfexKTuZbcAIlDdc2HGB03Z8bju8Ci96+j6cZEgv04eUZSl/5erRuyrIrA/erC09J3gqz3ojMTPsGxmQs8Rbkv6ZWM2mrsBizZq3K3XMCAP/eC1072pnOjgE91PzDUmQwBSm2xxyvjDDjJxp0M5EVdTQ/GiJXtV/Fwq8NvhI1P3nkQoDOEz+i3I1ZNrsRPLoaC+HKd+DdnO24slTUXXYO2/j9/Y3z+gjj25WR3Q1iFzKXcVH5pPVToDavMKLhlchcXI0FvqjKPYyqAY1uNEg1oVlqcyD/CcOUur1ugNQGriXPf+//nb3WZgxfcZiCwyee4oCAa3OxSMIaENn3QQ6QVGNocNanvulcA9LwIMU8qXp0+AixtFvbTlM/LHBWy10YDH2LKg7kZ9ePd6JnSFYIdB8gKhnbolrtLVIpC9NDcyzYosFrZ1NsvGgEiy+5+tLl+XERaZunulZ3VBG+4w583/PfeIZ4l7kRde1HWkym5oI0IluQG9MagyIv2a2fSScZEIClDPkOJqFaL6WszVViAgB3pAL3dEr8+48=,iv:bByFvLj8L+yZ2ErlkDBHGRhnNVQsFOe7q3WwyGVWQOU=,tag:VK8iwa8m0thEBNyTvEZOZw==,type:str]
+#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
+#
+#
#ENC[AES256_GCM,data:NronfCPkbPQLilb38VmliNn0Yg==,iv:AbC7xk46CJ5dqU55IbyPX+OZVEROz+OGnJfxoZmaKwE=,tag:GEsziOOFhDF16Vjqx59SNw==,type:comment]
prometheus:
- key: ENC[AES256_GCM,data:MNmUv4J5qVRB2NH3vFcIPGsx8ZB7ggYLK/4HyI2hBE+KhBGgh/9GeIauN6VDxO0xPqVe6xsY41vMDE8K5wmQyvTOi2fyXzL6LDxPHKVZVUKMjRgiYKJJh9hghzVeQwKwTjfZ+eXFgSKf+ENpSgh4+zbFqm0eVhhZy6EQ38494IlwS/UsojC831xg0OeeHNF5QrE7rIG8zo+rjsntpWZbJzSM9BgzFAAfW38Ywi03lstbJi8IEq/gFmZjQxU3CFHicD0X/jKY/uBxZB8lu8Km2ZevGDLFGwGX3zpcYxou3667m9M=,iv:1Px2X4RKD1sbQ9NhFW9rf0Q8cu0ex8P2RjmR5wUmFbA=,tag:rKkYDav55LfUwUueaA9Qfg==,type:str]
- crt: ENC[AES256_GCM,data:0eNafjanGCWtqCiavj5vAQKi9nczPShx0w9dfULmP03sPZTh74FCZwZvu2vQ8i0GbKNZdHMKYAP/Utyd1XdttaVr4Kvf6ggkQXj5a0AOakRmTOjkO2WhZtWUVd/fJSfcsifa1gG+x5O32yVZXx4pWSVtcV57g+BnksTyt5JBnPz+u5pEBK0VZKRSjIjlvanLM+l/Dp1tyrmKarFX+28bCDUxB3I6wZUEnF35wUNbu6pVMcR8JofQG6KrmsjixMWPRDz+u1w8b/+nTGOXyykUUjxH7a6wEf7/RTGNBwT44CrSACxybJMCed2MBjY42jA0Lm4ISwE8epvOkpptu7NRyEgMiVke5mNSH9ZGaUe6mCBpbUVkL+tUQG5rwclsL6ijaCyqsWSD5bb2i6wGhmPe5/ERKxmLjOWNeAQSf1HiJc/bSXOSpt15DuGgwwJ4jfebOqdshUy7CMc7KclQj7ppqhTYhRHbM1mJwCJr6QGVDh5xSzFDSH1qbCRdeXkPEkm7WxRJbAtzY73UmO4eqhsp5n6+PtiFNNqQg66mOGF8N7PlEKh2vcoxgtjnTTVHVlgiAHuT2TMWNuhO3qwJeF6G3zApFSPuJWcEH7PGAeezL+qUF2TzHVthOHQMUNFr1m8i4ms/hCE9DGSv5oo+X7YKO6xcIe00xNQEzMNk+HqmAKed9pl/eBHhD62UvQNZh66e1VjWpOE/ig0hP6vgKSwyQL6xUtJWWzYl184KcWokw+O9Vyw2FCR++0iu+Zn+PIYYQg4Vwpqd5VM0cj0tIB7W1+aLz8hGIOgQKDjQUshWeMxEjESILgb3+7lNyZkKT/y48ocHL/dedHRLXuxUcSQ6ZUGhWf33so7763Gimo2hK3jmIaprnx4LGyiBKPPxkSl+Bt7seUiFJ041olDmO+fUDvi0ko166CA+3mUxeoeNRh74J2RPHR8dmy1okp1NLEQztyHw4Ps=,iv:14bMOT+Fn8j2kFDQxTuwtsTyYnp4fIF0WRpQntz4afE=,tag:fWnktLbiQzG8UExa3nspUA==,type:str]
+ key: ENC[AES256_GCM,data:3/x/3FSbr/3uv1ziG79E/eQ7ysV8G6+tyGWC57fJjLSlNpTFsp+oc3lYWJbaTkDdazWz53CmrBrT3r2Lo4gMb6+CsxQjZWBCs7M7eJXB1p+a1ZwWOVndN0IWWnB9HkK2cmFh260s06FmPRNsnaBx3TvscWlr0+qcnmBxHE9tfT/k3ud3euhlMNovrKFnjSaPtMtDmBHFnr23ogcOBoe8/b29wtVC9ILh3B8qU30Rqsnu1kQhAYCPVrZhwYzAoVjX83uou8QV/GjaTgvbaRS3J/mK9kxRzspgb0zKxC/TPjptrxM=,iv:+Ly48Af4d/SCw5/WUKmzrkMzDXFRfc+RaCjiS7BEg5I=,tag:tUdZdfgY8cPz2M1RmtskZQ==,type:str]
+ crt: ENC[AES256_GCM,data:Vs69VLwR7Gw+pPuyXmyX8wRgS07fPO9+pgQOdWfTSFNcPY3M7IK08qDCxfZad3Y2/hVtW0afTq6RJWYXTr5faW1GYcp4ur1sPliU5qOYod9yJhZlxDhHPVaYfTrY1y8zy4ynW0C9tprx3AD9kGXUyXEPO2lQBgdfd50YIN0VUvTH8PC5AX+zJyytfGrfGHZlJDVBbQu3jOiuaDuyV6dszQf09PnVNaF8w67T0VUBS/01BJz46JPU/Enkzixz/ZH70wU4kHqG+77Pq4SXs1sg4kTK17Vb7px6HaOiqDy+si7nSU4Y0yQ1rKu3aqGfaz0EmKlmrxFx6RphJ1GMY+gm8k53PJubYb90DF5b/T+DYCGICYmLt9p4SEIYu3FXXcBvUkMn/Y5GGDfkbIOJLo/VqzUaGrLzy6uv90c4iGCG0FvuM+FWJAXiIC533MZt+zeEZilB5QHNqsIdLahi5kN2LCFhKHtYJVUohCt59cU0Ir3V1XTFJH8PsYAqZIwJQOhPUYmnm7GSPAWWK4i3UNH20wQY7h09MxyEgZhjcAUjtsdtZErfDykvDU4Vc+qQrH9vKGEHRberP3a/logWcYNBn3PiTPEqW3aOsVz8PdabUyFDsRymi+0eBKk5mQX4ttsPTTFZ80/t2lHoefe/SdVxGig2X+d3buUwCgXf/DZ/3KfYcZEw6Ge+HIPjYPbiJRureugy4bmL1HmhrsQCGen/mTubPH31eE33W/X4ewOgRGLjVBq6GNiJDya7jKLDn68AFX5PV+Gi7+iQAmm6zczfGWN4MR5UX14GhBNUs3NBHxx07/0Z8F+4JLMNprR+Kr/PpBP8fsOeDlbRKauQeuTaHmPkESTYtTmdzoBzV/sCwH6w2pbNoYrGLEjElhhOk3slBwaUJwQ/O+jTvw69SsmRjFrOzty7tVUEp1amNMJ976k2rYeMZehlTMk6KAewTNdI/XivEIg=,iv:J+6oHMZTFZmsDcyizC7vdJ1D1aHRJ9lcgIsCPx1fj9U=,tag:XtyFeB50RPRaW7j1JYu2jA==,type:str]
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
#ENC[AES256_GCM,data:8Pk3De3AWQPtW+o18w==,iv:O05B1JyftUqN/0/pCi5HReEOltp5jJ6GRER5+NXkoMY=,tag:Tl4duRnv+EoZ4xWVwMfEWA==,type:comment]
loki:
- key: ENC[AES256_GCM,data:gtQ3j59WJd3YxreCMoR70VZBJubaR8UfoeAEYgZR8KGIYkEGPnBCMEmBlu/L4qZO0fHg0DLSN/ixLbmvbOluTMNF1rbj/5W4F0O79YI2RztXZ3oxrtYf4dRPxIoCuOQi9PtD5VrduBUGGhvDW9yae9QxzQ+Ca7KwMHgOLu/5+VW6YdQRBdgEQycSDsdMvRTmFwnQuSxuQhWxhu9GqR2WGx3cinQIZ8ewr147aOiZNgUjnHLfYjtzRXqQtK0HEvjNVKBWPuOWLYRa+h10TQlKMQMZn7x7QJlDZhsF/aRqVRNwYc0=,iv:0vVdSLKOgFTwvUbW1uU2vINYwnXMIYIzOl+2BqsJ7Vk=,tag:nm34OwNXseUTzO/KUmT2Vg==,type:str]
- crt: ENC[AES256_GCM,data:O1if/oi5wJQNhHftNEwRhSvdnloaiE8EIJ0dlY9DO2Lml1rz5+2LfwGnN/mHGFOkIZri2AhizPUqXios5kKYgdh7ib4jD2C4DC8crKO9XiNiiChzqE0WqP/sda9UJL9zzmmm3WtkGljcL1iyr4zuCvH0uuIMX6W+NohIu19JT9wqamwMHBCEYuQ6gFAVOBnsz5Rsa6v2LBsIsUBadAzngUcrIztT1UO0cHiplBq5s+TkC96wWrlAUiaV1Lcf1aABDrI6o2u4uv6Vwv/d4AQrEpaNvH1N3un/M3lOIek53atwMYw598/BAioJfZXRTQ4qeqcv9+WxFJSpG6XrWxx941St6N3ITJcAMVmKQFfupj257oyazHF4oqyJKsgXQBTXlMdLPDLH/HTRVfv5k1qD5RQ6AXJrMy4NQrE4BlLBPkLU1wxyg2REqd6eKMgw1PQdqTeZHZrQCGzxWeY+rv/0v5jwSFzC/YY+hOZRz3BRpfufWC9mZQZpNoH8yccVhPybVT22YMMVljLUEg/0BICm9Q4mSMpc9hEJ7VwHZo5pT4DuNiVjComTpcnnrEgK3yYGBB6jsAAkU+zNmOZ6AkCvKAma2DVbOhwUx1ZuBruc4GsfJcHGWqWogr4zBpgDg9FOtLF28yQpfKDWZEdx1eq1Bu9gFhK1FoBxrzd7mX5ADn0XeRbFDn/G+C24ShA+D+rmhARAdCtz6M4uk5IZ3w+L8NA/qWyZ+bgaXX8KrpDOV+/7KFStD4FXkVk20+IaMpb6OSYskqPq1ICI0MIFsONajO8gCd026B6WD/hLsGvkLL/58IwtAd+bRBceXHgoqXeTjyqNgKhhiqmKejZUphzrIsMx+GWdP70GOdcj41I5PSN0GbMnXQTRPGJo/GYN4pP3TbtmVrEvs5rMuGe0WiDiXQGM2hAreGMnt43Ge7DjyB+BPAx6ZA==,iv:1E1u18aWSRZFKewRnH+pJKN9xCpFUcJ0Dy4kq4yMprY=,tag:nmI9X0IrT545vUWhoIdhHg==,type:str]
+ key: ENC[AES256_GCM,data:9D6ZrmJTAMUf6B2k1Kzl64KgTWwe+kDTTSH9d+Ho++hHnCMKr9ORytJUsaglSip7/X6guRXh2v6s9PuTlEvEhrsAcvj1gFU1nilmq8plOzWh52U1xtpNh8Lf0z5qUYUoG4XjR2kG80B431n/iov/N5/1QWx3PauUAdSWK8ljlZ/1rPBtNjdXWCQzI7zD6p7qKUvXifp2j6r4hlkb9tJH8/t5rlD0LRU7vA7xWg06UayUw94dfgCLVDfB5zqtwPKhot4BkELMUVaUPmJoW3p1ifhZ/JOgLbB0wgt1DMmu6iI8cuw=,iv:9iJBus8P+LnhOc0YDIzwiaKRbp2kc52rW7pyayKDPKs=,tag:pDjlecxjJtdI2OY/x8SpcA==,type:str]
+ crt: ENC[AES256_GCM,data:cl6K1gEzaKpwr/hksXhjtQty1UGbhAIqB4YNJccfFAOx65YOc1VQ3pIMn+L/IvDQMmuJRRm7zlGdYBnrexhWwuNlcnEi6e0Q25ulneJbrkg77v7rB+ap9VWZsafTRusRlObGTA01liV21UsaDA/Kknt+PFZTAdO8EC6KXegYgAVDNIhiEKUDsaZMrdVFkTSJ00qK9zfwDJ5mcTYM5A14o+3HyK/nMXKYqR+yxwQqLVYVvD6M8SjLbe9VJfBJlOsOe6toTOHUGglBnQr7x0lsEdBvk9UZ3+S2bKpU1qqY7OIxSSjeOZ7YWUC7r8D8lhz2yIOKRFvzJPm10ZxSDq4sn4jIs/hPXIgRTfO4h33pjOhqeTM5q6SRslYpKNsudYYrI++vog2B3b8qhg5II5yJ1Xhe3MqfH4pJeIZcYS8+uIrSMPujhR5q6jVhXwoCKVpifktmz+vopmEFfXzdnaboXYtj//bbhgn0wRxONBYv3dOfQMAVDtptqNJC9iskiZTeZdNmrMTko8BhU/cZF3VML0fTVo8XAQiMvFuk5FaaJaMVFW0sbuyoR3izCm0HGMsjyHmwRov3AarzHkjj7CTuMmZ0kDPrmzPHylgasfuh7W4VTOKN9Ld6umWR2YpBYKSrrnnr7rfag2Ll7ywEcl/Sj1ZymIlsixokiMGwE564AN1MqnsYc5uiCXfo6aUg6nnbUlEg8U0j6pQWICTkFCSjKpD9RgL/FqhcsY+qiGL+pPLHBYXUVo/uARup545+2MG1PA/vCGP/WTp36siXskx3wrQywHg1TIuhTsB0rh499lJhtXP4uStX4vHbE9dDjSOss56FFENn6kc84PInv1ulWcMLKFqEfI/KTgzH2E8NImcJORne+vWkMYOpoCfHTpIQizj6/+5W/5OPKgknpMUH2MaLusopbGNDk2uC5m1my1uirT+AGg==,iv:eTcuF44+5wemJmnTQWKMQnsVH40UlyNtQPLCOklMzdY=,tag:Um5r0IUKw4/VQR7HxKaaZg==,type:str]
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
@@ -279,6 +302,15 @@ mealie:
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
#
#
+#ENC[AES256_GCM,data:b74wua/tFSoef2fq5jZhNQ==,iv:RDtz7Y6eFQKiVVnNvoLAfzE4xo8t7RFiKjLTbd0xo80=,tag:iUS7ofvuVj6ZTsy8zA6KSg==,type:comment]
+homebox:
+ api_secret: ENC[AES256_GCM,data:BT6m0D9Xwa1tnQQRzpUnEF4bjLFne297oS3p8HM8Q/1Vakrf+uFcfS0C4MU=,iv:5WeWyfe8kt+AWwsV3YXxfLVuSEE8lYmNFxrXyRZzISc=,tag:cYd6U3BxqyGst+UsMpRypA==,type:str]
+ oidc:
+ secret: ENC[AES256_GCM,data:26flutXrbmP4UqyfQs4PmROQGwrJhmkTw2Ujro0jg+q5nfy1mN5i5zKcnAg=,iv:a/fwjeE7MVByIG/L8Tq2ORjF4aSOwWSusER0c3ySBV8=,tag:kkx4hAlfff42Qghe+l9uLg==,type:str]
+ hash: ENC[AES256_GCM,data:CRdr7WWotsMujhH5PFEFNNF/y0xLjLu6TZc93/eIZyzFZPp9kdHcVyMs8pnyQTMT5r3ynWRsT17N8s7X84uZNqPCu1o4KGvNR5UioiSecHdov1LoJbE1mYCCm2H34PEFwpjSMP013ipz0ybuaYqMTASOn1B/lOUt2bP6yj9NnlBVPUg=,iv:K4iH1ZykdgcL9a0eqCB6PPCU/8jGpX9NEt3yljbOVpY=,tag:EpWG3NEwioRietOi/IbvmA==,type:str]
+#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
+#
+#
#ENC[AES256_GCM,data:T4Wtn49AAxPd2QUFTR+q,iv:bH5goGWBDqumAat9dUv2OwfCUJUpuVqncTMqMBZUXhI=,tag:G+W6hHA+yftQ+4RJpXrxHg==,type:comment]
switch:
admin:
@@ -310,7 +342,7 @@ sops:
k+uyWPPi+enFkVaceSwMFrA66uaWWrwAj11sXEB7yzvGFPrnAGezjQ==
-----END AGE ENCRYPTED FILE-----
recipient: age120wuwcmsm845ztsvsz46pswj5je53uc2n35vadklrfqudu6cxuusxetk7y
- lastmodified: "2026-06-12T13:44:23Z"
- mac: ENC[AES256_GCM,data:FMOY7qMDSCzvOUL44zmwLwUVAXfYkat1JbiNeBVQFuUrC4lAwuukxW9MCPs5plj84LOAUMVgMofyudFJh5VKTR6Y0EnB5ft0NnbGgwMwzQnQn7d9Mcg9xPca3ccSbSGNx0UrC+8lTjXuzhoawMQ5ZXZ3ZK0k7JrFQ2El7UUwxEA=,iv:+oj0bvsDo8gidUn6m0FOeWsJOxIXPHhzvtiIbQ1VgcY=,tag:8xLcthizKqWjqg2eQvJlRA==,type:str]
+ lastmodified: "2026-06-23T00:53:05Z"
+ mac: ENC[AES256_GCM,data:30XGjw0JCuUTo5nbcAYkIeMyJ2H50f8F9hdTArYLxAlRz0iffx0n7BXH/LLtI/5FKcOmfhoHP/CT22wcSFxKAPzWD5Ce/xNGAFNoTftodU4CE+/VHn7VFhWYaXVjnQs2duuy4QHQvcDa8uMo+c7ZunqrkZO0zU5fKSYOaJMLloQ=,iv:MyMgnJ96P9RoDYxsbJVZnnK1q82o5AB/hueMXeQhKqQ=,tag:1s288++ruxdUfSnyP8/ecA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.1
diff --git a/config/services/containers/app/gitea/gitea.container.j2 b/config/services/containers/app/gitea/gitea.container.j2
index 4abb252..eafc847 100644
--- a/config/services/containers/app/gitea/gitea.container.j2
+++ b/config/services/containers/app/gitea/gitea.container.j2
@@ -15,7 +15,7 @@ HostName=gitea
PublishPort={{ services['gitea']['ports']['http'] }}:3000/tcp
-Volume=%h/data/containers/gitea:/data:rw
+Volume=%h/data/containers/gitea/data:/data:rw
Volume=%h/containers/gitea/ssl:/etc/ssl/gitea:ro
# General
@@ -23,7 +23,7 @@ Environment="TZ={{ timezone }}"
Environment="GITEA__server__DISABLE_SSH=true"
# Database
Environment="GITEA__database__DB_TYPE=postgres"
-Environment="GITEA__database__HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
+Environment="GITEA__database__HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
Environment="GITEA__database__NAME=gitea_db"
Environment="GITEA__database__USER=gitea"
Secret=GITEA__database__PASSWD,type=env
@@ -34,7 +34,7 @@ Environment="GITEA__oauth2_client__ACCOUNT_LINKING=auto"
# OIDC configuration
Environment="GITEA__openid__ENABLE_OPENID_SIGNIN=false"
Environment="GITEA__openid__ENABLE_OPENID_SIGNUP=true"
-Environment="GITEA__openid__WHITELISTED_URIS={{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="GITEA__openid__WHITELISTED_URIS={{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
# automatic create user via authelia
Environment="GITEA__service__DISABLE_REGISTRATION=false"
Environment="GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=true"
@@ -42,7 +42,7 @@ Environment="GITEA__service__SHOW_REGISTRATION_BUTTON=false"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/homebox/homebox.container.j2 b/config/services/containers/app/homebox/homebox.container.j2
new file mode 100644
index 0000000..b8cf450
--- /dev/null
+++ b/config/services/containers/app/homebox/homebox.container.j2
@@ -0,0 +1,49 @@
+[Quadlet]
+DefaultDependencies=false
+
+[Unit]
+Description=Homebox
+
+[Container]
+Image=ghcr.io/sysadminsmedia/homebox:{{ version['containers']['homebox'] }}
+
+ContainerName=homebox
+HostName=homebox
+
+PublishPort={{ services['homebox']['ports']['http'] }}:7745
+
+# Volumes
+Volume=%h/data/containers/homebox/data:/data:rw
+Volume=%h/containers/homebox/ssl:/etc/ssl/homebox:ro
+
+# Environment
+Environment="TZ={{ timezone }}"
+Secret=HBOX_AUTH_API_KEY_PEPPER,type=env
+# OIDC
+Environment="HBOX_OIDC_ENABLED=true"
+Environment="HBOX_OIDC_ISSUER_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
+Environment="HBOX_OIDC_CLIENT_ID=homebox"
+Environment="HBOX_OIDC_SCOPE=openid profile email groups"
+Environment="HBOX_OPTIONS_TRUST_PROXY=true"
+Environment="HBOX_OIDC_ALLOWED_GROUPS=admins,users"
+Environment="HBOX_OPTIONS_ALLOW_LOCAL_LOGIN=false"
+Secret=HBOX_OIDC_CLIENT_SECRET,type=env
+
+# Database
+Environment="HBOX_DATABASE_DRIVER=postgres"
+Environment="HBOX_DATABASE_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
+Environment="HBOX_DATABASE_PORT={{ services['postgresql']['ports']['tcp'] }}"
+Environment="HBOX_DATABASE_USERNAME=homebox"
+Environment="HBOX_DATABASE_DATABASE=homebox_db"
+Environment="HBOX_DATABASE_SSL_MODE=verify-full"
+Environment="HBOX_DATABASE_SSL_ROOT_CERT=/etc/ssl/homebox/{{ root_cert_filename }}"
+Secret=HBOX_DATABASE_PASSWORD,type=env
+
+[Service]
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+Restart=always
+RestartSec=10s
+TimeoutStopSec=120
+
+[Install]
+WantedBy=default.target
diff --git a/config/services/containers/app/immich/immich.container.j2 b/config/services/containers/app/immich/immich.container.j2
index 47c379a..7ee05c8 100644
--- a/config/services/containers/app/immich/immich.container.j2
+++ b/config/services/containers/app/immich/immich.container.j2
@@ -20,7 +20,7 @@ AddDevice=/dev/dri:/dev/dri
PodmanArgs=--group-add keep-groups
# Volumes
-Volume=%h/data/containers/immich:/data:rw
+Volume=%h/data/containers/immich/data:/data:rw
Volume=%h/containers/immich/ssl:/etc/ssl/immich:ro
# Environment
@@ -34,7 +34,7 @@ Environment="REDIS_PORT={{ services['immich']['ports']['redis'] }}"
Environment="REDIS_DBINDEX=0"
# Database
-Environment="DB_HOSTNAME={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="DB_HOSTNAME={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="DB_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="DB_USERNAME=immich"
Environment="DB_DATABASE_NAME=immich_db"
@@ -44,7 +44,7 @@ Environment="NODE_EXTRA_CA_CERTS=/etc/ssl/immich/{{ root_cert_filename }}"
Secret=IMMICH_DB_PASSWORD,target=/run/secrets/DB_PASSWORD
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/mealie/mealie.container.j2 b/config/services/containers/app/mealie/mealie.container.j2
index d8ed020..5b41a33 100644
--- a/config/services/containers/app/mealie/mealie.container.j2
+++ b/config/services/containers/app/mealie/mealie.container.j2
@@ -21,7 +21,7 @@ Environment="ALLOW_PASSWORD_LOGIN=false"
# Database (PostgreSQL)
Environment="DB_ENGINE=postgres"
-Environment="POSTGRES_SERVER={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="POSTGRES_SERVER={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="POSTGRES_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="POSTGRES_USER=mealie"
Environment="POSTGRES_DB=mealie_db"
@@ -32,7 +32,7 @@ Secret=MEALIE_POSTGRES_PASSWORD,type=env,target=POSTGRES_PASSWORD
# OIDC
Environment="OIDC_AUTH_ENABLED=true"
Environment="OIDC_SIGNUP_ENABLED=true"
-Environment="OIDC_CONFIGURATION_URL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/.well-known/openid-configuration"
+Environment="OIDC_CONFIGURATION_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration"
Environment="OIDC_CLIENT_ID=mealie"
Environment="OIDC_AUTO_REDIRECT=false"
Environment="OIDC_ADMIN_GROUP=admins"
@@ -40,7 +40,7 @@ Environment="OIDC_USER_GROUP=users"
Secret=MEALIE_OIDC_CLIENT_SECRET,type=env,target=OIDC_CLIENT_SECRET
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/memos/memos.container.j2 b/config/services/containers/app/memos/memos.container.j2
index a9eba88..51db31e 100644
--- a/config/services/containers/app/memos/memos.container.j2
+++ b/config/services/containers/app/memos/memos.container.j2
@@ -25,7 +25,7 @@ Environment="MEMOS_DRIVER=postgres"
Secret=MEMOS_DSN,type=env
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/nextcloud/nextcloud.container.j2 b/config/services/containers/app/nextcloud/nextcloud.container.j2
index c1d6fa9..4973c6c 100644
--- a/config/services/containers/app/nextcloud/nextcloud.container.j2
+++ b/config/services/containers/app/nextcloud/nextcloud.container.j2
@@ -4,6 +4,9 @@ DefaultDependencies=false
[Unit]
Description=Nextcloud
+After=redis_nextcloud.service
+Wants=redis_nextcloud.service
+
[Container]
Image=docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}
ContainerName=nextcloud
diff --git a/config/services/containers/app/outline/outline.container.j2 b/config/services/containers/app/outline/outline.container.j2
index 1b76e1b..65874b7 100644
--- a/config/services/containers/app/outline/outline.container.j2
+++ b/config/services/containers/app/outline/outline.container.j2
@@ -29,7 +29,7 @@ Secret=OUTLINE_SECRET_KEY,type=env,target=SECRET_KEY
Secret=OUTLINE_UTILS_SECRET,type=env,target=UTILS_SECRET
# Database
-Environment="DATABASE_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="DATABASE_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="DATABASE_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="DATABASE_NAME=outline_db"
Environment="DATABASE_USER=outline"
@@ -47,9 +47,9 @@ Environment="FILE_STORAGE_UPLOAD_MAX_SIZE=262144000"
# OIDC
Environment="OIDC_CLIENT_ID=outline"
-Environment="OIDC_AUTH_URI=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/api/oidc/authorization"
-Environment="OIDC_TOKEN_URI=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/api/oidc/token"
-Environment="OIDC_USERINFO_URI=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/api/oidc/userinfo"
+Environment="OIDC_AUTH_URI=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/api/oidc/authorization"
+Environment="OIDC_TOKEN_URI=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/api/oidc/token"
+Environment="OIDC_USERINFO_URI=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/api/oidc/userinfo"
Environment="OIDC_USERNAME_CLAIM=preferred_username"
Environment="OIDC_DISPLAY_NAME=Authelia"
Environment="OIDC_SCOPES=openid offline_access profile email"
@@ -69,7 +69,7 @@ Secret=OUTLINE_OIDC_CLIENT_SECRET,type=env,target=OIDC_CLIENT_SECRET
Environment="LOG_LEVEL=warn"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/paperless/paperless.container.j2 b/config/services/containers/app/paperless/paperless.container.j2
index db18abf..534997b 100644
--- a/config/services/containers/app/paperless/paperless.container.j2
+++ b/config/services/containers/app/paperless/paperless.container.j2
@@ -35,7 +35,7 @@ Secret=PAPERLESS_SECRET_KEY,type=env
Environment="PAPERLESS_REDIS=redis://host.containers.internal:{{ services['paperless']['ports']['redis'] }}"
# Database
-Environment="PAPERLESS_DBHOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="PAPERLESS_DBHOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="PAPERLESS_DBPORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="PAPERLESS_DBNAME=paperless_db"
Environment="PAPERLESS_DBUSER=paperless"
@@ -50,7 +50,7 @@ Environment="PAPERLESS_SOCIALACCOUNT_ALLOW_SIGNUPS=true"
Secret=PAPERLESS_SOCIALACCOUNT_PROVIDERS,type=env
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/sure/sure-web.container.j2 b/config/services/containers/app/sure/sure-web.container.j2
index e745809..f0a1f1c 100644
--- a/config/services/containers/app/sure/sure-web.container.j2
+++ b/config/services/containers/app/sure/sure-web.container.j2
@@ -29,7 +29,7 @@ Secret=SURE_SECRET_KEY_BASE,type=env,target=SECRET_KEY_BASE
# PostgreSQL
Environment="POSTGRES_USER=sure"
Environment="POSTGRES_DB=sure_db"
-Environment="DB_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="DB_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="DB_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="PGSSLMODE=verify-full"
Environment="PGSSLROOTCERT=/etc/ssl/sure/{{ root_cert_filename }}"
@@ -40,7 +40,7 @@ Environment="REDIS_URL=redis://host.containers.internal:{{ services['sure']['por
# OIDC - Authelia
Environment="OIDC_CLIENT_ID=sure"
-Environment="OIDC_ISSUER=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="OIDC_ISSUER=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="OIDC_REDIRECT_URI=https://{{ services['sure']['domain']['public'] }}.{{ domain['public'] }}/auth/openid_connect/callback"
Secret=SURE_OIDC_CLIENT_SECRET,type=env,target=OIDC_CLIENT_SECRET
Environment="OIDC_BUTTON_LABEL=Sign in with Authelia"
@@ -58,7 +58,7 @@ Environment="EXCHANGE_RATE_PROVIDER=yahoo_finance"
Environment="SECURITIES_PROVIDER=yahoo_finance"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/sure/sure-worker.container.j2 b/config/services/containers/app/sure/sure-worker.container.j2
index 03589c7..0d6f958 100644
--- a/config/services/containers/app/sure/sure-worker.container.j2
+++ b/config/services/containers/app/sure/sure-worker.container.j2
@@ -29,7 +29,7 @@ Secret=SURE_SECRET_KEY_BASE,type=env,target=SECRET_KEY_BASE
# PostgreSQL
Environment="POSTGRES_USER=sure"
Environment="POSTGRES_DB=sure_db"
-Environment="DB_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="DB_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="DB_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="PGSSLMODE=verify-full"
Environment="PGSSLROOTCERT=/etc/ssl/sure/{{ root_cert_filename }}"
@@ -40,7 +40,7 @@ Environment="REDIS_URL=redis://host.containers.internal:{{ services['sure']['por
# OIDC - Authelia
Environment="OIDC_CLIENT_ID=sure"
-Environment="OIDC_ISSUER=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="OIDC_ISSUER=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="OIDC_REDIRECT_URI=https://{{ services['sure']['domain']['public'] }}.{{ domain['public'] }}/auth/openid_connect/callback"
Secret=SURE_OIDC_CLIENT_SECRET,type=env,target=OIDC_CLIENT_SECRET
Environment="OIDC_BUTTON_LABEL=Sign in with Authelia"
@@ -58,7 +58,7 @@ Environment="EXCHANGE_RATE_PROVIDER=yahoo_finance"
Environment="SECURITIES_PROVIDER=yahoo_finance"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/app/vaultwarden/vaultwarden.container.j2 b/config/services/containers/app/vaultwarden/vaultwarden.container.j2
index 963a420..e750e6f 100644
--- a/config/services/containers/app/vaultwarden/vaultwarden.container.j2
+++ b/config/services/containers/app/vaultwarden/vaultwarden.container.j2
@@ -15,7 +15,7 @@ HostName=vaultwarden
PublishPort={{ services['vaultwarden']['ports']['http'] }}:80/tcp
-Volume=%h/data/containers/vaultwarden:/data:rw
+Volume=%h/data/containers/vaultwarden/data:/data:rw
Volume=%h/containers/vaultwarden/ssl:/etc/ssl/vaultwarden:ro
Environment="TZ={{ timezone }}"
@@ -25,7 +25,7 @@ Secret=VW_ADMIN_TOKEN,type=env,target=ADMIN_TOKEN
Secret=VW_DATABASE_URL,type=env,target=DATABASE_URL
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/config/services/containers/auth/authelia/authelia.container.j2 b/config/services/containers/auth/authelia/authelia.container.j2
index 9673780..c9a6a07 100644
--- a/config/services/containers/auth/authelia/authelia.container.j2
+++ b/config/services/containers/auth/authelia/authelia.container.j2
@@ -56,9 +56,9 @@ Exec=--config /config/authelia.yaml
# Wait for dependency
# They run as rootless podman container, so their port is not opened until they are normally running
# Check their ports with nc command
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
# services['ldap']['ports']['ldaps'] is 6360, but nftables works on 636 the original port
-ExecStartPre=/usr/bin/nc -zv {{ services['ldap']['domain'] }}.{{ domain['internal'] }} 636
+ExecStartPre=/usr/bin/nc -zv {{ services['ldap']['domain']['internal'] }}.{{ domain['internal'] }} 636
ExecStartPre=sleep 5
Restart=always
RestartSec=10s
diff --git a/config/services/containers/auth/authelia/config/authelia.yaml.j2 b/config/services/containers/auth/authelia/config/authelia.yaml.j2
index 3e7424d..b273234 100644
--- a/config/services/containers/auth/authelia/config/authelia.yaml.j2
+++ b/config/services/containers/auth/authelia/config/authelia.yaml.j2
@@ -30,12 +30,12 @@ identity_validation:
# Authentication backend provider configuration
authentication_backend:
ldap:
- # ldaps uses 636 -> NAT automatically change port 636 in output packet -> 2636 which lldap server uses.
- address: 'ldaps://{{ services['ldap']['domain'] }}.{{ domain['internal'] }}'
+ # ldaps uses 636 -> NAT automatically change port 636 in output packet -> 6360 which lldap server uses.
+ address: 'ldaps://{{ services['ldap']['domain']['internal'] }}.{{ domain['internal'] }}'
implementation: 'lldap'
# tls configuration, it uses certificates_directory's /etc/ssl/authelia/{{ root_cert_filename }}
tls:
- server_name: '{{ services['ldap']['domain'] }}.{{ domain['internal'] }}'
+ server_name: '{{ services['ldap']['domain']['internal'] }}.{{ domain['internal'] }}'
skip_verify: false
# LLDAP base DN
base_dn: '{{ domain['dc'] }}'
@@ -53,7 +53,7 @@ access_control:
default_policy: 'deny'
rules:
# authelia portal
- - domain: '{{ services['authelia']['domain'] }}.{{ domain['public'] }}'
+ - domain: '{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}'
policy: 'bypass'
# - domain: 'test.ilnmors.com'
# policy: 'one_factor'
@@ -68,7 +68,7 @@ session:
cookies:
- name: 'authelia_public_session'
domain: '{{ domain['public'] }}'
- authelia_url: 'https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}'
+ authelia_url: 'https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}'
same_site: 'lax'
# This authelia doesn't use Redis.
@@ -77,12 +77,12 @@ session:
storage:
encryption_key: '' # $AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE is designated in container file
postgres:
- address: 'tcp://{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}'
+ address: 'tcp://{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}'
database: 'authelia_db'
username: 'authelia'
password: '' # $AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE is designated in container file
tls:
- server_name: '{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}'
+ server_name: '{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}'
skip_verify: false
# Notification provider
@@ -94,47 +94,18 @@ notifier:
identity_providers:
oidc:
hmac_secret: '' # $AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE
- jwks:{% raw %}
+ jwks:
- algorithm: 'RS256'
use: 'sig'
- key: {{ secret "/run/secrets/AUTHELIA_JWKS_RS256" | mindent 10 "|" | msquote }}
+ key: {% raw %}{{ secret "/run/secrets/AUTHELIA_JWKS_RS256" | mindent 10 "|" | msquote }}{% endraw %}{{ '' }}
- algorithm: 'ES256'
use: 'sig'
- key: {{ secret "/run/secrets/AUTHELIA_JWKS_ES256" | mindent 10 "|" | msquote }}{% endraw %}
+ key: {% raw %}{{ secret "/run/secrets/AUTHELIA_JWKS_ES256" | mindent 10 "|" | msquote }}{% endraw %}{{ '' }}
lifespans:
access_token: '1h'
id_token: '1h'
refresh_token: '720h'
clients:
- # https://www.authelia.com/integration/openid-connect/clients/synology-dsm/
- - client_id: 'dsm'
- client_name: 'dsm'
- consent_mode: 'implicit'
- # It depends on application
- # hash value generate:
- # podman exec -it authelia sh
- # authelia crypto hash generate pbkdf2 --password 'password'
- client_secret: '{{ hostvars['console']['dsm']['oidc']['hash'] }}'
- # If there were not client secret, public should be `true` [true | false]
- public: false
- authorization_policy: 'one_factor'
- require_pkce: false
- pkce_challenge_method: ''
- redirect_uris:
- - 'https://{{ services['nas']['domain'] }}.{{ domain['internal'] }}:{{ services['nas']['ports']['https'] }}'
- scopes:
- - 'openid'
- - 'profile'
- - 'groups'
- - 'email'
- response_types:
- - 'code'
- grant_types:
- - 'authorization_code'
- access_token_signed_response_alg: 'none'
- userinfo_signed_response_alg: 'none'
- # [ client_secret_post | client_secret_basic ]
- token_endpoint_auth_method: 'client_secret_post'
# https://www.authelia.com/integration/openid-connect/clients/gitea/
- client_id: 'gitea'
client_name: 'gitea'
@@ -319,3 +290,24 @@ identity_providers:
access_token_signed_response_alg: 'none'
userinfo_signed_response_alg: 'none'
token_endpoint_auth_method: 'client_secret_basic'
+ # https://www.authelia.com/integration/openid-connect/clients/homebox/
+ - client_id: 'homebox'
+ client_name: 'homebox'
+ consent_mode: 'implicit'
+ client_secret: '{{ hostvars['console']['homebox']['oidc']['hash'] }}'
+ public: false
+ authorization_policy: 'one_factor'
+ require_pkce: true
+ pkce_challenge_method: 'S256'
+ redirect_uris:
+ - 'https://{{ services['homebox']['domain']['public'] }}.{{ domain['public'] }}/api/v1/users/login/oidc/callback'
+ scopes:
+ - 'openid'
+ - 'groups'
+ - 'email'
+ - 'profile'
+ response_types:
+ - 'code'
+ grant_types:
+ - 'authorization_code'
+ token_endpoint_auth_method: 'client_secret_basic'
diff --git a/config/services/containers/common/caddy/caddy.container.j2 b/config/services/containers/common/caddy/caddy.container.j2
index 63dd00c..4c1902d 100644
--- a/config/services/containers/common/caddy/caddy.container.j2
+++ b/config/services/containers/common/caddy/caddy.container.j2
@@ -19,9 +19,9 @@ Image={{ domain['internal'] }}/{{ node['name'] }}/caddy:{{ version['containers']
ContainerName=caddy_{{ node['name'] }}
HostName=caddy_{{ node['name'] }}
{% if node['name'] == 'infra' %}
-AddHost={{ services['ca']['domain'] }}.{{ domain['internal'] }}:host-gateway
-AddHost={{ services['prometheus']['domain'] }}.{{ domain['internal'] }}:host-gateway
-AddHost={{ services['loki']['domain'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['ca']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['prometheus']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['loki']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
{% endif %}
PublishPort={{ services['caddy']['ports']['http'] }}:80/tcp
diff --git a/config/services/containers/common/caddy/etc/Caddyfile.j2 b/config/services/containers/common/caddy/etc/Caddyfile.j2
new file mode 100644
index 0000000..4238acd
--- /dev/null
+++ b/config/services/containers/common/caddy/etc/Caddyfile.j2
@@ -0,0 +1,92 @@
+{% if node['name'] == 'auth' %}
+{
+ # CrowdSec LAPI connection
+ crowdsec {
+ api_url https://{{ services['crowdsec']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}
+ api_key "{file./run/secrets/CADDY_CROWDSEC_KEY}"
+ }
+}
+
+# Snippets
+# CrowdSec log for parser
+(crowdsec_log) {
+ log {
+ output file /log/access.log {
+ mode 0644
+ roll_size 100MiB
+ roll_keep 1
+ }
+ format json
+ }
+}
+{% endif %}
+{% if node['name'] == 'app' %}
+{
+ servers {
+ # Only accept packets from auth main caddy
+ trusted_proxies static {{ hostvars['fw']['network4']['auth']['server'] }} {{ hostvars['fw']['network6']['auth']['server'] }}
+ }
+}
+{% endif %}
+# Private TLS ACME with DNS-01-challenge
+(private_tls) {
+ tls {
+ issuer acme {
+ dir https://{{ services['ca']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}/acme/acme@{{ domain['internal'] }}/directory
+ dns rfc2136 {
+ server {{ services['bind']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['bind']['ports']['dns'] }}
+ key_name acme-key
+ key_alg hmac-sha256
+ key "{file./run/secrets/CADDY_ACME_KEY}"
+ }
+ resolvers {{ services['bind']['domain']['internal'] }}.{{ domain['internal'] }}
+ }
+ }
+}
+# Node domain
+{{ node['name'] }}.{{ domain['internal'] }} {
+ import private_tls
+ metrics
+}
+# Applications
+{% for item in caddy_services %}
+{% set service = services[item] %}
+{% set web_type = service['dependency']['web'] %}
+{% if node['name'] == 'auth' %}
+{% if service['domain']['public'] == '@' %}
+{{ domain['public'] }} {
+{% else %}
+{{ service['domain']['public'] }}.{{ domain['public'] }} {
+{% endif %}
+ import crowdsec_log
+ route {
+ crowdsec
+{% if web_type == 'auth-public' %}
+ reverse_proxy host.containers.internal:{{ service['ports']['http'] }}
+{% else %}
+ reverse_proxy https://{{ service['domain']['internal'] }}.{{ domain['internal'] }} {
+ header_up Host {http.reverse_proxy.upstream.host}
+ }
+{% endif %}
+ }
+}
+{% elif node['name'] == 'infra' %}
+{{ service['domain']['internal'] }}.{{ domain['internal'] }} {
+ import private_tls
+ route {
+ {% if service['ports']['https'] is defined %}
+ reverse_proxy https://{{ service['domain']['internal'] }}.{{ domain['internal'] }}:{{ service['ports']['https'] }}
+ {% else %}
+ reverse_proxy host.containers.internal:{{ service['ports']['http'] }}
+ {% endif %}
+ }
+}
+{% elif node['name'] == 'app' %}
+{{ service['domain']['internal'] }}.{{ domain['internal'] }} {
+ import private_tls
+ reverse_proxy host.containers.internal:{{ service['ports']['http'] }} {
+ header_up Host {http.request.header.X-Forwarded-Host}
+ }
+}
+{% endif %}
+{% endfor %}{{ '' }}
diff --git a/config/services/containers/common/caddy/etc/app/Caddyfile.j2 b/config/services/containers/common/caddy/etc/app/Caddyfile.j2
deleted file mode 100644
index 03f9dc3..0000000
--- a/config/services/containers/common/caddy/etc/app/Caddyfile.j2
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- servers {
- # Only accept packets from auth main caddy
- trusted_proxies static {{ hostvars['fw']['network4']['auth']['server'] }} {{ hostvars['fw']['network6']['auth']['server'] }}
- }
-}
-# Private TLS ACME with DNS-01-challenge
-(private_tls) {
- tls {
- issuer acme {
- dir https://{{ services['ca']['domain'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}/acme/acme@{{ domain['internal'] }}/directory
- dns rfc2136 {
- server {{ services['bind']['domain'] }}.{{ domain['internal'] }}:{{ services['bind']['ports']['dns'] }}
- key_name acme-key
- key_alg hmac-sha256
- key "{file./run/secrets/CADDY_ACME_KEY}"
- }
- resolvers {{ services['bind']['domain'] }}.{{ domain['internal'] }}
- }
- }
-}
-
-{{ node['name'] }}.{{ domain['internal'] }} {
- import private_tls
- metrics
-}
-# test.app.ilnmors.internal {
-# import private_tls
-# root * /usr/share/caddy
-# file_server
-# }
-{{ services['vaultwarden']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['vaultwarden']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['gitea']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['gitea']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['immich']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['immich']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['paperless']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['paperless']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['nextcloud']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['nextcloud']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['collabora']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['collabora']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['sure']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['sure']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['outline']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['outline']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['memos']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['memos']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
-{{ services['mealie']['domain']['internal'] }}.{{ domain['internal'] }} {
- import private_tls
- reverse_proxy host.containers.internal:{{ services['mealie']['ports']['http'] }} {
- header_up Host {http.request.header.X-Forwarded-Host}
- }
-}
diff --git a/config/services/containers/common/caddy/etc/auth/Caddyfile.j2 b/config/services/containers/common/caddy/etc/auth/Caddyfile.j2
deleted file mode 100644
index e9fd55f..0000000
--- a/config/services/containers/common/caddy/etc/auth/Caddyfile.j2
+++ /dev/null
@@ -1,162 +0,0 @@
-{
- # CrowdSec LAPI connection
- crowdsec {
- api_url https://{{ services['crowdsec']['domain'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}
- api_key "{file./run/secrets/CADDY_CROWDSEC_KEY}"
- }
-}
-
-# Snippets
-# CrowdSec log for parser
-(crowdsec_log) {
- log {
- output file /log/access.log {
- mode 0644
- roll_size 100MiB
- roll_keep 1
- }
- format json
- }
-}
-# Private TLS ACME with DNS-01-challenge
-(private_tls) {
- tls {
- issuer acme {
- dir https://{{ services['ca']['domain'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}/acme/acme@{{ domain['internal'] }}/directory
- dns rfc2136 {
- server {{ services['bind']['domain'] }}.{{ domain['internal'] }}:{{ services['bind']['ports']['dns'] }}
- key_name acme-key
- key_alg hmac-sha256
- key "{file./run/secrets/CADDY_ACME_KEY}"
- }
- resolvers {{ services['bind']['domain'] }}.{{ domain['internal'] }}
- }
- }
-}
-
-# Public domain
-{{ services['authelia']['domain'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy host.containers.internal:{{ services['authelia']['ports']['http'] }}
- }
-}
-# test.ilnmors.com {
-# import crowdsec_log
-# route {
-# crowdsec
-# forward_auth host.containers.internal:9091 {
-# # Authelia Forward Auth endpoint URI
-# uri /api/authz/forward-auth
-# copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
-# }
-# root * /usr/share/caddy
-# file_server
-# }
-# }
-# test.app.ilnmors.com {
-# import crowdsec_log
-# route {
-# crowdsec
-# reverse_proxy https://test.app.ilnmors.internal {
-# header_up Host {http.reverse_proxy.upstream.host}
-# }
-# }
-# }
-{{ services['vaultwarden']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{ services['vaultwarden']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['gitea']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{ services['gitea']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['immich']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{ services['immich']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['paperless']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{ services['paperless']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['nextcloud']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['collabora']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['collabora']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['sure']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['sure']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['outline']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['outline']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['memos']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['memos']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-{{ services['mealie']['domain']['public'] }}.{{ domain['public'] }} {
- import crowdsec_log
- route {
- crowdsec
- reverse_proxy https://{{services['mealie']['domain']['internal'] }}.{{ domain['internal'] }} {
- header_up Host {http.reverse_proxy.upstream.host}
- }
- }
-}
-
-# Internal domain
-{{ node['name'] }}.{{ domain['internal'] }} {
- import private_tls
- metrics
-}
diff --git a/config/services/containers/common/caddy/etc/infra/Caddyfile.j2 b/config/services/containers/common/caddy/etc/infra/Caddyfile.j2
deleted file mode 100644
index 6420833..0000000
--- a/config/services/containers/common/caddy/etc/infra/Caddyfile.j2
+++ /dev/null
@@ -1,41 +0,0 @@
-# Private TLS ACME with DNS-01-challenge
-(private_tls) {
- tls {
- issuer acme {
- dir https://{{ services['ca']['domain'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}/acme/acme@{{ domain['internal'] }}/directory
- dns rfc2136 {
- server {{ services['bind']['domain'] }}.{{ domain['internal'] }}:{{ services['bind']['ports']['dns'] }}
- key_name acme-key
- key_alg hmac-sha256
- key "{file./run/secrets/CADDY_ACME_KEY}"
- }
- resolvers {{ services['bind']['domain'] }}.{{ domain['internal'] }}
- }
- }
-}
-
-{{ node['name'] }}.{{ domain['internal'] }} {
- import private_tls
- metrics
-}
-
-{{ services['ldap']['domain'] }}.{{ domain['internal'] }} {
- import private_tls
- route {
- reverse_proxy host.containers.internal:{{ services['ldap']['ports']['http'] }}
- }
-}
-
-{{ services['prometheus']['domain'] }}.{{ domain['internal'] }} {
- import private_tls
- route {
- reverse_proxy https://{{ services['prometheus']['domain'] }}.{{ domain['internal'] }}:{{ services['prometheus']['ports']['https'] }}
- }
-}
-
-{{ services['grafana']['domain'] }}.{{ domain['internal'] }} {
- import private_tls
- route {
- reverse_proxy host.containers.internal:{{ services['grafana']['ports']['http'] }}
- }
-}
diff --git a/config/services/containers/infra/ca/config/ca.json.j2 b/config/services/containers/infra/ca/config/ca.json.j2
index 1241cb7..17f9ca2 100644
--- a/config/services/containers/infra/ca/config/ca.json.j2
+++ b/config/services/containers/infra/ca/config/ca.json.j2
@@ -6,7 +6,7 @@
"address": ":9000",
"insecureAddress": "",
"dnsNames": [
- "{{ services['ca']['domain'] }}.{{ domain['internal'] }}"
+ "{{ services['ca']['domain']['internal'] }}.{{ domain['internal'] }}"
],
"logger": {
"format": "text"
diff --git a/config/services/containers/infra/ca/config/defaults.json.j2 b/config/services/containers/infra/ca/config/defaults.json.j2
index 5525b2e..ea76ad7 100644
--- a/config/services/containers/infra/ca/config/defaults.json.j2
+++ b/config/services/containers/infra/ca/config/defaults.json.j2
@@ -1,6 +1,6 @@
{
- "ca-url": "https://{{ services['ca']['domain'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}",
+ "ca-url": "https://{{ services['ca']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['ca']['ports']['https'] }}",
"ca-config": "/home/step/config/ca.json",
- "fingerprint": "215c851d2d0d2dbf90fc3507425207c29696ffd587c640c94a68dddb1d84d8e8",
+ "fingerprint": "",
"root": "/home/step/certs/{{ root_cert_filename }}"
}
diff --git a/config/services/containers/infra/grafana/etc/grafana.ini.j2 b/config/services/containers/infra/grafana/etc/grafana.ini.j2
index c1c3f7f..f554bd2 100644
--- a/config/services/containers/infra/grafana/etc/grafana.ini.j2
+++ b/config/services/containers/infra/grafana/etc/grafana.ini.j2
@@ -8,13 +8,13 @@ provisioning = /etc/grafana/provisioning
[server]
protocol = http
http_port = {{ services['grafana']['ports']['http'] }}
-domain = {{ services['grafana']['domain'] }}.{{ domain['internal'] }}
-root_url = http://{{ services['grafana']['domain'] }}.{{ domain['internal'] }}/
+domain = {{ services['grafana']['domain']['internal'] }}.{{ domain['internal'] }}
+root_url = https://{{ services['grafana']['domain']['internal'] }}.{{ domain['internal'] }}/
router_logging = false
[database]
type = postgres
-host = {{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}
+host = {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}
name = grafana_db
user = grafana
password = $__file{/run/secrets/GF_DB_PASSWORD}
diff --git a/config/services/containers/infra/grafana/etc/ldap.toml.j2 b/config/services/containers/infra/grafana/etc/ldap.toml.j2
index e9a14ea..c7e513d 100644
--- a/config/services/containers/infra/grafana/etc/ldap.toml.j2
+++ b/config/services/containers/infra/grafana/etc/ldap.toml.j2
@@ -1,6 +1,6 @@
# https://github.com/lldap/lldap/blob/main/example_configs/grafana_ldap_config.toml
[[servers]]
-host = "{{ services['ldap']['domain'] }}.{{ domain['internal'] }}"
+host = "{{ services['ldap']['domain']['internal'] }}.{{ domain['internal'] }}"
port = {{ services['ldap']['ports']['ldaps'] }}
# Activate STARTTLS or LDAPS
use_ssl = true
diff --git a/config/services/containers/infra/grafana/etc/provisioning/datasources/datasources.yaml.j2 b/config/services/containers/infra/grafana/etc/provisioning/datasources/datasources.yaml.j2
index 44630a3..1e52584 100644
--- a/config/services/containers/infra/grafana/etc/provisioning/datasources/datasources.yaml.j2
+++ b/config/services/containers/infra/grafana/etc/provisioning/datasources/datasources.yaml.j2
@@ -4,7 +4,7 @@ apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
- url: https://{{ services['prometheus']['domain'] }}.{{ domain['internal'] }}:{{ services['prometheus']['ports']['https'] }}
+ url: https://{{ services['prometheus']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['prometheus']['ports']['https'] }}
access: proxy
isDefault: true
jsonData:
@@ -16,7 +16,7 @@ datasources:
- name: Loki
type: loki
- url: https://{{ services['loki']['domain'] }}.{{ domain['internal'] }}:{{ services['loki']['ports']['https'] }}
+ url: https://{{ services['loki']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['loki']['ports']['https'] }}
access: proxy
jsonData:
tlsAuth: false
@@ -26,4 +26,4 @@ datasources:
maxLines: 1000
secureJsonData:
tlsCACert: "$__file{/etc/ssl/grafana/{{ root_cert_filename }}}"
- httpHeaderValue1: "{{ domain['internal'] }} "
+ httpHeaderValue1: "{{ domain['internal'] }}"
diff --git a/config/services/containers/infra/grafana/grafana.container.j2 b/config/services/containers/infra/grafana/grafana.container.j2
index 409fe85..5319fa7 100644
--- a/config/services/containers/infra/grafana/grafana.container.j2
+++ b/config/services/containers/infra/grafana/grafana.container.j2
@@ -13,10 +13,10 @@ Image=docker.io/grafana/grafana:{{ version['containers']['grafana'] }}
ContainerName=grafana
HostName=grafana
-AddHost={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:host-gateway
-AddHost={{ services['ldap']['domain'] }}.{{ domain['internal'] }}:host-gateway
-AddHost={{ services['prometheus']['domain'] }}.{{ domain['internal'] }}:host-gateway
-AddHost={{ services['loki']['domain'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['ldap']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['prometheus']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['loki']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
PublishPort={{ services['grafana']['ports']['http'] }}:3000/tcp
diff --git a/config/services/containers/infra/ldap/ldap.container.j2 b/config/services/containers/infra/ldap/ldap.container.j2
index c13f6ab..ffe0d92 100644
--- a/config/services/containers/infra/ldap/ldap.container.j2
+++ b/config/services/containers/infra/ldap/ldap.container.j2
@@ -13,7 +13,7 @@ Image=docker.io/lldap/lldap:{{ version['containers']['ldap'] }}
ContainerName=ldap
HostName=ldap
# They are at the same host (for Pasta, it is needed)
-AddHost={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:host-gateway
+AddHost={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:host-gateway
# For LDAPS - 636 > 6360 nftables
PublishPort={{ services['ldap']['ports']['ldaps'] }}:6360/tcp
# Web UI
diff --git a/config/services/containers/infra/postgresql/config/pg_hba.conf.j2 b/config/services/containers/infra/postgresql/config/pg_hba.conf.j2
index 888f3b3..79fce4e 100644
--- a/config/services/containers/infra/postgresql/config/pg_hba.conf.j2
+++ b/config/services/containers/infra/postgresql/config/pg_hba.conf.j2
@@ -1,29 +1,28 @@
# @authcomment@
-# TYPE DATABASE USER ADDRESS METHOD
-
+# TYPE DATABASE USER ADDRESS METHOD
# Local host `trust`
-local all all trust
+local all all trust
# Local monitoring connection (host - infra VM) `trust`
-hostssl postgres alloy {{ hostvars['fw']['network4']['infra']['server'] }}/32 trust
-hostssl postgres alloy {{ hostvars['fw']['network6']['infra']['server'] }}/128 trust
-hostssl postgres alloy {{ hostvars['fw']['network4']['subnet']['lla'] }} trust
-hostssl postgres alloy {{ hostvars['fw']['network6']['subnet']['lla'] }} trust
+hostssl postgres alloy {{ hostvars['fw']['network4']['infra']['server'] }}/32 trust
+hostssl postgres alloy {{ hostvars['fw']['network6']['infra']['server'] }}/128 trust
+hostssl postgres alloy {{ hostvars['fw']['network4']['subnet']['lla'] }} trust
+hostssl postgres alloy {{ hostvars['fw']['network6']['subnet']['lla'] }} trust
# Local connection (in postgresql container) needs password (127.0.0.1 - container loopback)
-host all all 127.0.0.1/32 scram-sha-256
-host all all ::1/128 scram-sha-256
+host all all 127.0.0.1/32 scram-sha-256
+host all all ::1/128 scram-sha-256
# Local connection (host - infra VM) needs password (169.254.1.0/24 - link_local subnet for containers in pasta mode)
-hostssl all all {{ hostvars['fw']['network4']['infra']['server'] }}/32 scram-sha-256
-hostssl all all {{ hostvars['fw']['network6']['infra']['server'] }}/128 scram-sha-256
-hostssl all all {{ hostvars['fw']['network4']['subnet']['lla'] }} scram-sha-256
-hostssl all all {{ hostvars['fw']['network6']['subnet']['lla'] }} scram-sha-256
+hostssl all all {{ hostvars['fw']['network4']['infra']['server'] }}/32 scram-sha-256
+hostssl all all {{ hostvars['fw']['network6']['infra']['server'] }}/128 scram-sha-256
+hostssl all all {{ hostvars['fw']['network4']['subnet']['lla'] }} scram-sha-256
+hostssl all all {{ hostvars['fw']['network6']['subnet']['lla'] }} scram-sha-256
# auth VM
-hostssl all all {{ hostvars['fw']['network4']['auth']['server'] }}/32 scram-sha-256
-hostssl all all {{ hostvars['fw']['network6']['auth']['server'] }}/128 scram-sha-256
+hostssl all all {{ hostvars['fw']['network4']['auth']['server'] }}/32 scram-sha-256
+hostssl all all {{ hostvars['fw']['network6']['auth']['server'] }}/128 scram-sha-256
# app VM (Applications, 192.168.10.13)
-hostssl all all {{ hostvars['fw']['network4']['app']['server'] }}/32 scram-sha-256
-hostssl all all {{ hostvars['fw']['network6']['app']['server'] }}/128 scram-sha-256
+hostssl all all {{ hostvars['fw']['network4']['app']['server'] }}/32 scram-sha-256
+hostssl all all {{ hostvars['fw']['network6']['app']['server'] }}/128 scram-sha-256
diff --git a/config/services/containers/infra/postgresql/config/postgresql.conf.j2 b/config/services/containers/infra/postgresql/config/postgresql.conf.j2
index 1911f45..de38079 100644
--- a/config/services/containers/infra/postgresql/config/postgresql.conf.j2
+++ b/config/services/containers/infra/postgresql/config/postgresql.conf.j2
@@ -41,4 +41,4 @@ autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_scale_factor = 0.05
autovacuum_vacuum_cost_limit = 1000
effective_io_concurrency = 200
-random_page_cost = 1.2
\ No newline at end of file
+random_page_cost = 1.2
diff --git a/config/services/containers/infra/postgresql/services/postgresql-cluster-backup.service b/config/services/containers/infra/postgresql/services/postgresql-cluster-backup.service
index 91405d3..b6e8a15 100644
--- a/config/services/containers/infra/postgresql/services/postgresql-cluster-backup.service
+++ b/config/services/containers/infra/postgresql/services/postgresql-cluster-backup.service
@@ -11,8 +11,12 @@ StandardOutput=journal
StandardError=journal
ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/cluster && chown postgres:root /backups/cluster && chmod 770 /backups/cluster"
+ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/sql && chown postgres:root /backups/sql && chmod 770 /backups/sql"
+
# Run the script
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'pg_dumpall -U postgres --schema-only | grep -v -E "CREATE ROLE postgres" > /backups/cluster/pg_cluster_$(date "+%%Y-%%m-%%d").sql'
-ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/cluster -maxdepth 1 -type f -mtime +7 -delete"
+ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'cp /backups/cluster/pg_cluster_$(date "+%%Y-%%m-%%d").sql /backups/sql/pg_cluster.sql'
+ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/cluster -maxdepth 1 -type f -name 'pg_cluster_*.sql' -mtime +7 -delete"
ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/cluster && chmod 660 /backups/cluster/*"
+ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/sql && chmod 660 /backups/sql/pg_cluster.sql"
diff --git a/config/services/containers/infra/postgresql/services/postgresql-data-backup@.service b/config/services/containers/infra/postgresql/services/postgresql-data-backup@.service
index 2a7f5a2..76b1723 100644
--- a/config/services/containers/infra/postgresql/services/postgresql-data-backup@.service
+++ b/config/services/containers/infra/postgresql/services/postgresql-data-backup@.service
@@ -11,6 +11,7 @@ StandardOutput=journal
StandardError=journal
ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/%i && chown postgres:root /backups/%i && chmod 770 /backups/%i"
+ExecStartPre=/usr/bin/podman exec postgresql sh -c "mkdir -p /backups/sql && chown postgres:root /backups/sql && chmod 770 /backups/sql"
# Run the script
## DB Connection
@@ -21,5 +22,7 @@ ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'printf "SET session
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'pg_dump -U postgres -d %i_db --data-only >> /backups/%i/pg_%i_$(date "+%%Y-%%m-%%d").sql'
## reset session replication role
ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'printf "SET session_replication_role = origin;\n" >> /backups/%i/pg_%i_$(date "+%%Y-%%m-%%d").sql'
-ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/%i -maxdepth 1 -type f -mtime +7 -delete"
+ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c 'cp -a /backups/%i/pg_%i_$(date "+%%Y-%%m-%%d").sql /backups/sql/pg_%i.sql'
+ExecStart=/usr/bin/podman exec -u postgres postgresql sh -c "find /backups/%i -maxdepth 1 -type f -name 'pg_%i_*.sql' -mtime +7 -delete"
ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/%i && chmod 660 /backups/%i/*"
+ExecStart=/usr/bin/podman exec postgresql sh -c "chown -R postgres:root /backups/sql && chmod 660 /backups/sql/pg_%i.sql"
diff --git a/config/services/containers/infra/prometheus/etc/prometheus.yaml.j2 b/config/services/containers/infra/prometheus/etc/prometheus.yaml.j2
index f6cd455..34d6075 100644
--- a/config/services/containers/infra/prometheus/etc/prometheus.yaml.j2
+++ b/config/services/containers/infra/prometheus/etc/prometheus.yaml.j2
@@ -24,7 +24,7 @@ scrape_configs:
scheme: "https"
tls_config:
ca_file: "/etc/ssl/prometheus/{{ root_cert_filename }}"
- server_name: "{{ services['prometheus']['domain'] }}.{{ domain['internal'] }}"
+ server_name: "{{ ['internal'] }}.{{ domain['internal'] }}"
static_configs:
- targets: ["localhost:9090"]
# The label name is added as a label `label_name=` to any timeseries scraped from this config.
diff --git a/config/services/containers/infra/prometheus/etc/rules.yaml.j2 b/config/services/containers/infra/prometheus/etc/rules.yaml.j2
index 808c0db..fbb157f 100644
--- a/config/services/containers/infra/prometheus/etc/rules.yaml.j2
+++ b/config/services/containers/infra/prometheus/etc/rules.yaml.j2
@@ -1,7 +1,7 @@
groups:
- name: node_exporters_heartbeat
rules:
-{% for instance in ['vmm', 'fw', 'infra', 'auth', 'app'] %}
+{% for instance in ["vmm", "fw", "infra", "auth", "app"] %}
- alert: {{ instance }}_node_exporter_down
expr: |
(present_over_time(up{instance="{{ instance }}"}[5m]) or on() vector(0)) == 0
@@ -25,7 +25,7 @@ groups:
description: "postgresql node is down for 5 mins."
- name: Certificate_expiry_check
rules:
-{% for filename in ['root.crt', 'intermediate.crt', 'crowdsec.crt', 'blocky.crt', 'postgresql.crt', 'ldap.crt', 'prometheus.crt', 'loki.crt', 'dsm.crt'] %}
+{% for filename in ["root.crt", "intermediate.crt", "crowdsec.crt", "blocky.crt", "kopia.crt", "postgresql.crt", "ldap.crt", "prometheus.crt", "loki.crt"] %}
- alert: {{ filename | replace('.', '_') }}_is_expired_soon
expr: |
max(x509_cert_not_after{filename="{{ filename }}"}) - time() < 2592000
diff --git a/config/services/systemd/bk/rclone/config/rclone.config.j2 b/config/services/systemd/bk/rclone/config/rclone.config.j2
new file mode 100644
index 0000000..30d0f4f
--- /dev/null
+++ b/config/services/systemd/bk/rclone/config/rclone.config.j2
@@ -0,0 +1,13 @@
+[gdrive]
+type = drive
+client_id = {{ hostvars['console']['rclone']['google_drive']['oidc']['id'] }}
+client_secret = {{ hostvars['console']['rclone']['google_drive']['oidc']['secret'] }}
+scope = drive
+token = {{
+ {
+ "access_token":"expired",
+ "token_type":"Bearer",
+ "refresh_token":hostvars['console']['rclone']['google_drive']['refresh_token'],
+ "expiry":"1970-01-01T00:00:00Z",
+ } | to_json
+}}
diff --git a/config/services/systemd/bk/rclone/rclone.service.j2 b/config/services/systemd/bk/rclone/rclone.service.j2
new file mode 100644
index 0000000..8c71c2a
--- /dev/null
+++ b/config/services/systemd/bk/rclone/rclone.service.j2
@@ -0,0 +1,28 @@
+[Unit]
+Description=Daily Kopia rclone backup service
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+Type=oneshot
+
+# logging
+StandardOutput=journal
+StandardError=journal
+
+Environment="RCLONE_CONFIG=/etc/secrets/{{ node['uid'] }}/rclone/rclone.config"
+
+ExecStart=/usr/bin/rclone copy %h/data/kopia/ gdrive:kopia \
+ --transfers=4 \
+ --checkers=4 \
+ --tpslimit=8 \
+ --tpslimit-burst=4 \
+ --drive-chunk-size=64M \
+ --retries=20 \
+ --low-level-retries=10 \
+ --retries-sleep=30s \
+ --timeout=3m \
+ --contimeout=30s \
+ --drive-stop-on-upload-limit \
+ --stats=30s \
+ --log-level=INFO
diff --git a/config/services/systemd/bk/rclone/rclone.timer.j2 b/config/services/systemd/bk/rclone/rclone.timer.j2
new file mode 100644
index 0000000..1353ecd
--- /dev/null
+++ b/config/services/systemd/bk/rclone/rclone.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=Daily Kopia rclone backup timer
+
+[Timer]
+OnCalendar=*-*-* 09:00:00
+Persistent=true
+RandomizedDelaySec=300
+
+[Install]
+WantedBy=timers.target
diff --git a/config/services/systemd/common/alloy/config.alloy.j2 b/config/services/systemd/common/alloy/config.alloy.j2
index 3f7b220..f531716 100644
--- a/config/services/systemd/common/alloy/config.alloy.j2
+++ b/config/services/systemd/common/alloy/config.alloy.j2
@@ -6,7 +6,7 @@
//// Metric ouput
prometheus.remote_write "prometheus" {
endpoint {
- url = "https://{{ services['prometheus']['domain'] }}.{{ domain['internal'] }}:{{ services['prometheus']['ports']['https'] }}/api/v1/write"
+ url = "https://{{ services['prometheus']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['prometheus']['ports']['https'] }}/api/v1/write"
}
}
@@ -71,8 +71,8 @@ prometheus.scrape "system" {
////// For Crowdsec metrics
prometheus.scrape "crowdsec" {
targets = [
- { "__address__" = "{{ services['crowdsec']['domain'] }}.{{ domain['internal'] }}:6060", "job" = "crowdsec" },
- { "__address__" = "{{ services['crowdsec']['domain'] }}.{{ domain['internal'] }}:60601", "job" = "crowdsec-bouncer" },
+ { "__address__" = "{{ services['crowdsec']['domain']['internal'] }}.{{ domain['internal'] }}:6060", "job" = "crowdsec" },
+ { "__address__" = "{{ services['crowdsec']['domain']['internal'] }}.{{ domain['internal'] }}:60601", "job" = "crowdsec-bouncer" },
]
honor_labels = true
forward_to = [prometheus.relabel.default_label.receiver]
@@ -83,7 +83,7 @@ prometheus.scrape "crowdsec" {
////// For postgresql metrics
prometheus.exporter.postgres "postgresql" {
data_source_names = [
- "postgres://alloy@{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}/postgres?sslmode=verify-full",
+ "postgres://alloy@{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}/postgres?sslmode=verify-full",
]
}
prometheus.scrape "postgresql" {
@@ -99,7 +99,7 @@ prometheus.scrape "x509" {
}
{% endif %}
-{% if node['name'] in ['infra', 'auth', 'app'] %}
+{% if node['name'] in ["infra", "auth", "app"] %}
////// For Input Caddy metrics
prometheus.scrape "caddy" {
targets = [
@@ -114,7 +114,7 @@ prometheus.scrape "caddy" {
//// Logs output
loki.write "loki" {
endpoint {
- url = "https://{{ services['loki']['domain'] }}.{{ domain['internal'] }}:{{ services['loki']['ports']['https'] }}/loki/api/v1/push"
+ url = "https://{{ services['loki']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['loki']['ports']['https'] }}/loki/api/v1/push"
tenant_id = "{{ domain['internal'] }}"
}
}
diff --git a/config/services/systemd/common/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.j2 b/config/services/systemd/common/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.j2
index f2201b6..c91f986 100644
--- a/config/services/systemd/common/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.j2
+++ b/config/services/systemd/common/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml.j2
@@ -8,7 +8,7 @@ log_compression: true
log_max_size: 100
log_max_backups: 3
log_max_age: 30
-api_url: "https://{{ services['crowdsec']['domain'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}"
+api_url: "https://{{ services['crowdsec']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}"
api_key: "{{ hostvars['console']['crowdsec']['bouncer']['fw'] }}"
insecure_skip_verify: false
disable_ipv6: false
diff --git a/config/services/systemd/common/crowdsec/etc/local_api_credentials.yaml.j2 b/config/services/systemd/common/crowdsec/etc/local_api_credentials.yaml.j2
index 752ba69..93f6054 100644
--- a/config/services/systemd/common/crowdsec/etc/local_api_credentials.yaml.j2
+++ b/config/services/systemd/common/crowdsec/etc/local_api_credentials.yaml.j2
@@ -1,3 +1,3 @@
-url: https://{{ services['crowdsec']['domain'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}
+url: https://{{ services['crowdsec']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['crowdsec']['ports']['https'] }}
login: {{ node['name'] }}
password: {{ hostvars['console']['crowdsec']['machine'][node['name']] }}
diff --git a/config/services/systemd/common/kopia/kopia-backup.service.j2 b/config/services/systemd/common/kopia/kopia-backup.service.j2
index 96bce14..7cf0606 100644
--- a/config/services/systemd/common/kopia/kopia-backup.service.j2
+++ b/config/services/systemd/common/kopia/kopia-backup.service.j2
@@ -28,8 +28,10 @@ BindPaths=/etc/secrets/{{ kopia_uid }}
BindPaths=/var/cache/kopia
EnvironmentFile=/etc/secrets/{{ kopia_uid }}/kopia.env
+ExecStartPre=/usr/bin/nc -zv {{ services['kopia']['domain']['internal'] }}.{{ domain['internal'] }} 443
+
ExecStartPre=/usr/bin/kopia repository connect server \
- --url=https://{{ services['kopia']['domain'] }}.{{ domain['internal'] }}:{{ services['kopia']['ports']['https'] }} \
+ --url=https://{{ services['kopia']['domain']['internal'] }}.{{ domain['internal'] }}:443 \
--override-username={{ node['name'] }} \
--override-hostname={{ node['name'] }}.{{ domain['internal'] }}
diff --git a/config/services/systemd/common/kopia/kopia-server.service.j2 b/config/services/systemd/common/kopia/kopia-server.service.j2
new file mode 100644
index 0000000..f80857e
--- /dev/null
+++ b/config/services/systemd/common/kopia/kopia-server.service.j2
@@ -0,0 +1,24 @@
+[Unit]
+Description=Kopia repository server
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+# logging
+StandardOutput=journal
+StandardError=journal
+
+EnvironmentFile=/etc/secrets/{{ node['uid'] }}/kopia.env
+
+ExecStartPre=/usr/bin/kopia repository connect filesystem \
+ --path={{ node['home_path'] }}/data/kopia/repository
+
+ExecStart=/usr/bin/kopia server start \
+ --no-ui \
+ --tls-cert-file=/etc/kopia/ssl/kopia.crt \
+ --tls-key-file=/etc/kopia/ssl/kopia.key \
+ --address=0.0.0.0:{{ services['kopia']['ports']['https'] }} \
+ --log-level=info
+
+[Install]
+WantedBy=default.target
diff --git a/config/services/systemd/common/kopia/kopia.env.j2 b/config/services/systemd/common/kopia/kopia.env.j2
index 70477b1..6e27a2e 100644
--- a/config/services/systemd/common/kopia/kopia.env.j2
+++ b/config/services/systemd/common/kopia/kopia.env.j2
@@ -1,4 +1,8 @@
+{% if node['name'] == "bk" %}
+KOPIA_PASSWORD={{ hostvars['console']['kopia']['repository'] }}
+{% elif node['name'] in ["infra", "app"] %}
KOPIA_PASSWORD={{ hostvars['console']['kopia']['users'][node['name']] }}
+{% endif %}
KOPIA_CONFIG_PATH=/etc/kopia/repository.config
KOPIA_CACHE_DIRECTORY=/var/cache/kopia
KOPIA_LOG_DIR=/var/cache/kopia/logs
diff --git a/config/services/systemd/fw/bind/lib/db.1.00df.ip6.arpa b/config/services/systemd/fw/bind/lib/db.1.00df.ip6.arpa
index 62c6181..a4fd193 100644
--- a/config/services/systemd/fw/bind/lib/db.1.00df.ip6.arpa
+++ b/config/services/systemd/fw/bind/lib/db.1.00df.ip6.arpa
@@ -9,5 +9,4 @@ $TTL 86400
)
IN NS bind.ilnmors.internal.
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR fw.ilnmors.internal.
-1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR nas.ilnmors.internal.
0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR console.ilnmors.internal.
diff --git a/config/services/systemd/fw/bind/lib/db.1.168.192.in-addr.arpa b/config/services/systemd/fw/bind/lib/db.1.168.192.in-addr.arpa
index e011c72..a6d7501 100644
--- a/config/services/systemd/fw/bind/lib/db.1.168.192.in-addr.arpa
+++ b/config/services/systemd/fw/bind/lib/db.1.168.192.in-addr.arpa
@@ -9,5 +9,6 @@ $TTL 86400
)
IN NS bind.ilnmors.internal.
1 IN PTR fw.ilnmors.internal.
-11 IN PTR nas.ilnmors.internal.
+2 IN PTR switch.ilnmors.internal.
20 IN PTR console.ilnmors.internal.
+101 IN PTR printer.ilnmors.internal.
diff --git a/config/services/systemd/fw/bind/lib/db.10.00df.ip6.arpa b/config/services/systemd/fw/bind/lib/db.10.00df.ip6.arpa
index 0d9bd6c..0663dac 100644
--- a/config/services/systemd/fw/bind/lib/db.10.00df.ip6.arpa
+++ b/config/services/systemd/fw/bind/lib/db.10.00df.ip6.arpa
@@ -11,6 +11,7 @@ $TTL 86400
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR fw.ilnmors.internal.
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR blocky.ilnmors.internal.
3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR bind.ilnmors.internal.
+9.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR bk.ilnmors.internal.
0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR vmm.ilnmors.internal.
1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR infra.ilnmors.internal.
2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR auth.ilnmors.internal.
diff --git a/config/services/systemd/fw/bind/lib/db.10.168.192.in-addr.arpa b/config/services/systemd/fw/bind/lib/db.10.168.192.in-addr.arpa
index dea0da8..c024ea7 100644
--- a/config/services/systemd/fw/bind/lib/db.10.168.192.in-addr.arpa
+++ b/config/services/systemd/fw/bind/lib/db.10.168.192.in-addr.arpa
@@ -11,6 +11,7 @@ $TTL 86400
1 IN PTR fw.ilnmors.internal.
2 IN PTR blocky.ilnmors.internal.
3 IN PTR bind.ilnmors.internal.
+9 IN PTR bk.ilnmors.internal.
10 IN PTR vmm.ilnmors.internal.
11 IN PTR infra.ilnmors.internal.
12 IN PTR auth.ilnmors.internal.
diff --git a/config/services/systemd/fw/bind/lib/db.ilnmors.com b/config/services/systemd/fw/bind/lib/db.ilnmors.com
index f9e03d4..308a9c1 100644
--- a/config/services/systemd/fw/bind/lib/db.ilnmors.com
+++ b/config/services/systemd/fw/bind/lib/db.ilnmors.com
@@ -8,5 +8,7 @@ $TTL 86400
86400 ; minimum (1 day)
)
IN NS bind.ilnmors.internal.
+@ IN A 192.168.10.12
+@ IN AAAA fd00:10::12
* IN A 192.168.10.12
* IN AAAA fd00:10::12
diff --git a/config/services/systemd/fw/bind/lib/db.ilnmors.internal b/config/services/systemd/fw/bind/lib/db.ilnmors.internal
index 4c45d46..9e1c2d3 100644
--- a/config/services/systemd/fw/bind/lib/db.ilnmors.internal
+++ b/config/services/systemd/fw/bind/lib/db.ilnmors.internal
@@ -14,6 +14,8 @@ fw IN A 192.168.10.1
fw IN AAAA fd00:10::1
blocky IN A 192.168.10.2
blocky IN AAAA fd00:10::2
+bk IN A 192.168.10.9
+bk IN AAAA fd00:10::9
vmm IN A 192.168.10.10
vmm IN AAAA fd00:10::10
infra IN A 192.168.10.11
@@ -23,13 +25,12 @@ auth IN AAAA fd00:10::12
app IN A 192.168.10.13
app IN AAAA fd00:10::13
switch IN A 192.168.1.2
-nas IN A 192.168.1.11
-nas IN AAAA fd00:1::11
console IN A 192.168.1.20
console IN AAAA fd00:1::20
printer IN A 192.168.1.101
ntp IN CNAME fw.ilnmors.internal.
crowdsec IN CNAME fw.ilnmors.internal.
+kopia IN CNAME bk.ilnmors.internal.
ca IN CNAME infra.ilnmors.internal.
postgresql IN CNAME infra.ilnmors.internal.
ldap IN CNAME infra.ilnmors.internal.
diff --git a/config/services/systemd/fw/blocky/etc/config.yaml.j2 b/config/services/systemd/fw/blocky/etc/config.yaml.j2
index e7a7bdf..36736a8 100644
--- a/config/services/systemd/fw/blocky/etc/config.yaml.j2
+++ b/config/services/systemd/fw/blocky/etc/config.yaml.j2
@@ -5,14 +5,14 @@ connectIPVersion: dual
ports:
dns:
- - "{{ hostvars['fw']['network4']['blocky']['server'] }}:53"
- - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:53"
+ - "{{ hostvars['fw']['network4']['blocky']['server'] }}:{{ services['blocky']['ports']['dns'] }}"
+ - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:{{ services['blocky']['ports']['dns'] }}"
tls:
- - "{{ hostvars['fw']['network4']['blocky']['server'] }}:853"
- - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:853"
+ - "{{ hostvars['fw']['network4']['blocky']['server'] }}:{{ services['blocky']['ports']['dot'] }}"
+ - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:{{ services['blocky']['ports']['dot'] }}"
https:
- - "{{ hostvars['fw']['network4']['blocky']['server'] }}:443"
- - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:443"
+ - "{{ hostvars['fw']['network4']['blocky']['server'] }}:{{ services['blocky']['ports']['https'] }}"
+ - "[{{ hostvars['fw']['network6']['blocky']['server'] }}]:{{ services['blocky']['ports']['https'] }}"
log:
level: info
@@ -31,13 +31,13 @@ upstreams:
conditional:
fallbackUpstream: false
mapping:
- ilnmors.internal: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
- ilnmors.com: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
+ {{ domain['internal'] }}: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
+ {{ domain['public'] }}: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
1.168.192.in-addr.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
10.168.192.in-addr.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
0.0.0.0.0.0.0.0.1.0.0.0.0.0.d.f.ip6.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
0.0.0.0.0.0.0.0.0.1.0.0.0.0.d.f.ip6.arpa: "{{ hostvars['fw']['network4']['bind']['server'] }}, {{ hostvars['fw']['network6']['bind']['server'] }}"
- vpn.ilnmors.com: "tcp-tls:1.1.1.1:853, tcp-tls:1.0.0.1:853, tcp-tls:[2606:4700:4700::1111]:853, tcp-tls:[2606:4700:4700::1001]:853"
+ vpn.{{ domain['public'] }}: "tcp-tls:1.1.1.1:853, tcp-tls:1.0.0.1:853, tcp-tls:[2606:4700:4700::1111]:853, tcp-tls:[2606:4700:4700::1001]:853"
blocking:
blockType: nxDomain
diff --git a/config/services/systemd/fw/ddns/ddns.sh b/config/services/systemd/fw/ddns/ddns.sh
index f564544..8ef2a31 100644
--- a/config/services/systemd/fw/ddns/ddns.sh
+++ b/config/services/systemd/fw/ddns/ddns.sh
@@ -17,25 +17,27 @@ CURRENT_IP=""
# usage() function
usage() {
- echo "Usage: $0 -d \"domain\" [-t \"ttl\"] [-p] [-r]"
- echo "-d : Specify the domain to update"
- echo "-t : Specify the TTL(Time to live)"
- echo "-p: Specify the cloudflare proxy to use"
- echo "-r: Delete the DNS record"
- exit 1
+ echo "Usage: $0 -d \"domain\" [-t \"ttl\"] [-p] [-r]"
+ echo "-d : Specify the domain to update"
+ echo "-t : Specify the TTL(Time to live)"
+ echo "-p: Specify the cloudflare proxy to use"
+ echo "-r: Delete the DNS record"
+ exit 1
}
# Log function
log() {
- local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
+ local timestamp
local level="$1"
local msg="$2"
- echo "time=\"$timestamp\" level=\"$level\" msg=\"$msg\" source=\"ddns.sh\"">&2
+
+ timestamp="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
+ echo "time=\"$timestamp\" level=\"$level\" msg=\"$msg\" source=\"ddns.sh\"" >&2
}
# getopts to get arguments
while getopts "d:t:pr" opt; do
- case $opt in
+ case "$opt" in
d)
DOMAIN="$OPTARG"
;;
@@ -60,26 +62,26 @@ while getopts "d:t:pr" opt; do
done
# Get option and move to parameters - This has no functional thing, because it only use arguments with parameters
-shift $((OPTIND - 1))
+shift "$((OPTIND - 1))"
# Check necessary options
-if [ -z "$DOMAIN" ]; then
+if [[ -z "$DOMAIN" ]]; then
log "error" "-d option is required"
usage
fi
-if ! [[ "$TTL" =~ ^[0-9]+$ ]] || [ "$TTL" -le 0 ]; then
+if ! [[ "$TTL" =~ ^[0-9]+$ ]] || [[ "$TTL" -le 0 ]]; then
log "error" "-t option (ttl) requires a number above 0."
usage
fi
# Check necessary environment variables (Injected by systemd or shell)
-if [ -z "$ZONE_ID" ]; then
+if [[ -z "$ZONE_ID" ]]; then
log "error" "ZONE_ID is required via environment variable."
exit 1
fi
-if [ -z "$API_KEY" ]; then
+if [[ -z "$API_KEY" ]]; then
log "error" "API_KEY is required via environment variable."
exit 1
fi
@@ -89,6 +91,7 @@ if ! command -v curl >/dev/null; then
log "error" "curl is required"
exit 1
fi
+
if ! command -v jq >/dev/null; then
log "error" "jq is required"
exit 1
@@ -100,32 +103,61 @@ CONTENT_TYPE="Content-Type: application/json"
AUTHORIZATION="Authorization: Bearer $API_KEY"
# Current IP
-CURRENT_IP=$( ip address show dev wan | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 )
+CURRENT_IP="$(ip address show dev wan | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)"
+
# Get current IP from external server when IP is private IP
if [[ -z "$CURRENT_IP" || "$CURRENT_IP" =~ ^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|127\.) ]]; then
log "info" "IP from interface is private or empty. Fetching public IP..."
- CURRENT_IP=$(curl -sf "https://ifconfig.me") ||\
- CURRENT_IP=$(curl -sf "https://ifconfig.kr") ||\
- CURRENT_IP=$(curl -sf "https://api.ipify.org")
+ CURRENT_IP="$(curl -sf "https://ifconfig.me")" || \
+ CURRENT_IP="$(curl -sf "https://ifconfig.kr")" || \
+ CURRENT_IP="$(curl -sf "https://api.ipify.org")"
fi
-if [ "$CURRENT_IP" == "" ]; then
+
+if [[ -z "$CURRENT_IP" ]]; then
log "error" "Can't get an IP"
exit 1
fi
# DNS functions
-# get_dns_record() function
-get_dns_record()
-{
+# build_dns_payload() function
+build_dns_payload() {
local type="$1"
local name="$2"
+ local ttl="$3"
+ local comment="$4"
+ local content="$5"
- local response="$(
- curl -s "$URL?type=$type&name=$name"\
- -H "$CONTENT_TYPE"\
- -H "$AUTHORIZATION")"
- if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
+ jq -n \
+ --arg name "$name" \
+ --argjson ttl "$ttl" \
+ --arg type "$type" \
+ --arg comment "$comment" \
+ --arg content "$content" \
+ --argjson proxied "$PROXIED" \
+ '{
+ name: $name,
+ ttl: $ttl,
+ type: $type,
+ comment: $comment,
+ content: $content,
+ proxied: $proxied
+ }'
+}
+
+# get_dns_record() function
+get_dns_record() {
+ local type="$1"
+ local name="$2"
+ local response
+
+ response="$(
+ curl -s "$URL?type=$type&name=$name" \
+ -H "$CONTENT_TYPE" \
+ -H "$AUTHORIZATION"
+ )"
+
+ if [[ "$(jq -r '.success' <<< "$response")" == "false" ]]; then
log "error" "Can't get dns record by $response"
exit 1
else
@@ -135,27 +167,26 @@ get_dns_record()
}
# create_dns_record() function
-create_dns_record()
-{
+create_dns_record() {
local type="$1"
local name="$2"
local ttl="$3"
local comment="$4"
local content="$5"
- local response="$(
- curl -s "$URL"\
- -X POST\
- -H "$CONTENT_TYPE"\
- -H "$AUTHORIZATION"\
- -d "{
- \"name\": \"$name\",
- \"ttl\": $ttl,
- \"type\": \"$type\",
- \"comment\": \"$comment\",
- \"content\": \"$content\",
- \"proxied\": $PROXIED
- }")"
- if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
+ local payload
+ local response
+
+ payload="$(build_dns_payload "$type" "$name" "$ttl" "$comment" "$content")"
+
+ response="$(
+ curl -s "$URL" \
+ -X POST \
+ -H "$CONTENT_TYPE" \
+ -H "$AUTHORIZATION" \
+ -d "$payload"
+ )"
+
+ if [[ "$(jq -r '.success' <<< "$response")" == "false" ]]; then
log "error" "Can't create dns record by $response"
exit 1
else
@@ -165,49 +196,49 @@ create_dns_record()
}
# update_dns_record() function
-update_dns_record()
-{
+update_dns_record() {
local type="$1"
local name="$2"
local ttl="$3"
local comment="$4"
local content="$5"
local id="$6"
- local response=$(
- curl -s "$URL/$id"\
- -X PUT\
- -H "$CONTENT_TYPE"\
- -H "$AUTHORIZATION"\
- -d "{
- \"name\": \"$name\",
- \"ttl\": $ttl,
- \"type\": \"$type\",
- \"comment\": \"$comment\",
- \"content\": \"$content\",
- \"proxied\": $PROXIED
- }")
- if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
+ local payload
+ local response
+
+ payload="$(build_dns_payload "$type" "$name" "$ttl" "$comment" "$content")"
+
+ response="$(
+ curl -s "$URL/$id" \
+ -X PUT \
+ -H "$CONTENT_TYPE" \
+ -H "$AUTHORIZATION" \
+ -d "$payload"
+ )"
+
+ if [[ "$(jq -r '.success' <<< "$response")" == "false" ]]; then
log "error" "Can't update dns record by $response"
exit 1
else
- #return
+ # return
echo "$response"
fi
}
# delete_dns_record() function
-delete_dns_record()
-{
+delete_dns_record() {
local type="$1"
local id="$2"
+ local response
- local response=$(
- curl -s "$URL/$id"\
- -X DELETE\
- -H "$CONTENT_TYPE"\
+ response="$(
+ curl -s "$URL/$id" \
+ -X DELETE \
+ -H "$CONTENT_TYPE" \
-H "$AUTHORIZATION"
- )
- if [ "$(echo "$response" | jq -r '.success')" == "false" ]; then
+ )"
+
+ if [[ "$(jq -r '.success' <<< "$response")" == "false" ]]; then
log "error" "Can't delete dns record by $response"
exit 1
else
@@ -217,44 +248,50 @@ delete_dns_record()
}
# Get DNS A, and CNAME record
-A_DNS_RECORD=$(get_dns_record "A" "$DOMAIN")
-S_DNS_RECORD=$(get_dns_record "CNAME" "*.$DOMAIN")
-W_DNS_RECORD=$(get_dns_record "CNAME" "www.$DOMAIN")
+A_DNS_RECORD="$(get_dns_record "A" "$DOMAIN")"
+S_DNS_RECORD="$(get_dns_record "CNAME" "*.$DOMAIN")"
+W_DNS_RECORD="$(get_dns_record "CNAME" "www.$DOMAIN")"
# Delete DNS record with Delete flag
-if [ "$DELETE_FLAG" == "true" ]; then
+if [[ "$DELETE_FLAG" == "true" ]]; then
FLAG="false"
- if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
- A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
+
+ if [[ "$(jq -r '.result | length' <<< "$A_DNS_RECORD")" -eq 1 ]]; then
+ A_DNS_ID="$(jq -r '.result[0].id' <<< "$A_DNS_RECORD")"
delete_dns_record "A" "$A_DNS_ID"
log "info" "root DNS record is deleted"
FLAG="true"
fi
- if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
- S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
+
+ if [[ "$(jq -r '.result | length' <<< "$S_DNS_RECORD")" -eq 1 ]]; then
+ S_DNS_ID="$(jq -r '.result[0].id' <<< "$S_DNS_RECORD")"
delete_dns_record "CNAME" "$S_DNS_ID"
log "info" "sub DNS record is deleted"
FLAG="true"
fi
- if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then
- W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
+
+ if [[ "$(jq -r '.result | length' <<< "$W_DNS_RECORD")" -eq 1 ]]; then
+ W_DNS_ID="$(jq -r '.result[0].id' <<< "$W_DNS_RECORD")"
delete_dns_record "CNAME" "$W_DNS_ID"
log "info" "www DNS record is deleted"
FLAG="true"
fi
- if [ "$FLAG" == "false" ]; then
+
+ if [[ "$FLAG" == "false" ]]; then
log "info" "Nothing is Deleted. There are no DNS records"
fi
+
exit
fi
# Create or update DNS A record
-if [ "$(echo $A_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # root DNS record exist
- A_DNS_ID="$(echo $A_DNS_RECORD | jq -r '.result[0].id')"
- A_DNS_CONTENT="$(echo $A_DNS_RECORD | jq -r '.result[0].content')"
- A_DNS_TTL="$(echo $A_DNS_RECORD | jq -r '.result[0].ttl')"
- A_DNS_PROXIED="$(echo $A_DNS_RECORD | jq -r '.result[0].proxied')"
- if [ "$A_DNS_CONTENT" != $CURRENT_IP -o "$A_DNS_TTL" != "$TTL" -o "$A_DNS_PROXIED" != "$PROXIED" ]; then
+if [[ "$(jq -r '.result | length' <<< "$A_DNS_RECORD")" -eq 1 ]]; then # root DNS record exist
+ A_DNS_ID="$(jq -r '.result[0].id' <<< "$A_DNS_RECORD")"
+ A_DNS_CONTENT="$(jq -r '.result[0].content' <<< "$A_DNS_RECORD")"
+ A_DNS_TTL="$(jq -r '.result[0].ttl' <<< "$A_DNS_RECORD")"
+ A_DNS_PROXIED="$(jq -r '.result[0].proxied' <<< "$A_DNS_RECORD")"
+
+ if [[ "$A_DNS_CONTENT" != "$CURRENT_IP" || "$A_DNS_TTL" != "$TTL" || "$A_DNS_PROXIED" != "$PROXIED" ]]; then
update_dns_record "A" "$DOMAIN" "$TTL" "$(date "+%Y-%m-%d %H:%M:%S"): root domain from ddns.sh" "$CURRENT_IP" "$A_DNS_ID"
log "info" "Root DNS record is successfully changed Domain: $DOMAIN IP: $A_DNS_CONTENT to $CURRENT_IP TTL: $A_DNS_TTL to $TTL proxied: $A_DNS_PROXIED to $PROXIED"
else
@@ -266,12 +303,13 @@ else # root DNS record does not exist
fi
# Create or update DNS CNAME records
-if [ "$(echo $S_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # sub DNS record exist
- S_DNS_ID="$(echo $S_DNS_RECORD | jq -r '.result[0].id')"
- S_DNS_CONTENT="$(echo $S_DNS_RECORD | jq -r '.result[0].content')"
- S_DNS_TTL="$(echo $S_DNS_RECORD | jq -r '.result[0].ttl')"
- S_DNS_PROXIED="$(echo $S_DNS_RECORD | jq -r '.result[0].proxied')"
- if [ "$S_DNS_CONTENT" != "$DOMAIN" -o "$S_DNS_TTL" != "$C_TTL" -o "$S_DNS_PROXIED" != "$PROXIED" ]; then
+if [[ "$(jq -r '.result | length' <<< "$S_DNS_RECORD")" -eq 1 ]]; then # sub DNS record exist
+ S_DNS_ID="$(jq -r '.result[0].id' <<< "$S_DNS_RECORD")"
+ S_DNS_CONTENT="$(jq -r '.result[0].content' <<< "$S_DNS_RECORD")"
+ S_DNS_TTL="$(jq -r '.result[0].ttl' <<< "$S_DNS_RECORD")"
+ S_DNS_PROXIED="$(jq -r '.result[0].proxied' <<< "$S_DNS_RECORD")"
+
+ if [[ "$S_DNS_CONTENT" != "$DOMAIN" || "$S_DNS_TTL" != "$C_TTL" || "$S_DNS_PROXIED" != "$PROXIED" ]]; then
update_dns_record "CNAME" "*.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): sub domain from ddns.sh" "$DOMAIN" "$S_DNS_ID"
log "info" "Sub DNS record is successfully changed Domain: $S_DNS_CONTENT to *.$DOMAIN CNAME: $DOMAIN TTL: $S_DNS_TTL to $C_TTL proxied: $S_DNS_PROXIED to $PROXIED"
else
@@ -282,12 +320,13 @@ else # sub DNS record does not exist
log "info" "Sub DNS record is successfully created Domain: *.$DOMAIN CNAME: $DOMAIN TTL: $C_TTL proxied: $PROXIED"
fi
-if [ "$(echo $W_DNS_RECORD | jq -r '.result | length')" -eq 1 ]; then # www DNS record exist
- W_DNS_ID="$(echo $W_DNS_RECORD | jq -r '.result[0].id')"
- W_DNS_CONTENT="$(echo $W_DNS_RECORD | jq -r '.result[0].content')"
- W_DNS_TTL="$(echo $W_DNS_RECORD | jq -r '.result[0].ttl')"
- W_DNS_PROXIED="$(echo $W_DNS_RECORD | jq -r '.result[0].proxied')"
- if [ "$W_DNS_CONTENT" != "$DOMAIN" -o "$W_DNS_TTL" != "$C_TTL" -o "$W_DNS_PROXIED" != "$PROXIED" ]; then
+if [[ "$(jq -r '.result | length' <<< "$W_DNS_RECORD")" -eq 1 ]]; then # www DNS record exist
+ W_DNS_ID="$(jq -r '.result[0].id' <<< "$W_DNS_RECORD")"
+ W_DNS_CONTENT="$(jq -r '.result[0].content' <<< "$W_DNS_RECORD")"
+ W_DNS_TTL="$(jq -r '.result[0].ttl' <<< "$W_DNS_RECORD")"
+ W_DNS_PROXIED="$(jq -r '.result[0].proxied' <<< "$W_DNS_RECORD")"
+
+ if [[ "$W_DNS_CONTENT" != "$DOMAIN" || "$W_DNS_TTL" != "$C_TTL" || "$W_DNS_PROXIED" != "$PROXIED" ]]; then
update_dns_record "CNAME" "www.$DOMAIN" "$C_TTL" "$(date "+%Y-%m-%d %H:%M:%S"): www domain from ddns.sh" "$DOMAIN" "$W_DNS_ID"
log "info" "www DNS record is successfully changed Domain: $W_DNS_CONTENT to www.$DOMAIN CNAME: $DOMAIN TTL: $W_DNS_TTL to $C_TTL proxied: $W_DNS_PROXIED to $PROXIED"
else
diff --git a/config/services/systemd/fw/kea/kea-dhcp4.conf.j2 b/config/services/systemd/fw/kea/kea-dhcp4.conf.j2
index 65e2952..04f1acf 100644
--- a/config/services/systemd/fw/kea/kea-dhcp4.conf.j2
+++ b/config/services/systemd/fw/kea/kea-dhcp4.conf.j2
@@ -28,15 +28,10 @@
"ip-address": "{{ hostvars['fw']['network4']['switch']['client'] }}",
"hostname": "switch"
},
- {
- "hw-address": "90:09:d0:65:a9:db",
- "ip-address": "{{ hostvars['fw']['network4']['nas']['client'] }}",
- "hostname": "nas"
- },
{
"hw-address": "d8:e2:df:ff:1b:d5",
"ip-address": "{{ hostvars['fw']['network4']['console']['client'] }}",
- "hostname": "surface"
+ "hostname": "console"
},
{
"hw-address": "38:ca:84:94:5e:06",
diff --git a/config/services/systemd/vmm/btrfs/btrfs-scrub-backup.service.j2 b/config/services/systemd/vmm/btrfs/btrfs-scrub-backup.service.j2
new file mode 100644
index 0000000..8f9fce6
--- /dev/null
+++ b/config/services/systemd/vmm/btrfs/btrfs-scrub-backup.service.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=BTRFS backup auto scrub
+ConditionPathIsMountPoint={{ hardware['disk']['backup']['fs']['mount_point'] }}
+RequiresMountsFor={{ hardware['disk']['backup']['fs']['mount_point'] }}
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/btrfs scrub start -Bd {{ hardware['disk']['backup']['fs']['mount_point'] }}
+Nice=19
+IOSchedulingClass=idle
diff --git a/config/services/systemd/vmm/btrfs/btrfs-scrub.timer.j2 b/config/services/systemd/vmm/btrfs/btrfs-scrub-backup.timer.j2
similarity index 100%
rename from config/services/systemd/vmm/btrfs/btrfs-scrub.timer.j2
rename to config/services/systemd/vmm/btrfs/btrfs-scrub-backup.timer.j2
diff --git a/config/services/systemd/vmm/btrfs/btrfs-scrub-data.service.j2 b/config/services/systemd/vmm/btrfs/btrfs-scrub-data.service.j2
new file mode 100644
index 0000000..3727c6a
--- /dev/null
+++ b/config/services/systemd/vmm/btrfs/btrfs-scrub-data.service.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=BTRFS data auto scrub
+ConditionPathIsMountPoint={{ hardware['disk']['data']['fs']['mount_point'] }}
+RequiresMountsFor={{ hardware['disk']['data']['fs']['mount_point'] }}
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/btrfs scrub start -Bd {{ hardware['disk']['data']['fs']['mount_point'] }}
+Nice=19
+IOSchedulingClass=idle
diff --git a/config/services/systemd/vmm/btrfs/btrfs-scrub-data.timer.j2 b/config/services/systemd/vmm/btrfs/btrfs-scrub-data.timer.j2
new file mode 100644
index 0000000..5b9216b
--- /dev/null
+++ b/config/services/systemd/vmm/btrfs/btrfs-scrub-data.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=Monthly BTRFS auto scrub
+
+[Timer]
+OnCalendar=*-*-01 04:00:00
+Persistent=true
+RandomizedDelaySec=300
+
+[Install]
+WantedBy=timers.target
diff --git a/config/services/systemd/vmm/btrfs/btrfs-scrub.service.j2 b/config/services/systemd/vmm/btrfs/btrfs-scrub.service.j2
deleted file mode 100644
index 9ee6e12..0000000
--- a/config/services/systemd/vmm/btrfs/btrfs-scrub.service.j2
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=BTRFS auto scrub
-ConditionPathIsMountPoint={{ hardware['btrfs']['mount_point'] }}
-RequiresMountsFor={{ hardware['btrfs']['mount_point'] }}
-
-[Service]
-Type=oneshot
-ExecStart=/usr/bin/btrfs scrub start -Bd {{ hardware['btrfs']['mount_point'] }}
-Nice=19
-IOSchedulingClass=idle
diff --git a/config/services/systemd/vmm/libvirt/services/app.service b/config/services/systemd/vmm/libvirt/services/app.service.j2
similarity index 59%
rename from config/services/systemd/vmm/libvirt/services/app.service
rename to config/services/systemd/vmm/libvirt/services/app.service.j2
index 24f814e..2983dae 100644
--- a/config/services/systemd/vmm/libvirt/services/app.service
+++ b/config/services/systemd/vmm/libvirt/services/app.service.j2
@@ -1,7 +1,9 @@
[Unit]
Description=app vm
-After=network-online.target libvirtd.service fw.service infra.service auth.service
-Wants=fw.service infra.service auth.service
+After=network-online.target libvirtd.service fw.service bk.service infra.service auth.service
+Wants=fw.service bk.service infra.service auth.service
+ConditionPathIsMountPoint={{ hardware['disk']['data']['fs']['mount_point'] }}
+RequiresMountsFor={{ hardware['disk']['data']['fs']['mount_point'] }}
[Service]
Type=oneshot
diff --git a/config/services/systemd/vmm/libvirt/services/auth.service b/config/services/systemd/vmm/libvirt/services/auth.service.j2
similarity index 100%
rename from config/services/systemd/vmm/libvirt/services/auth.service
rename to config/services/systemd/vmm/libvirt/services/auth.service.j2
diff --git a/config/services/systemd/vmm/libvirt/services/bk.service.j2 b/config/services/systemd/vmm/libvirt/services/bk.service.j2
new file mode 100644
index 0000000..0a8bad2
--- /dev/null
+++ b/config/services/systemd/vmm/libvirt/services/bk.service.j2
@@ -0,0 +1,25 @@
+[Unit]
+Description=bk vm
+After=network-online.target libvirtd.service fw.service
+Wants=fw.service
+ConditionPathIsMountPoint={{ hardware['disk']['backup']['fs']['mount_point'] }}
+RequiresMountsFor={{ hardware['disk']['backup']['fs']['mount_point'] }}
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+TimeoutStopSec=360
+
+ExecStart=/usr/bin/virsh -c qemu:///system start bk
+
+ExecStartPost=/bin/sleep 30
+
+ExecStop=/bin/bash -c '\
+ /usr/bin/virsh -c qemu:///system shutdown bk; \
+ while /usr/bin/virsh -c qemu:///system list --state-running --name | grep -q "bk"; do \
+ echo "Waiting for bk to shutdown..."; \
+ sleep 2; \
+ done'
+
+[Install]
+WantedBy=default.target
diff --git a/config/services/systemd/vmm/libvirt/services/fw.service b/config/services/systemd/vmm/libvirt/services/fw.service.j2
similarity index 100%
rename from config/services/systemd/vmm/libvirt/services/fw.service
rename to config/services/systemd/vmm/libvirt/services/fw.service.j2
diff --git a/config/services/systemd/vmm/libvirt/services/infra.service b/config/services/systemd/vmm/libvirt/services/infra.service.j2
similarity index 82%
rename from config/services/systemd/vmm/libvirt/services/infra.service
rename to config/services/systemd/vmm/libvirt/services/infra.service.j2
index 714e2c9..55207bd 100644
--- a/config/services/systemd/vmm/libvirt/services/infra.service
+++ b/config/services/systemd/vmm/libvirt/services/infra.service.j2
@@ -1,7 +1,7 @@
[Unit]
Description=infra vm
-After=network-online.target libvirtd.service fw.service
-Wants=fw.service
+After=network-online.target libvirtd.service fw.service bk.service
+Wants=fw.service bk.service
[Service]
Type=oneshot
diff --git a/config/services/systemd/vmm/libvirt/xml/storages/backup-pool.xml b/config/services/systemd/vmm/libvirt/xml/storages/backup-pool.xml
new file mode 100644
index 0000000..40178e7
--- /dev/null
+++ b/config/services/systemd/vmm/libvirt/xml/storages/backup-pool.xml
@@ -0,0 +1,8 @@
+
+
+
+ backup-pool
+
+ /var/lib/libvirt/disk/backup
+
+
diff --git a/config/services/systemd/vmm/libvirt/xml/storages/data-pool.xml b/config/services/systemd/vmm/libvirt/xml/storages/data-pool.xml
index 8bfd284..ee58a2f 100644
--- a/config/services/systemd/vmm/libvirt/xml/storages/data-pool.xml
+++ b/config/services/systemd/vmm/libvirt/xml/storages/data-pool.xml
@@ -3,6 +3,6 @@
data-pool
- /var/lib/libvirt/data
+ /var/lib/libvirt/disk/data
diff --git a/config/services/systemd/vmm/libvirt/xml/vms/vms.xml.j2 b/config/services/systemd/vmm/libvirt/xml/vms/vms.xml.j2
index fef60f1..f2041a0 100644
--- a/config/services/systemd/vmm/libvirt/xml/vms/vms.xml.j2
+++ b/config/services/systemd/vmm/libvirt/xml/vms/vms.xml.j2
@@ -70,10 +70,14 @@
+{% endif %}
+{% if hostvars[target_vm]['vm']['data_storage'] is defined %}
+{% set pool = hostvars[target_vm]['vm']['data_storage']['pool'] %}
+{% set disk = hostvars['vmm']['hardware']['disk'][pool]['fs'] %}
-
-
+
+
{% endif %}
diff --git a/config/services/containers/infra/postgresql/init/.gitkeep b/data/sql/postgresql/.gitkeep
similarity index 100%
rename from config/services/containers/infra/postgresql/init/.gitkeep
rename to data/sql/postgresql/.gitkeep
diff --git a/docs/archives/services/app/actual-budget/actual-budget.container.j2 b/docs/archives/services/app/actual-budget/actual-budget.container.j2
index 23a4001..f23700c 100644
--- a/docs/archives/services/app/actual-budget/actual-budget.container.j2
+++ b/docs/archives/services/app/actual-budget/actual-budget.container.j2
@@ -14,7 +14,7 @@ PublishPort={{ services['actualbudget']['ports']['http'] }}:5006
Volume=%h/data/containers/actual-budget:/data:rw
Environment="TZ={{ timezone }}"
-Environment="ACTUAL_OPENID_DISCOVERY_URL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}/.well-known/openid-configuration"
+Environment="ACTUAL_OPENID_DISCOVERY_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration"
Environment="ACTUAL_OPENID_CLIENT_ID=actual-budget"
Environment="ACTUAL_OPENID_SERVER_HOSTNAME=https://{{ services['actualbudget']['domain']['public'] }}.{{ domain['public'] }}"
Environment="ACTUAL_OPENID_AUTH_METHOD=oauth2"
diff --git a/docs/archives/services/app/affine/affine.container.j2 b/docs/archives/services/app/affine/affine.container.j2
index c3dea8f..e0ab508 100644
--- a/docs/archives/services/app/affine/affine.container.j2
+++ b/docs/archives/services/app/affine/affine.container.j2
@@ -40,7 +40,7 @@ Environment="AFFINE_INDEXER_ENABLED=true"
Environment="AFFINE_INDEXER_SEARCH_ENDPOINT=http://host.containers.internal:{{ services['affine']['ports']['manticore'] }}"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/docs/archives/services/app/affine/set_affine.yaml b/docs/archives/services/app/affine/set_affine.yaml
index 440f72a..c1616c8 100644
--- a/docs/archives/services/app/affine/set_affine.yaml
+++ b/docs/archives/services/app/affine/set_affine.yaml
@@ -112,7 +112,7 @@
value: "{{ hostvars['console']['affine']['secret_key'] }}"
- name: "AFFINE_DATABASE_URL"
value: "postgresql://affine:{{ hostvars['console']['postgresql']['password']['affine'] | urlencode | replace('/', '%2F') }}\
- @{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/affine_db?sslmode=verify-full&\
+ @{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/affine_db?sslmode=verify-full&\
sslrootcert=/etc/ssl/affine/{{ root_cert_filename }}"
notify: "notification_restart_affine"
no_log: true
@@ -166,14 +166,17 @@
ansible.builtin.stat:
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
loop:
- - image: "docker.io/manticoresearch/manticore:{{ version['containers']['manticore'] }}"
+ - name: "manticore"
+ image: "docker.io/manticoresearch/manticore:{{ version['containers']['manticore'] }}"
file: "docker.io_manticoresearch_manticore_{{ version['containers']['manticore'] }}"
- - image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
+ - name: "redis"
+ image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
- - image: "ghcr.io/toeverything/affine:{{ version['containers']['affine'] }}"
+ - name: affine
+ image: "ghcr.io/toeverything/affine:{{ version['containers']['affine'] }}"
file: "ghcr.io_toeverything_affine_{{ version['containers']['affine'] }}"
loop_control:
- label: "{{ item.file }}"
+ label: "{{ item.name }}"
register: container_archive_images
- name: Save container archive images
diff --git a/docs/archives/services/app/ezbookkeeping/ezbookkeeping.container.j2 b/docs/archives/services/app/ezbookkeeping/ezbookkeeping.container.j2
index 15a8f66..4d6c759 100644
--- a/docs/archives/services/app/ezbookkeeping/ezbookkeeping.container.j2
+++ b/docs/archives/services/app/ezbookkeeping/ezbookkeeping.container.j2
@@ -25,7 +25,7 @@ Environment="EBK_LOG_MODE=console"
# Database
Environment="EBK_DATABASE_TYPE=postgres"
-Environment="EBK_DATABASE_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
+Environment="EBK_DATABASE_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
Environment="EBK_DATABASE_NAME=ezbookkeeping_db"
Environment="EBK_DATABASE_USER=ezbookkeeping"
Secret=EBK_DATABASE_PASSWD,type=env
@@ -38,7 +38,7 @@ Environment="EBK_AUTH_OAUTH2_PROVIDER=oidc"
Environment="EBK_AUTH_OAUTH2_CLIENT_ID=ezbookkeeping"
Secret=EBK_AUTH_OAUTH2_CLIENT_SECRET,type=env
Environment="EBK_AUTH_OAUTH2_USE_PKCE=true"
-Environment="EBK_AUTH_OIDC_PROVIDER_BASE_URL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="EBK_AUTH_OIDC_PROVIDER_BASE_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="EBK_AUTH_ENABLE_OIDC_DISPLAY_NAME=true"
Environment="EBK_AUTH_OIDC_CUSTOM_DISPLAY_NAME=Authelia"
@@ -52,7 +52,7 @@ Environment="EBK_MCP_ENABLE_MCP=false"
Environment="EBK_LLM_TRANSACTION_FROM_AI_IMAGE_RECOGNITION=false"
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/docs/archives/services/app/opencloud/etc/csp.yaml.j2 b/docs/archives/services/app/opencloud/etc/csp.yaml.j2
index 9ebc5eb..3419085 100644
--- a/docs/archives/services/app/opencloud/etc/csp.yaml.j2
+++ b/docs/archives/services/app/opencloud/etc/csp.yaml.j2
@@ -6,7 +6,7 @@ directives:
- 'blob:'
- 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps'
- 'https://update.opencloud.eu'
- - 'https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}'
+ - 'https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}'
# default-src:
# - '''none'''
font-src:
diff --git a/docs/archives/services/app/opencloud/etc/proxy.yaml.j2 b/docs/archives/services/app/opencloud/etc/proxy.yaml.j2
index 86cc7eb..cd59e28 100644
--- a/docs/archives/services/app/opencloud/etc/proxy.yaml.j2
+++ b/docs/archives/services/app/opencloud/etc/proxy.yaml.j2
@@ -3,11 +3,11 @@ role_assignment:
oidc_role_mapper:
role_claim: "preferred_username"
role_mapping:
-{% for admin_user in ['il'] %}
+{% for admin_user in ["il"] %}
- role_name: "admin"
claim_value: "{{ admin_user }}"
{% endfor %}
-{% for general_user in ['morsalin', 'eunkyoung'] %}
+{% for general_user in ["morsalin", "eunkyoung"] %}
- role_name: "user"
claim_value: "{{ general_user }}"
{% endfor %}
diff --git a/docs/archives/services/app/opencloud/opencloud.container.j2 b/docs/archives/services/app/opencloud/opencloud.container.j2
index ddc45f2..18572a9 100644
--- a/docs/archives/services/app/opencloud/opencloud.container.j2
+++ b/docs/archives/services/app/opencloud/opencloud.container.j2
@@ -27,7 +27,7 @@ Environment="OC_URL=https://{{ services['opencloud']['domain']['public'] }}.{{ d
## CSP file location: allow authelia public domain
Environment="PROXY_CSP_CONFIG_FILE_LOCATION=/etc/opencloud/csp.yaml"
# OIDC
-Environment="OC_OIDC_ISSUER=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="OC_OIDC_ISSUER=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="PROXY_OIDC_REWRITE_WELLKNOWN=true"
## OIDC CLIENT CONFIGURATION and SCOPES
Environment="WEB_OIDC_CLIENT_ID=opencloud"
@@ -41,8 +41,8 @@ Environment="GRAPH_USERNAME_MATCH=none"
# OIDC standard link environments
-#Environment="WEB_OIDC_AUTHORITY=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
-#Environment="WEBFINGER_OIDC_ISSUER=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+#Environment="WEB_OIDC_AUTHORITY=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
+#Environment="WEBFINGER_OIDC_ISSUER=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
#Environment="OC_OIDC_CLIENT_ID=opencloud"
#Environment="OC_OIDC_CLIENT_SCOPES=openid profile email groups"
#Environment="WEBFINGER_ANDROID_OIDC_CLIENT_ID=opencloud"
diff --git a/docs/archives/services/app/trilium/trilium.container.j2 b/docs/archives/services/app/trilium/trilium.container.j2
index 9033ae4..276f805 100644
--- a/docs/archives/services/app/trilium/trilium.container.j2
+++ b/docs/archives/services/app/trilium/trilium.container.j2
@@ -26,13 +26,13 @@ Environment="TRILIUM_NO_UPLOAD_LIMIT=true"
## Short Alias doesn't work now.
#Environment="TRILIUM_OAUTH_BASE_URL=https://{{ services['trilium']['domain']['public'] }}.{{ domain['public'] }}"
#Environment="TRILIUM_OAUTH_CLIENT_ID=trilium"
-#Environment="TRILIUM_OAUTH_ISSUER_BASE_URL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+#Environment="TRILIUM_OAUTH_ISSUER_BASE_URL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
#Environment="TRILIUM_OAUTH_ISSUER_NAME=Authelia"
#Environment="TRILIUM_OAUTH_ISSUER_ICON=https://www.authelia.com/images/branding/logo-cropped.png"
#Secret="TRILIUM_OAUTH_CLIENT_SECRET",type=env
Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL=https://{{ services['trilium']['domain']['public'] }}.{{ domain['public'] }}"
Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID=trilium"
-Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME=Authelia"
Environment="TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON=https://www.authelia.com/images/branding/logo-cropped.png"
Secret="TRILIUM_OAUTH_CLIENT_SECRET",type=env,target=TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET
diff --git a/docs/archives/services/app/vikunja/vikunja.container.j2 b/docs/archives/services/app/vikunja/vikunja.container.j2
index f6c1c9f..93613c4 100644
--- a/docs/archives/services/app/vikunja/vikunja.container.j2
+++ b/docs/archives/services/app/vikunja/vikunja.container.j2
@@ -28,7 +28,7 @@ Secret=VIKUNJA_SERVICE_JWTSECRET,type=env
# Database
Environment="VIKUNJA_DATABASE_TYPE=postgres"
-Environment="VIKUNJA_DATABASE_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="VIKUNJA_DATABASE_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="VIKUNJA_DATABASE_USER=vikunja"
Environment="VIKUNJA_DATABASE_DATABASE=vikunja_db"
Environment="VIKUNJA_DATABASE_SSLMODE=verify-full"
@@ -39,7 +39,7 @@ Secret=VIKUNJA_DATABASE_PASSWORD,type=env
# OIDC
Environment="VIKUNJA_AUTH_OPENID_ENABLED=true"
Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_NAME=Authelia"
-Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_AUTHURL=https://{{ services['authelia']['domain'] }}.{{ domain['public'] }}"
+Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_AUTHURL=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_CLIENTID=vikunja"
# Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_SCOPE=" default value = openid email profile
# Vikunja doesn't support OIDC and local dual login.
@@ -48,7 +48,7 @@ Environment="VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_CLIENTID=vikunja"
Secret=VIKUNJA_AUTH_OPENID_PROVIDERS_authelia_CLIENTSECRET,type=env
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120
diff --git a/docs/archives/services/app/wikijs/wikijs.container.j2 b/docs/archives/services/app/wikijs/wikijs.container.j2
index a8738c6..103e7c1 100644
--- a/docs/archives/services/app/wikijs/wikijs.container.j2
+++ b/docs/archives/services/app/wikijs/wikijs.container.j2
@@ -23,7 +23,7 @@ Environment="TZ={{ timezone }}"
# Database
Environment="DB_TYPE=postgres"
-Environment="DB_HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}"
+Environment="DB_HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
Environment="DB_PORT={{ services['postgresql']['ports']['tcp'] }}"
Environment="DB_USER=wikijs"
Environment="DB_NAME=wikijs_db"
@@ -32,7 +32,7 @@ Environment="NODE_EXTRA_CA_CERTS=/etc/ssl/wiki/{{ root_cert_filename }}"
Secret=WIKIJS_DB_PASS,type=env,target=DB_PASS
[Service]
-ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
+ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
Restart=always
RestartSec=10s
TimeoutStopSec=120