Refactor systemctl services and categories due to alarm bugs

This commit restructures systemctl service definitions and category mappings.

Motivation: Alarm-related bugs revealed inconsistencies in service and role handling.

Preparation step: lays the groundwork for fixing the alarm issues by aligning categories, roles, and service templates.
This commit is contained in:
2025-08-18 13:35:43 +02:00
parent 29f50da226
commit 3a839cfe37
289 changed files with 975 additions and 948 deletions

View File

@@ -0,0 +1,18 @@
# Docker Compose Certificate Sync Service
## Description
Keeps Docker Compose services updated with fresh Lets Encrypt certificates via a systemd oneshot service and timer.
## Overview
Installs a small script and a systemd unit that copy certificates into your Compose project and trigger an Nginx hot-reload (fallback: restart) to minimize downtime.
## Features
- Automatic certificate sync into the Compose project
- Mailu-friendly filenames (`key.pem`, `cert.pem`)
- Nginx hot-reload if available, otherwise restart
- Runs on a schedule you define
## Further Resources
- [Wildcard Certificate Setup (SETUP.md)](./SETUP.md)
- [Role Documentation](https://s.infinito.nexus/code/tree/main/roles/sys-ctl-mtn-cert-deploy)
- [Issue Tracker](https://s.infinito.nexus/issues)

View File

@@ -0,0 +1,36 @@
## **🔐 Wildcard Certificate Setup with Let's Encrypt**
If you enabled `enable_wildcard_certificate`, follow these steps to manually request a **wildcard certificate**.
### **1⃣ Run the Certbot Command 🖥️**
```sh
certbot certonly --manual --preferred-challenges=dns --agree-tos \
--email administrator@PRIMARY_DOMAIN -d PRIMARY_DOMAIN -d "*.PRIMARY_DOMAIN"
```
### **2⃣ Add DNS TXT Record for Validation 📜**
Certbot will prompt you to add a DNS TXT record:
```
Please create a TXT record under the name:
_acme-challenge.PRIMARY_DOMAIN.
with the following value:
9oVizYIYVGlZ3VtWQIKRS5UghyXiqGoUNlCtIE7LiA
```
**Go to your DNS provider** and create a new **TXT record**:
- **Host:** `_acme-challenge.PRIMARY_DOMAIN`
- **Value:** `"9oVizYIYVGlZ3VtWQIKRS5UghyXiqGoUNlCtIE7LiA"`
- **TTL:** Set to **300 seconds (or lowest possible)**
**Verify the DNS record** before continuing:
```sh
dig TXT _acme-challenge.PRIMARY_DOMAIN @8.8.8.8
```
### **3⃣ Complete the Certificate Request ✅**
Once the DNS changes have propagated, **press Enter** in the Certbot terminal.
If successful, Certbot will save the certificates under:
```
/etc/letsencrypt/live/PRIMARY_DOMAIN/
```
- **fullchain.pem** → The certificate
- **privkey.pem** → The private key

View File

@@ -0,0 +1,54 @@
#!/bin/sh
# Check if the necessary parameters are provided
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <ssl_cert_folder> <docker_compose_instance_directory> <letsencrypt_live_path>"
exit 1
fi
# Assign parameters
ssl_cert_folder="$1"
docker_compose_instance_directory="$2"
letsencrypt_live_path="$3"
docker_compose_cert_directory="$docker_compose_instance_directory/volumes/certs"
# Copy certificates
cp -RvL "$letsencrypt_live_path/$ssl_cert_folder/"* "$docker_compose_cert_directory" || exit 1
# This code is optimized for mailu
cp -v "$letsencrypt_live_path/$ssl_cert_folder/privkey.pem" "$docker_compose_cert_directory/key.pem" || exit 1
cp -v "$letsencrypt_live_path/$ssl_cert_folder/fullchain.pem" "$docker_compose_cert_directory/cert.pem" || exit 1
# Set correct reading rights
chmod a+r -v "$docker_compose_cert_directory/"*
# Flag to track if any Nginx reload was successful
nginx_reload_successful=false
# Reload Nginx in all containers within the Docker Compose setup
cd "$docker_compose_instance_directory" || exit 1
# Iterate over all services
for service in $(docker compose ps --services); do
echo "Checking service: $service"
# Check if Nginx exists in the container
if docker compose exec -T "$service" which nginx > /dev/null 2>&1; then
echo "Reloading Nginx for service: $service"
if docker compose exec -T "$service" nginx -s reload; then
nginx_reload_successful=true
echo "Successfully reloaded Nginx for service: $service"
else
echo "Failed to reload Nginx for service: $service" >&2
fi
else
echo "Nginx not found in service: $service, skipping."
fi
done
# Restart all containers if no Nginx reload was successful
if [ "$nginx_reload_successful" = false ]; then
echo "No Nginx reload was successful. Restarting all Docker containers."
docker compose restart || exit 1
else
echo "At least one Nginx reload was successful. No restart needed."
fi

View File

@@ -0,0 +1,7 @@
---
- name: "restart tls deploy to docker service"
systemd:
name: "{{ CERT_SYNC_DOCKER_SERVICE_NAME_FULL }}"
state: restarted
enabled: yes
daemon_reload: yes

View File

@@ -0,0 +1,21 @@
galaxy_info:
author: "Kevin Veen-Birchenbach"
description: "Deploys Lets Encrypt certificates into Docker Compose Nginx setups via systemd service and timer."
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
Kevin Veen-Birchenbach
Consulting & Coaching Solutions
https://www.veen.world
galaxy_tags:
- nginx
- letsencrypt
- docker
- systemd
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://s.infinito.nexus/code/tree/main/roles/sys-ctl-mtn-cert-deploy"
min_ansible_version: "2.9"
platforms:
- name: Any
versions: [all]

View File

@@ -0,0 +1,13 @@
- name: Include dependency 'sys-ctl-alm-compose'
include_role:
name: sys-ctl-alm-compose
when: run_once_sys_ctl_alm_compose is not defined
- name: "Install '{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}'"
ansible.builtin.copy:
src: "{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}"
dest: "{{ CERT_SYNC_DOCKER_SCRIPT_PATH }}"
mode: "0755"
owner: root
group: root
notify: restart tls deploy to docker service

View File

@@ -0,0 +1,27 @@
- block:
- include_tasks: 01_core.yml
- set_fact:
run_once_sys_ctl_mtn_cert_deploy: true
when: run_once_sys_ctl_mtn_cert_deploy is not defined
- name: "create {{ cert_mount_directory }}"
file:
path: "{{ cert_mount_directory }}"
state: directory
mode: "0755"
notify: restart tls deploy to docker service
- name: Copy {{ CERT_SYNC_DOCKER_SERVICE_NAME_FULL }}
template:
src: "{{ CERT_SYNC_DOCKER_BASE }}.service.j2"
dest: "/etc/systemd/system/{{ CERT_SYNC_DOCKER_SERVICE_NAME_FULL }}"
notify: restart tls deploy to docker service
- name: "include role for sys-timer for {{ CERT_SYNC_DOCKER_SERVICE_NAME_FULL }}"
include_role:
name: sys-timer
vars:
on_calendar: "{{ SYS_SCHEDULE_MAINTANANCE_LETSENCRYPT_DEPLOY }}"
service_name: "{{ CERT_SYNC_DOCKER_SERVICE_NAME_BASE }}"
persistent: "true"

View File

@@ -0,0 +1,7 @@
[Unit]
Description=Let's Encrypt deploy to {{ docker_compose.directories.instance }}
OnFailure=sys-ctl-alm-compose.{{ SOFTWARE_NAME }}@%n.service
[Service]
Type=oneshot
ExecStart={{ PATH_ADMINISTRATOR_SCRIPTS }}/{{ CERT_SYNC_DOCKER_SCRIPT_FILE }} {{ ssl_cert_folder }} {{ docker_compose.directories.instance }} {{ LETSENCRYPT_LIVE_PATH }}

View File

@@ -0,0 +1,6 @@
CERT_SYNC_DOCKER_BASE: "sys-ctl-mtn-cert-deploy"
CERT_SYNC_DOCKER_SCRIPT_FILE: "{{ CERT_SYNC_DOCKER_BASE }}.sh"
CERT_SYNC_DOCKER_SCRIPT_PATH: "{{ PATH_ADMINISTRATOR_SCRIPTS }}{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}"
CERT_SYNC_DOCKER_SERVICE_NAME_BASE: "{{ application_id | get_entity_name }}.{{ CERT_SYNC_DOCKER_BASE }}"
CERT_SYNC_DOCKER_SERVICE_NAME_FULL: "{{ CERT_SYNC_DOCKER_SERVICE_NAME_BASE }}{{ SYS_SERVICE_SUFFIX }}"