Compare commits

...

5 Commits

Author SHA1 Message Date
av 5f619eaccc backups: use apprise for notifications
Linting / YAML Lint (push) Successful in 9s
Linting / Ansible Lint (push) Failing after 29s
2026-04-04 11:30:53 +03:00
av 362d6d8710 apprise: changed to simple stateful setup 2026-04-04 11:25:27 +03:00
av 5e6df110c8 apprise: only one worker for small memory consumption 2026-04-04 10:54:27 +03:00
av a0543e13f4 Add apprise application for notifications 2026-04-04 10:50:10 +03:00
av 41fe116dd7 Remove old public key 2026-04-04 10:49:53 +03:00
9 changed files with 108 additions and 50 deletions
+21
View File
@@ -0,0 +1,21 @@
services:
apprise_app:
image: caronc/apprise:v1.3.3
container_name: apprise_app
restart: unless-stopped
ports:
- "127.0.0.1:{{ apprise_external_port }}:8000"
networks:
- "web_proxy_network"
volumes:
- "{{ config_dir }}:/config"
environment:
PUID: "{{ owner_create_result.uid }}"
PGID: "{{ owner_create_result.group }}"
APPRISE_STATEFUL_MODE: simple
APPRISE_WORKER_COUNT: 1
networks:
web_proxy_network:
external: true
+1
View File
@@ -0,0 +1 @@
tgram://{{ notifications_tg_bot_token }}/{{ notifications_tg_chat_id }}
-25
View File
@@ -1,25 +0,0 @@
$ANSIBLE_VAULT;1.1;AES256
39343035656562656632323766356561386665373036383564616331333333613765353737663632
3531663835303562393063343231623464663232333532380a663838663938316566616532623065
66336463643862626538366462346231386333366464323131363836326436373563623164336632
6234353437383432380a396136653136616335343936343335633236373363353766666539396334
36613836663831333838633231363731323234323761306630646632616238363662376462333039
32373938343562313064663334383766653161613032623936646361316561666532356465623133
32303663313834663834366363383265653939316336356239313364623366386631626536643439
31333362353961353434333636343336323239363461663937313931616262316330376165393263
63366665396431323034383939633365316134356564656136393032393864393636616234316231
37616336396435626264643232343766616364306264376338313238356261653863336535363237
34653638316161636431653465343536323331656230633332333139386132653433626662343837
35396437633233363637376561303338386432643039626336376366373334613463663465613637
36643734626163623738336435383032353837366532316566613864306430653336616637383262
65646131643533323563393133373964633863636666633338616236386531323064396137376232
37653333666566386563383235356232663338643161313635643661326339333661393135643030
62356662623365376662646166316262353964383936373463393339623961376232653664306439
36336231393434356661316336653033346430386366663138323832613532303265343136373836
64666561616535623732326464643831363866326265343165356330646561653066393764336134
30326436663066633163393163306265383834306634663639336437303965373063323335333537
38643234623061376565636536323563623739313165343464316466363364613963636437363830
33306632313839373132636130326331363538323763326333316165363633336561373030373963
38313135343464303331343866646634393162393361333962356133376163393865373239323763
31303336613937303031343532333036653133363439643864663661373639646566643831313662
35613430333861376565
+15 -21
View File
@@ -158,38 +158,32 @@ class Notifier(ABC):
raise NotImplementedError() raise NotImplementedError()
class TelegramNotifier(Notifier): class AppriseNotifier(Notifier):
TYPE_NAME = "telegram" TYPE_NAME = "apprise"
def __init__(self, name: str, params: Dict[str, Any]): def __init__(self, name: str, params: Dict[str, Any]):
self.name = name self.name = name
self.telegram_bot_token = str(params.get("telegram_bot_token", "")) self.api_url = str(params.get("api_url", "")).rstrip("/")
self.telegram_chat_id = str(params.get("telegram_chat_id", "")) self.tag = str(params.get("tag", ""))
if not all( if not self.api_url or not self.tag:
[
self.telegram_bot_token,
self.telegram_chat_id,
]
):
raise ValueError( raise ValueError(
f"Missing notification configuration values for backend {name}" f"Missing notification configuration values for backend {name}"
) )
def send(self, html_message: str) -> None: def send(self, html_message: str) -> None:
url = f"https://api.telegram.org/bot{self.telegram_bot_token}/sendMessage" url = f"{self.api_url}/notify/{self.tag}/"
data = { payload = {
"chat_id": self.telegram_chat_id, "body": html_message,
"parse_mode": "HTML", "format": "html",
"text": html_message,
} }
response = requests.post(url, data=data, timeout=30) response = requests.post(url, json=payload, timeout=30)
if response.status_code == 200: if response.ok:
logger.info("Telegram notification sent successfully") logger.info("Apprise notification sent successfully")
else: else:
logger.error( logger.error(
f"Failed to send Telegram notification: {response.status_code} - {response.text}" f"Failed to send Apprise notification: {response.status_code} - {response.text}"
) )
@@ -459,8 +453,8 @@ def initialize(config_path: Path) -> BackupManager:
if not isinstance(params, dict): if not isinstance(params, dict):
raise ValueError(f"Notificator config for {name} must be a table") raise ValueError(f"Notificator config for {name} must be a table")
notifier_type = params.get("type", "") notifier_type = params.get("type", "")
if notifier_type == TelegramNotifier.TYPE_NAME: if notifier_type == AppriseNotifier.TYPE_NAME:
notifiers.append(TelegramNotifier(name, params)) notifiers.append(AppriseNotifier(name, params))
if not notifiers: if not notifiers:
raise ValueError("At least one notification backend must be configured") raise ValueError("At least one notification backend must be configured")
+4 -4
View File
@@ -12,7 +12,7 @@ aws_access_key_id = "{{ restic_s3_access_key }}"
aws_secret_access_key = "{{ restic_s3_access_secret }}" aws_secret_access_key = "{{ restic_s3_access_secret }}"
aws_default_region = "{{ restic_s3_region }}" aws_default_region = "{{ restic_s3_region }}"
[notifier.server_notifications_channel] [notifier.apprise]
type = "telegram" type = "apprise"
telegram_bot_token = "{{ notifications_tg_bot_token }}" api_url = "{{ apprise_external_url }}"
telegram_chat_id = "{{ notifications_tg_chat_id }}" tag = "server"
+3
View File
@@ -37,6 +37,9 @@
- name: 'Configure remembos' - name: 'Configure remembos'
ansible.builtin.import_playbook: playbook-remembos.yml ansible.builtin.import_playbook: playbook-remembos.yml
- name: 'Configure apprise'
ansible.builtin.import_playbook: playbook-apprise.yml
# #
- name: 'Configure homepage' - name: 'Configure homepage'
+60
View File
@@ -0,0 +1,60 @@
---
- name: "Configure apprise application"
hosts: all
vars_files:
- vars/secrets.yml
- vars/vars.yml
vars:
app_name: "apprise"
app_user: "{{ app_name }}"
app_owner_uid: 1104
app_owner_gid: 1104
base_dir: "{{ (application_dir, app_name) | path_join }}"
config_dir: "{{ (base_dir, 'config') | path_join }}"
tasks:
- name: "Create user and environment"
ansible.builtin.import_role:
name: owner
vars:
owner_name: "{{ app_user }}"
owner_uid: "{{ app_owner_uid }}"
owner_gid: "{{ app_owner_gid }}"
owner_extra_groups: ["docker"]
- name: "Create application internal directories"
ansible.builtin.file:
path: "{{ item }}"
state: "directory"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0750"
loop:
- "{{ base_dir }}"
- "{{ config_dir }}"
- name: "Copy apprise config"
ansible.builtin.template:
src: "./files/{{ app_name }}/server.cfg.j2"
dest: "{{ config_dir }}/server.cfg"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0640"
- name: "Copy docker compose file"
ansible.builtin.template:
src: "./files/{{ app_name }}/docker-compose.template.yml"
dest: "{{ base_dir }}/docker-compose.yml"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: "0640"
- name: "Run application with docker compose"
community.docker.docker_compose_v2:
project_src: "{{ base_dir }}"
state: "present"
remove_orphans: true
tags:
- run-app
+1
View File
@@ -4,6 +4,7 @@
vars_files: vars_files:
- vars/secrets.yml - vars/secrets.yml
- vars/vars.yml
vars: vars:
backup_config_dir: "/etc/backup" backup_config_dir: "/etc/backup"
+3
View File
@@ -0,0 +1,3 @@
---
apprise_external_port: 8000
apprise_external_url: "http://127.0.0.1:{{ apprise_external_port }}"