Compare commits
46 Commits
28faff3c99
...
master
Author | SHA1 | Date | |
---|---|---|---|
1d5ce38922
|
|||
0b9e66f067
|
|||
379a113b86
|
|||
8538c00175
|
|||
645276018b
|
|||
ce5d682842
|
|||
de5b0f66bd
|
|||
64602b1db3
|
|||
caecb9b57e
|
|||
e8be04d5e1
|
|||
a7f90da43f
|
|||
0f80206c62
|
|||
1daff82cc5
|
|||
9b4293c624
|
|||
0d93e8094c
|
|||
b92ab556e5
|
|||
8086799c7b
|
|||
6ec5df4b66
|
|||
fb91e45806
|
|||
44f82434e7
|
|||
31ca27750e
|
|||
4be8d297ba
|
|||
bcd8e62691
|
|||
160f4219c5
|
|||
c518125bbd
|
|||
e16e23d18c
|
|||
ede37e7fa3
|
|||
b4cddb337a
|
|||
35f1abd718
|
|||
21b52a1887
|
|||
af39ca9de8
|
|||
e10b37a9f6
|
|||
85627f8931
|
|||
38e2294a65
|
|||
dfcb781a90
|
|||
2c8bd2bb8d
|
|||
592c3a062b
|
|||
04d789f0a4
|
|||
16719977c8
|
|||
6cd8d3b14b
|
|||
791caab704
|
|||
df60296f9d
|
|||
232d06a123
|
|||
a3886c8675
|
|||
db55fcd180
|
|||
53dd462cac
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,5 +7,3 @@
|
||||
/ansible-vault-password-file
|
||||
/temp
|
||||
*.retry
|
||||
|
||||
test_smtp.py
|
||||
|
@@ -46,8 +46,9 @@ tasks:
|
||||
- >
|
||||
ansible localhost
|
||||
--module-name template
|
||||
--args "src=files/authelia/configuration.yml.j2 dest={{.DEST_FILE}}"
|
||||
--args "src=files/authelia/configuration.template.yml dest={{.DEST_FILE}}"
|
||||
--extra-vars "@vars/secrets.yml"
|
||||
--extra-vars "@files/authelia/secrets.yml"
|
||||
- defer: rm -f {{.DEST_FILE}}
|
||||
- >
|
||||
{{.AUTHELIA_DOCKER}}
|
||||
|
1683
files/authelia/configuration.template.yml
Normal file
1683
files/authelia/configuration.template.yml
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,14 +2,14 @@ services:
|
||||
|
||||
authelia_app:
|
||||
container_name: 'authelia_app'
|
||||
image: 'docker.io/authelia/authelia:4.39.4'
|
||||
image: 'docker.io/authelia/authelia:4.39.8'
|
||||
user: '{{ user_create_result.uid }}:{{ user_create_result.group }}'
|
||||
restart: 'unless-stopped'
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
volumes:
|
||||
- "{{ config_dir }}:/config"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
136
files/authelia/secrets.yml
Normal file
136
files/authelia/secrets.yml
Normal file
@@ -0,0 +1,136 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
37373465363866623436393966626530656465653837363463323664383666663164363233623738
|
||||
3233383234343332623065386134643161346132653431350a303935373631656366633339663333
|
||||
32353263346437626633346263323533313238613462613334353334643236343438306630333037
|
||||
6435313930313262310a386662336637623461303636633337303531353261343861313966383764
|
||||
32353439333364353434653164666434326232383562363063313433373137383138396266383134
|
||||
36613538653531346232353236313262313138656234626638623034363436303337313961333536
|
||||
66366666383363333439333439623931626662383764393463663733333034636633353538656137
|
||||
62386263613533343963396166666532313862366433636536613266353064633932323765336362
|
||||
34643634643962333563346633306665313765393663306364363362333536646635343832333634
|
||||
30383361653063396333616433323235663338346439303465323135626639646166303164643339
|
||||
31616534633034393339373934346531633433323433646436333863306566356462613531663136
|
||||
61343561616434306163616130626338663737633866646537323263316636626137366361363963
|
||||
31303361366365616335363230343239663038623830303232376236393639663232333764643064
|
||||
34666439316430356664313531333363626562633636326463313765343263393636333465386339
|
||||
33623037343134633535303863626564373630656463336330396336303462373735346331616663
|
||||
63666161356565643539343431386231396162323030383836366161303634626266663934356362
|
||||
61623833613734333661613338373663663230363331373236323166636534613962613763343663
|
||||
31666534303965333466653335646263343764346465373461326166666266303138363933653566
|
||||
37636530306632346636626336616536346236663664383864623863653835366133633635613861
|
||||
63303634333962343039646564353534313063383434386462366333386331303433366665623734
|
||||
61353039313762383664626330663230656237373061616132376564323763393632356665306633
|
||||
34643865333165616664376162306634366532386437383461396163376366363832363834356164
|
||||
64376637373135383539353636346461353761366561303530326363366238393932333039313264
|
||||
34316539626365306461323336396631633532306637306331373863613531656565366236656338
|
||||
30306237626561613561353265643137353965313033313939643161613163643566663632663964
|
||||
61623134656238363134626530363933623930346532336366393163363562386265626233393139
|
||||
63633333313531666335376538613765663933626533636137306564616333373766613665613332
|
||||
65643331626361626136623432346233633364343963653932306632646436626433653337326665
|
||||
39343033353030616630663865613630613032333831626538323461383264636633623439393765
|
||||
65343866323237386336613764386439313830646239613135636161333138646664666339626137
|
||||
36616433393339346139323333363030613731313236636464393864616135346234643664343533
|
||||
31396661306664343031393865306533373762663962623730313261353231363661306134623934
|
||||
64613931356164386431663536363361386566353361333861666365636564643536306638376238
|
||||
37633865303063643962346664346366346362313463386432376637663934363165343537323532
|
||||
63363431623663656163316662343435636165306134373839613731326139636337343862326338
|
||||
61326433343631343065303735663434316330303139303834316137663330363762666664393062
|
||||
30653236636538396234313735613365386635323062666236656164633136313362643834336339
|
||||
32623834343334613839313138313462376237666238636663343333643533643537376261666433
|
||||
64323933323134393461623034623563316135333566326135326434613237363830623063626535
|
||||
66323533356366346130626530633337393263663664353430646330353339313534396434653137
|
||||
36663737396261653162663337663338373433653233616363626130333833323533303363643730
|
||||
66613135633761346433626164643130353963313762643361306537653639373934333565373439
|
||||
31636133383866373032373562653933316163353936386339326266363233663633623437346665
|
||||
66393630346434356563393039626537336537313930393437663562303031626338616266363361
|
||||
65653033363539633364326531653563383634303830386362303665306438663035373831646562
|
||||
30356564623733623939663332393463663730643533666134636361316263633166626566333831
|
||||
66376461383139626230343136373437393464646331633139633435303236623132343035373037
|
||||
39363131623330376262326235646633303232623139626239326361313236316665316464616265
|
||||
35303166333561626130323864363430663332306338353731383139386131346132653632633132
|
||||
37643865393462623831623435633838323664666264623232326561653866626437373864666232
|
||||
64393466326162323236353539326364336238643031313434346566316434383733663663356334
|
||||
62343337386532393236353432653239643735323531306337373739343839306264356666636635
|
||||
35626665646634653766323939633434303238633564613962643364356631623539623032363039
|
||||
31336535333763323236633531616661313834636231363362376661313931623131343364356364
|
||||
35653539393265323636303930633639316139643631386632646139643266303531653865623664
|
||||
31303930613561323330356337396138633033616265356137353336613638656161633063663964
|
||||
33373965383532656634333863643131333461376135646635323035316230393439386130663036
|
||||
37373331356364343433316435666130373031303038643063313131653835333365366138656238
|
||||
38643437376234316332306434633039346564643863656461353364346335353839303734366565
|
||||
32613364356532623231623632363637373664393764636262346264383134366439373238623032
|
||||
62326163306532356262393565373937316530623963313266373736356632313831313465666663
|
||||
61303962333836373832383236663532376130316465393039326366636133323233316134646430
|
||||
63313437663662353962633561643535396332303533343962643038393165373239336431336664
|
||||
65356663393565383263613530663762643731356463653538316439303863643363303261363838
|
||||
33353739306337326665393164366232393665363465343537373866396136346164333663393738
|
||||
31316335366238316537386236393461656266323566636364343139393665616138663432333564
|
||||
37653837646666376530373530636164343633653162343131373034633432333138613138346339
|
||||
32303332626338653561323835343266353633613434346465616162326162393733643837663230
|
||||
62333630333464633362656661336139393639623863343036636534323637336561333734373262
|
||||
36373365306531383830383361303566626239343062316166303636323539373966626336613638
|
||||
31623863643632653036323834346362663834666431643637666137376139386666643834323465
|
||||
63626264643337376663633335666631653637626364653866353131393336303937633430366430
|
||||
38383066313831346461643862333838386566613661623130313038386137323331373434363033
|
||||
34613537303134343532643430383532353934623066383530653435626566333239333162316435
|
||||
30386361346336666665656336646633353663376337326131663435636533646162616332306530
|
||||
30373263376437646639623039343234393537303931346461643966383732336366363331643135
|
||||
65383462353034643464366334636136373035313437366639336338366133663765313735353366
|
||||
62386239326134343761313464383239316465633932363862303536353365376338643863643834
|
||||
32633233336262626336383061316137646431353766303930336562386136383530613538383837
|
||||
66336235643437636138646663393565383466636232366133343232306563363635316561346565
|
||||
36633637303163303963396132653731663134666238363939666663303033316564356364633162
|
||||
31376233306138666131333634336639643163666562653934336162323964613863646564616361
|
||||
33666264303163326664633839303562333664383130356134383836313635376239353137313363
|
||||
66613132663137383737373530326131663861303935663635373464306334363962333566663261
|
||||
64616361366137626163626139333630653331383763353632396130306231376662666363353962
|
||||
66343064313932386631303663373432646135353438313632316634336235316139313237666362
|
||||
31383638393362663038363765303634363366326265643332393165643635643339343137373930
|
||||
37633031626365353033333938623466663963376366353561303166373164386132376365643630
|
||||
32333134316464643564373537643734353534366563666435663663616331383039393862613838
|
||||
63633962316533386337366263636265646334636235323430383832363964343939633264343338
|
||||
64366539383831373636343330356537323662666533323935646634363466663239663362326531
|
||||
66363863383762303539373636336330353834303239376330623964393439356130646166663332
|
||||
65326162336366363466646230656362653531386162356235326235333866373966636434326537
|
||||
38653139393563373337346636333337373039343439343139313366316264613763663664633037
|
||||
32313237653239643635393363316465346561613331623033323137653865396239633639323534
|
||||
61326262643365363737393031383461626530636266393836663937666135363662353665376362
|
||||
63643039373931316439303731663762393237623065643236303737643966393836646335626132
|
||||
36376665656662373437653933356330636638626162666564393636633630663562303839326662
|
||||
35626261616534386361373539633636356136616137323737393466633364653730356138343638
|
||||
36663537663361393566616365383161366236646630653737643765666638346531376136643163
|
||||
37643530373330353238323431343761653633306464643835343333623837313135303031666535
|
||||
30326538636432303363666131376334393361333232313834623230306630373834633265333237
|
||||
34323731333835363863643031346166636464653731636636313161643265613861336638313338
|
||||
32383438353763343933383537636464666466386131363566306562333136356538326239656232
|
||||
33343631613134616265393232613063643561633335323665383133313536313364343066366665
|
||||
63636439376436393162306638303062616435333039343566613961626434303766616535623364
|
||||
32643866393430303137366264306262643365663034613965666332313430366630653736303537
|
||||
39663832326132393066373166613161613130363033363633366563353461663435393565326362
|
||||
37616462393933303937643664343663373234663066633834626164303866323835363333366266
|
||||
36356133336165613032646436306162663534306239313330353935336332643637653534626233
|
||||
38303965646361316434343131653461353234396163613736333235656639326231353734636266
|
||||
61613566336437666265366637336363326266383666383165343661333766303830633633393664
|
||||
34613061396564616337643032666561633038663062336233666263306132663139396565323035
|
||||
33353438633338363263313630393239376162366461383265386633613939663461616233396334
|
||||
35616433663862616530636362396333343464393339396538333861303763393066626439396361
|
||||
32303732393062383662633937653531653933333463366638613035333832636235346233653866
|
||||
35656664636636326163353439626538343463613465613634656530366566323165623162303565
|
||||
31303139343138616132383731323061346431336133643735356532373838663761313139663361
|
||||
33656365636261303532333131346633373732643232303139353431663132346532616334613034
|
||||
30363137613133396335343162643936623330393834356365663932626262313366616534663033
|
||||
37376132656233633361623733356334636266383361656437613331306636656333623139303661
|
||||
38353639346266333833663533366661633136313262396465633738373438623262306637643336
|
||||
34656136343139663461336264346666333537633065343766316630626566363761396537643334
|
||||
30323766633664666639363965363138396334343365346333663035323839613030626533303830
|
||||
31333734386565383831373939306265636432386332313531623638333663643162623339613366
|
||||
34363935636266313736366639373833636230633661323935646331376336623937353039343561
|
||||
39623865663462663431643738653663663733663765383663623437383163613232336332653531
|
||||
64663133353934313436336633666435343162316135303663636130353936363936363032313263
|
||||
65376436316237663434323736663263376164346139616465663737323963316361373438633339
|
||||
31323261343635633338613636643232616537653331326331353161396331633461643861323466
|
||||
64633033623537386263376263346666633939336133616234363964363339616331636464326163
|
||||
63633862373030323132613439343431333938343864383637613435323732356234613965666364
|
||||
37343765353735633737393664306533633262353562323565306537646534663833343430643662
|
||||
39326134353335653938396532363136376332306162613836663464636233383436333735663731
|
||||
313461396466396230323561646662653063
|
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
echo "Backup: perform gitea backup"
|
||||
su --login gitea --command '/home/gitea/backup.sh'
|
||||
|
||||
echo "Backup: perform outline backup"
|
||||
su --login outline --command '/home/outline/backup.sh'
|
||||
|
||||
echo "Backup: perform gramps backup"
|
||||
su --login gramps --command '/home/gramps/backup.sh'
|
||||
|
||||
echo "Backup: perform miniflux backup"
|
||||
su --login miniflux --command '/home/miniflux/backup.sh'
|
||||
|
||||
echo "Backup: perform wakapi backup"
|
||||
su --login wakapi --command '/home/wakapi/backup.sh'
|
||||
|
||||
echo "Backup: send backups to remote storage with retic"
|
||||
|
||||
restic-shell.sh backup --verbose /home/gitea/backups /home/outline/backups /home/gramps/backups /home/miniflux/backups /home/wakapi/backups \
|
||||
&& restic-shell.sh check \
|
||||
&& restic-shell.sh forget --compact --prune --keep-daily 90 --keep-monthly 36 \
|
||||
&& restic-shell.sh check
|
||||
|
||||
|
||||
echo "Backup: send notification"
|
||||
|
||||
curl -s -X POST 'https://api.telegram.org/bot{{ notifications_tg_bot_token }}/sendMessage' \
|
||||
-d 'chat_id={{ notifications_tg_chat_id }}' \
|
||||
-d 'parse_mode=HTML' \
|
||||
-d 'text=<b>{{ notifications_name }}</b>: бекап успешно завершен!'
|
||||
|
||||
|
||||
echo -e "\nBackup: done"
|
326
files/backups/backup-all.template.py
Normal file
326
files/backups/backup-all.template.py
Normal file
@@ -0,0 +1,326 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Backup script for all applications
|
||||
Automatically discovers and runs backup scripts for all users,
|
||||
then creates restic backups and sends notifications.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import logging
|
||||
import pwd
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
import requests
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.StreamHandler(sys.stdout),
|
||||
logging.FileHandler("/var/log/backup-all.log"),
|
||||
],
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Configuration from Ansible template variables
|
||||
RESTIC_REPOSITORY = "{{ restic_repository }}"
|
||||
RESTIC_PASSWORD = "{{ restic_password }}"
|
||||
AWS_ACCESS_KEY_ID = "{{ restic_s3_access_key }}"
|
||||
AWS_SECRET_ACCESS_KEY = "{{ restic_s3_access_secret }}"
|
||||
AWS_DEFAULT_REGION = "{{ restic_s3_region }}"
|
||||
TELEGRAM_BOT_TOKEN = "{{ notifications_tg_bot_token }}"
|
||||
TELEGRAM_CHAT_ID = "{{ notifications_tg_chat_id }}"
|
||||
NOTIFICATIONS_NAME = "{{ notifications_name }}"
|
||||
|
||||
|
||||
class BackupManager:
|
||||
def __init__(self):
|
||||
self.errors = []
|
||||
self.warnings = []
|
||||
self.successful_backups = []
|
||||
|
||||
def get_home_directories(self) -> List[Tuple[str, str]]:
|
||||
"""Get all home directories and their owners"""
|
||||
home_dirs = []
|
||||
home_path = Path("/home")
|
||||
|
||||
if not home_path.exists():
|
||||
logger.error("/home directory does not exist")
|
||||
return home_dirs
|
||||
|
||||
for user_dir in home_path.iterdir():
|
||||
if user_dir.is_dir():
|
||||
try:
|
||||
# Get the owner of the directory
|
||||
stat_info = user_dir.stat()
|
||||
owner = pwd.getpwuid(stat_info.st_uid).pw_name
|
||||
home_dirs.append((str(user_dir), owner))
|
||||
except (KeyError, OSError) as e:
|
||||
logger.warning(f"Could not get owner for {user_dir}: {e}")
|
||||
|
||||
return home_dirs
|
||||
|
||||
def find_backup_script(self, home_dir: str) -> Optional[str]:
|
||||
"""Find backup script in user's home directory"""
|
||||
possible_scripts = [
|
||||
os.path.join(home_dir, "backup.sh"),
|
||||
os.path.join(home_dir, "backup"),
|
||||
]
|
||||
|
||||
for script_path in possible_scripts:
|
||||
if os.path.exists(script_path):
|
||||
# Check if file is executable
|
||||
if os.access(script_path, os.X_OK):
|
||||
return script_path
|
||||
else:
|
||||
logger.warning(
|
||||
f"Backup script {script_path} exists but is not executable"
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def run_user_backup(self, script_path: str, username: str) -> bool:
|
||||
"""Run backup script as the specified user"""
|
||||
try:
|
||||
logger.info(f"Running backup script {script_path} as user {username}")
|
||||
|
||||
# Use su to run the script as the user
|
||||
cmd = ["su", "--login", username, "--command", script_path]
|
||||
|
||||
result = subprocess.run(
|
||||
cmd, capture_output=True, text=True, timeout=3600 # 1 hour timeout
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
logger.info(f"Backup script for {username} completed successfully")
|
||||
self.successful_backups.append(username)
|
||||
return True
|
||||
else:
|
||||
error_msg = f"Backup script for {username} failed with return code {result.returncode}"
|
||||
if result.stderr:
|
||||
error_msg += f": {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"User {username}: {error_msg}")
|
||||
return False
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
error_msg = f"Backup script for {username} timed out"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"User {username}: {error_msg}")
|
||||
return False
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to run backup script for {username}: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"User {username}: {error_msg}")
|
||||
return False
|
||||
|
||||
def get_backup_directories(self) -> List[str]:
|
||||
"""Get all backup directories that exist"""
|
||||
backup_dirs = []
|
||||
home_dirs = self.get_home_directories()
|
||||
|
||||
for home_dir, _ in home_dirs:
|
||||
backup_path = os.path.join(home_dir, "backups")
|
||||
if os.path.exists(backup_path) and os.path.isdir(backup_path):
|
||||
backup_dirs.append(backup_path)
|
||||
|
||||
return backup_dirs
|
||||
|
||||
def run_restic_backup(self, backup_dirs: List[str]) -> bool:
|
||||
"""Run restic backup for all backup directories"""
|
||||
if not backup_dirs:
|
||||
logger.warning("No backup directories found")
|
||||
return True
|
||||
|
||||
try:
|
||||
logger.info("Starting restic backup")
|
||||
|
||||
# Set environment variables for restic
|
||||
env = os.environ.copy()
|
||||
env.update(
|
||||
{
|
||||
"RESTIC_REPOSITORY": RESTIC_REPOSITORY,
|
||||
"RESTIC_PASSWORD": RESTIC_PASSWORD,
|
||||
"AWS_ACCESS_KEY_ID": AWS_ACCESS_KEY_ID,
|
||||
"AWS_SECRET_ACCESS_KEY": AWS_SECRET_ACCESS_KEY,
|
||||
"AWS_DEFAULT_REGION": AWS_DEFAULT_REGION,
|
||||
}
|
||||
)
|
||||
|
||||
# Run backup
|
||||
backup_cmd = ["restic", "backup", "--verbose"] + backup_dirs
|
||||
result = subprocess.run(backup_cmd, env=env, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
error_msg = f"Restic backup failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"Restic backup: {error_msg}")
|
||||
return False
|
||||
|
||||
logger.info("Restic backup completed successfully")
|
||||
|
||||
# Run check
|
||||
check_cmd = ["restic", "check"]
|
||||
result = subprocess.run(check_cmd, env=env, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
error_msg = f"Restic check failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"Restic check: {error_msg}")
|
||||
return False
|
||||
|
||||
logger.info("Restic check completed successfully")
|
||||
|
||||
# Run forget and prune
|
||||
forget_cmd = [
|
||||
"restic",
|
||||
"forget",
|
||||
"--compact",
|
||||
"--prune",
|
||||
"--keep-daily",
|
||||
"90",
|
||||
"--keep-monthly",
|
||||
"36",
|
||||
]
|
||||
result = subprocess.run(forget_cmd, env=env, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
error_msg = f"Restic forget/prune failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"Restic forget/prune: {error_msg}")
|
||||
return False
|
||||
|
||||
logger.info("Restic forget/prune completed successfully")
|
||||
|
||||
# Final check
|
||||
result = subprocess.run(check_cmd, env=env, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
error_msg = f"Final restic check failed: {result.stderr}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"Final restic check: {error_msg}")
|
||||
return False
|
||||
|
||||
logger.info("Final restic check completed successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Restic backup process failed: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
self.errors.append(f"Restic: {error_msg}")
|
||||
return False
|
||||
|
||||
def send_telegram_notification(self, success: bool) -> None:
|
||||
"""Send notification to Telegram"""
|
||||
try:
|
||||
if success and not self.errors:
|
||||
message = f"<b>{NOTIFICATIONS_NAME}</b>: бекап успешно завершен!"
|
||||
if self.successful_backups:
|
||||
message += (
|
||||
f"\n\nУспешные бекапы: {', '.join(self.successful_backups)}"
|
||||
)
|
||||
else:
|
||||
message = f"<b>{NOTIFICATIONS_NAME}</b>: бекап завершен с ошибками!"
|
||||
|
||||
if self.successful_backups:
|
||||
message += (
|
||||
f"\n\n✅ Успешные бекапы: {', '.join(self.successful_backups)}"
|
||||
)
|
||||
|
||||
if self.warnings:
|
||||
message += f"\n\n⚠️ Предупреждения:\n" + "\n".join(self.warnings)
|
||||
|
||||
if self.errors:
|
||||
message += f"\n\n❌ Ошибки:\n" + "\n".join(self.errors)
|
||||
|
||||
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
||||
data = {"chat_id": TELEGRAM_CHAT_ID, "parse_mode": "HTML", "text": message}
|
||||
|
||||
response = requests.post(url, data=data, timeout=30)
|
||||
|
||||
if response.status_code == 200:
|
||||
logger.info("Telegram notification sent successfully")
|
||||
else:
|
||||
logger.error(
|
||||
f"Failed to send Telegram notification: {response.status_code} - {response.text}"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send Telegram notification: {str(e)}")
|
||||
|
||||
def run_backup_process(self) -> bool:
|
||||
"""Main backup process"""
|
||||
logger.info("Starting backup process")
|
||||
|
||||
# Get all home directories
|
||||
home_dirs = self.get_home_directories()
|
||||
logger.info(f"Found {len(home_dirs)} home directories")
|
||||
|
||||
# Process each user's backup
|
||||
for home_dir, username in home_dirs:
|
||||
logger.info(f"Processing backup for user: {username} ({home_dir})")
|
||||
|
||||
# Find backup script
|
||||
backup_script = self.find_backup_script(home_dir)
|
||||
|
||||
if backup_script is None:
|
||||
warning_msg = (
|
||||
f"No backup script found for user {username} in {home_dir}"
|
||||
)
|
||||
logger.warning(warning_msg)
|
||||
self.warnings.append(warning_msg)
|
||||
continue
|
||||
|
||||
# Run backup script
|
||||
self.run_user_backup(backup_script, username)
|
||||
|
||||
# Get backup directories
|
||||
backup_dirs = self.get_backup_directories()
|
||||
logger.info(f"Found backup directories: {backup_dirs}")
|
||||
|
||||
# Run restic backup
|
||||
restic_success = self.run_restic_backup(backup_dirs)
|
||||
|
||||
# Determine overall success
|
||||
overall_success = restic_success and len(self.errors) == 0
|
||||
|
||||
# Send notification
|
||||
self.send_telegram_notification(overall_success)
|
||||
|
||||
logger.info("Backup process completed")
|
||||
|
||||
if self.errors:
|
||||
logger.error(f"Backup completed with {len(self.errors)} errors")
|
||||
return False
|
||||
elif self.warnings:
|
||||
logger.warning(f"Backup completed with {len(self.warnings)} warnings")
|
||||
return True
|
||||
else:
|
||||
logger.info("Backup completed successfully")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
try:
|
||||
backup_manager = BackupManager()
|
||||
success = backup_manager.run_backup_process()
|
||||
|
||||
if success:
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Backup process interrupted by user")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error in backup process: {str(e)}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -91,3 +91,14 @@ rssbridge.vakhrushev.me {
|
||||
reverse_proxy rssbridge_app:80
|
||||
}
|
||||
|
||||
dozzle.vakhrushev.me {
|
||||
tls anwinged@ya.ru
|
||||
|
||||
forward_auth authelia_app:9091 {
|
||||
uri /api/authz/forward-auth
|
||||
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name Remote-Filter
|
||||
}
|
||||
|
||||
reverse_proxy dozzle_app:8080
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
|
||||
{{ service_name }}:
|
||||
image: caddy:2.10.0
|
||||
image: caddy:2.10.2
|
||||
restart: unless-stopped
|
||||
container_name: {{ service_name }}
|
||||
ports:
|
||||
@@ -15,8 +15,8 @@ services:
|
||||
- {{ data_dir }}:/data
|
||||
- {{ config_dir }}:/config
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
23
files/dozzle/docker-compose.yml.j2
Normal file
23
files/dozzle/docker-compose.yml.j2
Normal file
@@ -0,0 +1,23 @@
|
||||
services:
|
||||
|
||||
dozzle_app:
|
||||
image: amir20/dozzle:v8.13.12
|
||||
container_name: dozzle_app
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||
networks:
|
||||
- "web_proxy_network"
|
||||
environment:
|
||||
DOZZLE_HOSTNAME: vakhrushev.me
|
||||
DOZZLE_AUTH_PROVIDER: forward-proxy
|
||||
healthcheck:
|
||||
test: ["CMD", "/dozzle", "healthcheck"]
|
||||
interval: 3s
|
||||
timeout: 30s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
web_proxy_network:
|
||||
external: true
|
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
|
||||
gitea_app:
|
||||
image: gitea/gitea:1.24.2
|
||||
image: gitea/gitea:1.24.5
|
||||
restart: unless-stopped
|
||||
container_name: gitea_app
|
||||
ports:
|
||||
@@ -13,10 +13,10 @@ services:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
environment:
|
||||
- "USER_UID=${USER_UID}"
|
||||
- "USER_GID=${USER_GID}"
|
||||
- "USER_UID={{ user_create_result.uid }}"
|
||||
- "USER_GID={{ user_create_result.group }}"
|
||||
- "GITEA__server__SSH_PORT=2222"
|
||||
|
||||
# Mailer
|
||||
@@ -29,5 +29,5 @@ services:
|
||||
- "GITEA__mailer__FROM=gitea@vakhrushev.me"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
@@ -3,14 +3,14 @@
|
||||
services:
|
||||
|
||||
gramps_app: &gramps_app
|
||||
image: ghcr.io/gramps-project/grampsweb:25.7.1
|
||||
image: ghcr.io/gramps-project/grampsweb:25.8.0
|
||||
container_name: gramps_app
|
||||
depends_on:
|
||||
- gramps_redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- "gramps_network"
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
volumes:
|
||||
- "{{ (data_dir, 'gramps_db') | path_join }}:/root/.gramps/grampsdb" # persist Gramps database
|
||||
- "{{ (data_dir, 'gramps_users') | path_join }}:/app/users" # persist user database
|
||||
@@ -61,9 +61,12 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- "gramps_network"
|
||||
- "monitoring_network"
|
||||
|
||||
networks:
|
||||
gramps_network:
|
||||
driver: bridge
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
monitoring_network:
|
||||
external: true
|
||||
|
@@ -6,9 +6,9 @@ services:
|
||||
ports:
|
||||
- "127.0.0.1:{{ homepage_port }}:80"
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
||||
|
@@ -5,23 +5,27 @@ services:
|
||||
miniflux_app:
|
||||
image: miniflux/miniflux:2.2.10
|
||||
container_name: miniflux_app
|
||||
user: "{{ user_create_result.uid }}:{{ user_create_result.group }}"
|
||||
depends_on:
|
||||
miniflux_postgres:
|
||||
condition: service_healthy
|
||||
restart: 'unless-stopped'
|
||||
networks:
|
||||
- "miniflux_network"
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
volumes:
|
||||
- "{{ secrets_dir }}:/secrets:ro"
|
||||
environment:
|
||||
- DATABASE_URL=postgres://{{ miniflux_postgres_user }}:{{ miniflux_postgres_password }}@miniflux_postgres/{{ miniflux_postgres_database }}?sslmode=disable
|
||||
- DATABASE_URL_FILE=/secrets/miniflux_database_url
|
||||
- RUN_MIGRATIONS=1
|
||||
- CREATE_ADMIN=1
|
||||
- ADMIN_USERNAME={{ miniflux_admin_user }}
|
||||
- ADMIN_PASSWORD={{ miniflux_admin_password }}
|
||||
- ADMIN_USERNAME_FILE=/secrets/miniflux_admin_user
|
||||
- ADMIN_PASSWORD_FILE=/secrets/miniflux_admin_password
|
||||
- BASE_URL=https://miniflux.vakhrushev.me
|
||||
- DISABLE_LOCAL_AUTH=1
|
||||
- OAUTH2_OIDC_DISCOVERY_ENDPOINT=https://auth.vakhrushev.me
|
||||
- OAUTH2_CLIENT_ID={{ miniflux_oidc_client_id }}
|
||||
- OAUTH2_CLIENT_SECRET={{ miniflux_oidc_client_secret }}
|
||||
- OAUTH2_CLIENT_ID_FILE=/secrets/miniflux_oidc_client_id
|
||||
- OAUTH2_CLIENT_SECRET_FILE=/secrets/miniflux_oidc_client_secret
|
||||
- OAUTH2_OIDC_PROVIDER_NAME=Authelia
|
||||
- OAUTH2_PROVIDER=oidc
|
||||
- OAUTH2_REDIRECT_URL=https://miniflux.vakhrushev.me/oauth2/oidc/callback
|
||||
@@ -32,21 +36,28 @@ services:
|
||||
miniflux_postgres:
|
||||
image: postgres:16.3-bookworm
|
||||
container_name: miniflux_postgres
|
||||
user: "{{ user_create_result.uid }}:{{ user_create_result.group }}"
|
||||
restart: 'unless-stopped'
|
||||
environment:
|
||||
- POSTGRES_USER={{ miniflux_postgres_user }}
|
||||
- POSTGRES_PASSWORD={{ miniflux_postgres_password }}
|
||||
- POSTGRES_PASSWORD_FILE=/secrets/miniflux_postgres_password
|
||||
- POSTGRES_DB={{ miniflux_postgres_database }}
|
||||
networks:
|
||||
- "miniflux_network"
|
||||
- "monitoring_network"
|
||||
volumes:
|
||||
- {{ postgres_data_dir }}:/var/lib/postgresql/data
|
||||
- "/etc/passwd:/etc/passwd:ro"
|
||||
- "{{ secrets_dir }}:/secrets:ro"
|
||||
- "{{ postgres_data_dir }}:/var/lib/postgresql/data"
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "miniflux"]
|
||||
test: ["CMD", "pg_isready", "--username={{ miniflux_postgres_user }}", "--dbname={{ miniflux_postgres_database }}"]
|
||||
interval: 10s
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
miniflux_network:
|
||||
driver: bridge
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
monitoring_network:
|
||||
external: true
|
||||
|
@@ -2,7 +2,7 @@
|
||||
services:
|
||||
|
||||
netdata:
|
||||
image: netdata/netdata:v2.5.4
|
||||
image: netdata/netdata:v2.6.3
|
||||
container_name: netdata
|
||||
restart: unless-stopped
|
||||
cap_add:
|
||||
@@ -11,7 +11,8 @@ services:
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
- "monitoring_network"
|
||||
volumes:
|
||||
- "{{ config_dir }}:/etc/netdata"
|
||||
- "{{ (data_dir, 'lib') | path_join }}:/var/lib/netdata"
|
||||
@@ -33,5 +34,7 @@ services:
|
||||
NETDATA_EXTRA_DEB_PACKAGES: "fail2ban"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
monitoring_network:
|
||||
external: true
|
||||
|
@@ -1,3 +1,3 @@
|
||||
jobs:
|
||||
- name: fail2ban
|
||||
update_every: 5 # Collect Fail2Ban jails statistics every 5 seconds
|
||||
update_every: 15 # Collect Fail2Ban jails statistics every 15 seconds
|
||||
|
9
files/netdata/go.d/postgres.conf
Normal file
9
files/netdata/go.d/postgres.conf
Normal file
@@ -0,0 +1,9 @@
|
||||
update_every: 15
|
||||
|
||||
jobs:
|
||||
|
||||
- name: outline_db
|
||||
dsn: 'postgresql://netdata:{{ netdata_postgres_password }}@outline_postgres:5432/outline'
|
||||
|
||||
- name: miniflux_db
|
||||
dsn: 'postgresql://netdata:{{ netdata_postgres_password }}@miniflux_postgres:5432/miniflux'
|
@@ -1,5 +1,4 @@
|
||||
update_every: 5
|
||||
autodetection_retry: 0
|
||||
update_every: 15
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -20,3 +19,6 @@ jobs:
|
||||
selector:
|
||||
allow:
|
||||
- "miniflux_*"
|
||||
|
||||
- name: transcriber
|
||||
url: http://transcriber_app:8080/metrics
|
||||
|
@@ -3,7 +3,7 @@ services:
|
||||
# See sample https://github.com/outline/outline/blob/main/.env.sample
|
||||
|
||||
outline_app:
|
||||
image: outlinewiki/outline:0.85.1
|
||||
image: outlinewiki/outline:0.87.3
|
||||
container_name: outline_app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -13,7 +13,7 @@ services:
|
||||
- "127.0.0.1:{{ outline_port }}:3000"
|
||||
networks:
|
||||
- "outline_network"
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
environment:
|
||||
NODE_ENV: 'production'
|
||||
URL: 'https://outline.vakhrushev.me'
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- "outline_network"
|
||||
|
||||
- "monitoring_network"
|
||||
|
||||
outline_postgres:
|
||||
image: postgres:16.3-bookworm
|
||||
@@ -69,6 +69,7 @@ services:
|
||||
- {{ postgres_data_dir }}:/var/lib/postgresql/data
|
||||
networks:
|
||||
- "outline_network"
|
||||
- "monitoring_network"
|
||||
environment:
|
||||
POSTGRES_USER: '{{ outline_postgres_user }}'
|
||||
POSTGRES_PASSWORD: '{{ outline_postgres_password }}'
|
||||
@@ -77,5 +78,7 @@ services:
|
||||
networks:
|
||||
outline_network:
|
||||
driver: bridge
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
monitoring_network:
|
||||
external: true
|
||||
|
@@ -1,12 +1,12 @@
|
||||
services:
|
||||
|
||||
rssbridge_app:
|
||||
image: rssbridge/rss-bridge:2025-06-03
|
||||
image: rssbridge/rss-bridge:2025-08-05
|
||||
container_name: rssbridge_app
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
44
files/transcriber/config.secrets.toml
Normal file
44
files/transcriber/config.secrets.toml
Normal file
@@ -0,0 +1,44 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
33396537353265633634336630353330653337623861373731613734663938633837613437366537
|
||||
3439383366633266623463366530626662346338393165630a663539313066663061353635666366
|
||||
61393437393131333166626165306563366661353338363138633239666566313330363331666537
|
||||
3763356535396334380a386362383436363732353234333033613133383264643934306432313335
|
||||
34646164323664636532663835306230386633316539373564383163346663376666633564326134
|
||||
30666135626637343963383766383836653135633739636261353666303666633566346562643962
|
||||
63376165636434343066306539653637343736323437653465656436323533636237643333326438
|
||||
35626239323530643066363533323039393237333338316135313838643464306161646635313062
|
||||
36386565626435373333393566393831366538363864313737306565343162316536353539333864
|
||||
63376264643566613266373665666363366662643262616634333132386535383731396462633430
|
||||
32343738343039616139343833366661303430383766376139636434616565356161396433643035
|
||||
37363165383935373937346464343738643430333764336264373931616332393964346566636638
|
||||
39303434343461326464623363323937396663376335316237373166306134636432376435663033
|
||||
34346436623435626363636237373965633139343661623135633764303862353465306235666563
|
||||
66653764666635636462636434663264646665383236343166643133613966366334653030653262
|
||||
38326437313939616332636638323033346139343732653933356239306132613665376163646164
|
||||
30316663643666633334653133613764396165646533636534613931663138666366316235396466
|
||||
61313964396264626339306135376635633133366433303033633363396132303938363638346333
|
||||
66326466326134313535393831343262363862663065323135643630316431336531373833316363
|
||||
64376338653366353031333836643137333736363534363164306331313337353663653961623665
|
||||
64626562366637336637353433303261303964633236356162363139396339396136393237643935
|
||||
34316266326561663834353762343766363933313463313263393063343562613933393361653861
|
||||
38363635323231666438366536626435373365323733663139666534636564623666356436346539
|
||||
63326436386436356636633637373738343032353664323736653939346234643165313461643833
|
||||
35666439613136396264313033336539313537613238393262306365656238396464373936616538
|
||||
64316365616464386638313331653030346330393665353539393834346135643434363736323135
|
||||
37663433326439356663633162616435313061353662373766633731636439636266666466613363
|
||||
39343930386534376330663230623832643933336235636166626534366664366562356165373764
|
||||
63343432323864366162376263656565646661633536666336643030363039616666343063386165
|
||||
37343238303034313832393538313632396261316232376635633732656663396631323261363433
|
||||
38373738363833323934353739643538376237316535623035383965613965636337646537326537
|
||||
64663837643632666334393634323264613139353332306263613165383733386662366333316139
|
||||
63373839346265366166333331353231663763306163323063613138323835313831303666306561
|
||||
39316666343761303464333535336361333462623363633333383363303134336139356436666165
|
||||
62616364373030613837353939363636653537373965613531636130383266643637333233316137
|
||||
39353866366239643265366162663031346439663234363935353138323739393337313835313062
|
||||
33373263326565383735366364316461323930336437623834356132346633636364313732383661
|
||||
66346634613762613037386238656334616430633037343066623463313035646339313638653137
|
||||
65643166316664626236633332326136303235623934306462643636373437373630346435633835
|
||||
66346364393236393563623032306631396561623263653236393939313333373635303365316638
|
||||
66373037333565323733656331636337336665363038353635383531386366633632363031623430
|
||||
31356461663438653736316464363231303938653932613561633139316361633461626361383132
|
||||
396436303634613135383839396566393135
|
23
files/transcriber/docker-compose.yml.j2
Normal file
23
files/transcriber/docker-compose.yml.j2
Normal file
@@ -0,0 +1,23 @@
|
||||
services:
|
||||
|
||||
transcriber_app:
|
||||
image: "{{ registry_transcriber_image }}"
|
||||
container_name: transcriber_app
|
||||
user: '{{ user_create_result.uid }}:{{ user_create_result.group }}'
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- "{{ config_file }}:/config/config.toml:ro"
|
||||
- "{{ data_dir }}:/data"
|
||||
networks:
|
||||
- "web_proxy_network"
|
||||
- "monitoring_network"
|
||||
environment:
|
||||
- "USER_UID={{ user_create_result.uid }}"
|
||||
- "USER_GID={{ user_create_result.group }}"
|
||||
command: ./transcriber --config=/config/config.toml
|
||||
|
||||
networks:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
monitoring_network:
|
||||
external: true
|
@@ -3,12 +3,12 @@
|
||||
services:
|
||||
|
||||
wakapi_app:
|
||||
image: ghcr.io/muety/wakapi:2.14.0
|
||||
image: ghcr.io/muety/wakapi:2.15.0
|
||||
container_name: wakapi_app
|
||||
restart: unless-stopped
|
||||
user: '{{ user_create_result.uid }}:{{ user_create_result.group }}'
|
||||
networks:
|
||||
- "{{ web_proxy_network }}"
|
||||
- "web_proxy_network"
|
||||
volumes:
|
||||
- "{{ data_dir }}:/data"
|
||||
environment:
|
||||
@@ -28,5 +28,5 @@ services:
|
||||
|
||||
|
||||
networks:
|
||||
{{ web_proxy_network }}:
|
||||
web_proxy_network:
|
||||
external: true
|
||||
|
14
lefthook.yml
Normal file
14
lefthook.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
# Refer for explanation to following link:
|
||||
# https://lefthook.dev/configuration/
|
||||
|
||||
templates:
|
||||
av-hooks-dir: "/home/av/projects/private/git-hooks"
|
||||
|
||||
pre-commit:
|
||||
jobs:
|
||||
|
||||
- name: "gitleaks"
|
||||
run: "gitleaks git --staged"
|
||||
|
||||
- name: "check secret files"
|
||||
run: "python3 {av-hooks-dir}/pre-commit/check-secrets-encrypted-with-ansible-vault.py"
|
@@ -5,6 +5,7 @@
|
||||
vars_files:
|
||||
- vars/ports.yml
|
||||
- vars/secrets.yml
|
||||
- files/authelia/secrets.yml
|
||||
|
||||
vars:
|
||||
app_name: "authelia"
|
||||
@@ -30,19 +31,17 @@
|
||||
loop:
|
||||
- "{{ config_dir }}"
|
||||
|
||||
- name: "Copy configuration files"
|
||||
- name: "Copy users file"
|
||||
ansible.builtin.copy:
|
||||
src: "files/{{ app_name }}/{{ item }}"
|
||||
dest: "{{ (config_dir, item) | path_join }}"
|
||||
src: "files/{{ app_name }}/users.secrets.yml"
|
||||
dest: "{{ (config_dir, 'users.yml') | path_join }}"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
loop:
|
||||
- "users.yml"
|
||||
|
||||
- name: "Copy configuration files (templates)"
|
||||
ansible.builtin.template:
|
||||
src: "files/{{ app_name }}/configuration.yml.j2"
|
||||
src: "files/{{ app_name }}/configuration.template.yml"
|
||||
dest: "{{ (config_dir, 'configuration.yml') | path_join }}"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
vars:
|
||||
restic_shell_script: "{{ (bin_prefix, 'restic-shell.sh') | path_join }}"
|
||||
backup_all_script: "{{ (bin_prefix, 'backup-all.sh') | path_join }}"
|
||||
backup_all_script: "{{ (bin_prefix, 'backup-all.py') | path_join }}"
|
||||
|
||||
tasks:
|
||||
- name: "Copy restic shell script"
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
- name: "Copy backup all script"
|
||||
ansible.builtin.template:
|
||||
src: "files/backups/backup-all.sh.j2"
|
||||
src: "files/backups/backup-all.template.py"
|
||||
dest: "{{ backup_all_script }}"
|
||||
owner: root
|
||||
group: root
|
||||
|
@@ -21,13 +21,14 @@
|
||||
- "docker-{{ docker_edition }}-cli"
|
||||
- "docker-{{ docker_edition }}-rootless-extras"
|
||||
docker_users:
|
||||
- major
|
||||
|
||||
- name: "Login to yandex docker registry."
|
||||
ansible.builtin.script:
|
||||
cmd: "files/yandex-docker-registry-auth.sh"
|
||||
- "{{ primary_user }}"
|
||||
|
||||
- name: Create a network for web proxy
|
||||
community.docker.docker_network:
|
||||
name: "{{ web_proxy_network }}"
|
||||
name: "web_proxy_network"
|
||||
driver: "bridge"
|
||||
|
||||
- name: Create a network for monitoring
|
||||
community.docker.docker_network:
|
||||
name: "monitoring_network"
|
||||
driver: "bridge"
|
||||
|
34
playbook-dozzle.yml
Normal file
34
playbook-dozzle.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
- name: "Configure dozzle application"
|
||||
hosts: all
|
||||
|
||||
vars_files:
|
||||
- vars/ports.yml
|
||||
- vars/secrets.yml
|
||||
|
||||
vars:
|
||||
app_name: "dozzle"
|
||||
app_user: "{{ app_name }}"
|
||||
base_dir: "/home/{{ app_user }}"
|
||||
|
||||
tasks:
|
||||
- name: "Create user and environment"
|
||||
ansible.builtin.import_role:
|
||||
name: owner
|
||||
vars:
|
||||
owner_name: "{{ app_user }}"
|
||||
owner_extra_groups: ["docker"]
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
src: "./files/{{ app_name }}/docker-compose.yml.j2"
|
||||
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
|
@@ -11,6 +11,7 @@
|
||||
app_user: "{{ app_name }}"
|
||||
base_dir: "/home/{{ app_user }}"
|
||||
data_dir: "{{ (base_dir, 'data') | path_join }}"
|
||||
secrets_dir: "{{ (base_dir, 'secrets') | path_join }}"
|
||||
postgres_data_dir: "{{ (base_dir, 'data', 'postgres') | path_join }}"
|
||||
postgres_backups_dir: "{{ (base_dir, 'backups', 'postgres') | path_join }}"
|
||||
|
||||
@@ -32,6 +33,21 @@
|
||||
loop:
|
||||
- "{{ postgres_backups_dir }}"
|
||||
|
||||
- name: "Copy secrets"
|
||||
ansible.builtin.import_role:
|
||||
name: secrets
|
||||
vars:
|
||||
secrets_dest: "{{ secrets_dir }}"
|
||||
secrets_user: "{{ app_user }}"
|
||||
secrets_group: "{{ app_user }}"
|
||||
secrets_vars:
|
||||
- "miniflux_database_url"
|
||||
- "miniflux_admin_user"
|
||||
- "miniflux_admin_password"
|
||||
- "miniflux_oidc_client_id"
|
||||
- "miniflux_oidc_client_secret"
|
||||
- "miniflux_postgres_password"
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
src: "./files/{{ app_name }}/docker-compose.yml.j2"
|
||||
@@ -52,4 +68,5 @@
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
state: "present"
|
||||
recreate: "always"
|
||||
remove_orphans: true
|
||||
|
@@ -42,21 +42,34 @@
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
|
||||
- name: "Copy prometheus plugin config file"
|
||||
ansible.builtin.copy:
|
||||
src: "files/{{ app_name }}/go.d/prometheus.conf"
|
||||
dest: "{{ config_go_d_dir }}/prometheus.conf"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
- name: "Find all go.d plugin config files"
|
||||
ansible.builtin.find:
|
||||
paths: "files/{{ app_name }}/go.d"
|
||||
file_type: file
|
||||
delegate_to: localhost
|
||||
register: go_d_source_files
|
||||
|
||||
- name: "Copy fail2ban plugin config file"
|
||||
ansible.builtin.copy:
|
||||
src: "files/{{ app_name }}/go.d/fail2ban.conf"
|
||||
dest: "{{ config_go_d_dir }}/fail2ban.conf"
|
||||
- name: "Template all go.d plugin config files"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.path }}"
|
||||
dest: "{{ config_go_d_dir }}/{{ item.path | basename }}"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
loop: "{{ go_d_source_files.files }}"
|
||||
|
||||
- name: "Find existing go.d config files on server"
|
||||
ansible.builtin.find:
|
||||
paths: "{{ config_go_d_dir }}"
|
||||
file_type: file
|
||||
register: go_d_existing_files
|
||||
|
||||
- name: "Remove go.d config files that don't exist in source"
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.path }}"
|
||||
state: absent
|
||||
loop: "{{ go_d_existing_files.files }}"
|
||||
when: (item.path | basename) not in (go_d_source_files.files | map(attribute='path') | map('basename') | list)
|
||||
|
||||
- name: "Grab docker group id."
|
||||
ansible.builtin.shell:
|
||||
|
92
playbook-transcriber.yml
Normal file
92
playbook-transcriber.yml
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
- name: "Deploy transcriber application"
|
||||
hosts: all
|
||||
|
||||
vars_files:
|
||||
- vars/ports.yml
|
||||
- vars/secrets.yml
|
||||
|
||||
|
||||
vars:
|
||||
app_name: "transcriber"
|
||||
app_user: "{{ app_name }}"
|
||||
base_dir: "/home/{{ app_user }}"
|
||||
|
||||
config_dir: "{{ (base_dir, 'config') | path_join }}"
|
||||
config_file: "{{ (config_dir, 'config.toml') | path_join }}"
|
||||
|
||||
data_dir: "{{ (base_dir, 'data') | path_join }}"
|
||||
backups_dir: "{{ (base_dir, 'backups') | path_join }}"
|
||||
|
||||
docker_registry_prefix: "cr.yandex/crplfk0168i4o8kd7ade"
|
||||
|
||||
# transcriber_image: "{{ transcriber_image | default(omit) }}"
|
||||
|
||||
|
||||
tasks:
|
||||
- name: "Create user and environment"
|
||||
ansible.builtin.import_role:
|
||||
name: owner
|
||||
vars:
|
||||
owner_name: "{{ app_user }}"
|
||||
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:
|
||||
- "{{ config_dir }}"
|
||||
- "{{ data_dir }}"
|
||||
- "{{ backups_dir }}"
|
||||
|
||||
- name: "Copy configuration files (templates)"
|
||||
ansible.builtin.copy:
|
||||
src: "files/{{ app_name }}/config.secrets.toml"
|
||||
dest: "{{ config_file }}"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
|
||||
- name: "Login to yandex docker registry."
|
||||
ansible.builtin.script:
|
||||
cmd: "files/yandex-docker-registry-auth.sh"
|
||||
|
||||
- name: "Deploy service"
|
||||
when: transcriber_image is defined
|
||||
block:
|
||||
# - name: "Check is web service image passed"
|
||||
# ansible.builtin.assert:
|
||||
# that:
|
||||
# - "transcriber_image is defined"
|
||||
# fail_msg: 'You must pass variable "transcriber_image"'
|
||||
|
||||
- name: "Create full image name with container registry"
|
||||
ansible.builtin.set_fact:
|
||||
registry_transcriber_image: "{{ (docker_registry_prefix, transcriber_image) | path_join }}"
|
||||
|
||||
- name: "Push web service image to remote registry"
|
||||
community.docker.docker_image:
|
||||
state: present
|
||||
source: local
|
||||
name: "{{ transcriber_image }}"
|
||||
repository: "{{ registry_transcriber_image }}"
|
||||
push: true
|
||||
delegate_to: 127.0.0.1
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
src: "./files/{{ app_name }}/docker-compose.yml.j2"
|
||||
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
|
@@ -25,3 +25,18 @@
|
||||
- name: Remove dependencies that are no longer required
|
||||
ansible.builtin.apt:
|
||||
autoremove: true
|
||||
|
||||
- name: Check if Docker is available
|
||||
ansible.builtin.stat:
|
||||
path: /usr/bin/docker
|
||||
register: docker_exists
|
||||
|
||||
- name: Clean up unnecessary Docker data
|
||||
ansible.builtin.command:
|
||||
cmd: docker system prune --all --force
|
||||
register: docker_prune_result
|
||||
when: docker_exists.stat.exists
|
||||
failed_when:
|
||||
- docker_prune_result.rc is defined
|
||||
- docker_prune_result.rc != 0
|
||||
changed_when: "'Total reclaimed space' in docker_prune_result.stdout"
|
||||
|
55
roles/secrets/README.md
Normal file
55
roles/secrets/README.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Secrets Role
|
||||
|
||||
Ansible роль для сохранения секретов на удаленной машине.
|
||||
|
||||
## Описание
|
||||
|
||||
Роль позволяет безопасно сохранять секреты на удаленной машине в виде файлов с ограниченными правами доступа. Поддерживает сохранение переменных как файлов и копирование существующих файлов.
|
||||
|
||||
## Параметры
|
||||
|
||||
### Обязательные параметры
|
||||
|
||||
- `secrets_dest` - директория, куда будут сохранены секреты в виде файлов
|
||||
- `secrets_user` - имя пользователя, который будет владеть директорией и файлами
|
||||
- `secrets_group` - группа, которая будет владеть директорией и файлами (по умолчанию равна `secrets_user`)
|
||||
|
||||
### Опциональные параметры
|
||||
|
||||
- `secrets_vars` - список переменных, из которых будут извлечены секреты (по умолчанию: `[]`)
|
||||
- `secrets_files` - список файлов, которые будут скопированы "как есть" (по умолчанию: `[]`)
|
||||
- `secrets_dir_mode` - права доступа для директории (по умолчанию: `0750`)
|
||||
- `secrets_file_mode` - права доступа для файлов с секретами (по умолчанию: `0400`)
|
||||
|
||||
## Функциональность
|
||||
|
||||
1. Создает директорию `secrets_dest` если она не существует
|
||||
2. Сохраняет каждую переменную из `secrets_vars` как файл с таким же именем
|
||||
3. Копирует файлы из `secrets_files` в директорию назначения
|
||||
4. Устанавливает права доступа `0400` для всех файлов с секретами
|
||||
5. Назначает указанного пользователя и группу владельцами директории и файлов
|
||||
|
||||
## Пример использования
|
||||
|
||||
```yaml
|
||||
- name: Save application secrets
|
||||
include_role:
|
||||
name: secrets
|
||||
vars:
|
||||
secrets_dest: /opt/myapp/secrets
|
||||
secrets_user: myapp
|
||||
secrets_group: myapp
|
||||
secrets_vars:
|
||||
- database_password
|
||||
- api_key
|
||||
- jwt_secret
|
||||
secrets_files:
|
||||
- /path/to/ssl/certificate.pem
|
||||
- /path/to/ssl/private.key
|
||||
```
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Все файлы с секретами создаются с правами `0400` (только чтение для владельца)
|
||||
- Директория создается с правами `0750` (полный доступ для владельца, чтение и выполнение для группы)
|
||||
- Используется `no_log: true` для предотвращения вывода секретов в логи Ansible
|
9
roles/secrets/defaults/main.yml
Normal file
9
roles/secrets/defaults/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
# Default variables for secrets role
|
||||
secrets_dest: ""
|
||||
secrets_user: ""
|
||||
secrets_group: "{{ secrets_user }}"
|
||||
secrets_vars: []
|
||||
secrets_files: []
|
||||
secrets_dir_mode: "0750"
|
||||
secrets_file_mode: "0400"
|
22
roles/secrets/meta/main.yml
Normal file
22
roles/secrets/meta/main.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
galaxy_info:
|
||||
author: 'Anton Vakhrushev'
|
||||
description: Ansible role for saving secrets on remote machine
|
||||
license: MIT
|
||||
min_ansible_version: '2.9'
|
||||
platforms:
|
||||
- name: Ubuntu
|
||||
versions:
|
||||
- all
|
||||
- name: Debian
|
||||
versions:
|
||||
- all
|
||||
- name: EL
|
||||
versions:
|
||||
- all
|
||||
galaxy_tags:
|
||||
- secrets
|
||||
- security
|
||||
- files
|
||||
|
||||
dependencies: []
|
46
roles/secrets/tasks/main.yml
Normal file
46
roles/secrets/tasks/main.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
# tasks file for secrets role
|
||||
|
||||
- name: "Validate secrets_dest parameter"
|
||||
ansible.builtin.fail:
|
||||
msg: "secrets_dest is required but not defined"
|
||||
when: secrets_dest is not defined or secrets_dest == ""
|
||||
|
||||
- name: "Validate secrets_user parameter"
|
||||
ansible.builtin.fail:
|
||||
msg: "secrets_user is required but not defined"
|
||||
when: secrets_user is not defined or secrets_user == ""
|
||||
|
||||
- name: "Validate secrets_group parameter"
|
||||
ansible.builtin.fail:
|
||||
msg: "secrets_group is required but not defined"
|
||||
when: secrets_group is not defined or secrets_group == ""
|
||||
|
||||
- name: "Create secrets destination directory"
|
||||
ansible.builtin.file:
|
||||
path: "{{ secrets_dest }}"
|
||||
state: directory
|
||||
owner: "{{ secrets_user }}"
|
||||
group: "{{ secrets_group }}"
|
||||
mode: "{{ secrets_dir_mode }}"
|
||||
|
||||
- name: "Save variables as secret files"
|
||||
ansible.builtin.copy:
|
||||
content: "{{ lookup('vars', item) }}"
|
||||
dest: "{{ secrets_dest }}/{{ item }}"
|
||||
owner: "{{ secrets_user }}"
|
||||
group: "{{ secrets_group }}"
|
||||
mode: "{{ secrets_file_mode }}"
|
||||
loop: "{{ secrets_vars }}"
|
||||
when: secrets_vars | length > 0
|
||||
no_log: true
|
||||
|
||||
- name: "Copy secret files"
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ secrets_dest }}/{{ item | basename }}"
|
||||
owner: "{{ secrets_user }}"
|
||||
group: "{{ secrets_group }}"
|
||||
mode: "{{ secrets_file_mode }}"
|
||||
loop: "{{ secrets_files }}"
|
||||
when: secrets_files | length > 0
|
@@ -1,11 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
SMTP Password Generator for Yandex Cloud Postbox
|
||||
|
||||
Этот скрипт конвертирует Secret Access Key в SMTP пароль для использования
|
||||
с Yandex Cloud Postbox сервисом. Скрипт реализует алгоритм AWS4 подписи
|
||||
для генерации корректного SMTP пароля.
|
||||
|
||||
Yandex Cloud Postbox использует AWS-совместимый API, и для SMTP аутентификации
|
||||
требуется специальный пароль, который генерируется из Secret Access Key
|
||||
с использованием определенного алгоритма подписи.
|
||||
|
||||
Примеры использования:
|
||||
|
||||
python3 smtp-convert-secret-key-to-password.py "YourSecretAccessKey123"
|
||||
|
||||
Требования:
|
||||
- Python 3.x
|
||||
- Стандартные библиотеки: hmac, hashlib, base64, argparse, sys
|
||||
|
||||
Автор: Yandex.Cloud Team
|
||||
Ссылка: https://yandex.cloud/ru/docs/postbox/operations/send-email
|
||||
"""
|
||||
|
||||
import hmac
|
||||
import hashlib
|
||||
import base64
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
# These values are required to calculate the signature. Do not change them.
|
||||
DATE = "20230926"
|
||||
SERVICE = "postbox"
|
70
scripts/smtp-send-test-email.py
Normal file
70
scripts/smtp-send-test-email.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
SMTP Test Email Sender for Yandex Cloud Postbox
|
||||
|
||||
Скрипт для отправки тестового email через Yandex Cloud Postbox SMTP сервер.
|
||||
Используется для проверки корректности настроек SMTP аутентификации.
|
||||
|
||||
Примеры использования:
|
||||
python3 smtp-send-test-email.py --login "your-login" --password "smtp-password" --to "recipient@example.com"
|
||||
"""
|
||||
|
||||
import smtplib
|
||||
import argparse
|
||||
import sys
|
||||
from email.message import EmailMessage
|
||||
|
||||
|
||||
def send_test_email(login, password, to_email):
|
||||
"""Отправляет тестовое email через Yandex Cloud Postbox SMTP"""
|
||||
|
||||
# initialize connection to our email server
|
||||
smtp = smtplib.SMTP("postbox.cloud.yandex.net", port="587")
|
||||
|
||||
smtp.set_debuglevel(2)
|
||||
|
||||
smtp.ehlo() # send the extended hello to our server
|
||||
smtp.starttls() # tell server we want to communicate with TLS encryption
|
||||
|
||||
smtp.login(login, password) # login to our email server
|
||||
|
||||
message = EmailMessage()
|
||||
message.set_content("Hello, world! This is a test email from Yandex Cloud Postbox.")
|
||||
message.add_header("From", "service@vakhrushev.me")
|
||||
message.add_header("To", to_email)
|
||||
message.add_header("Subject", "Test Email from Yandex Cloud Postbox")
|
||||
|
||||
# send our email message
|
||||
smtp.send_message(message)
|
||||
|
||||
smtp.quit() # finally, don't forget to close the connection
|
||||
|
||||
print(f"Test email successfully sent to {to_email}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Send a test email via Yandex Cloud Postbox SMTP server."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--login", required=True, help="SMTP login (usually your email address)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--password",
|
||||
required=True,
|
||||
help="SMTP password (generated using smtp-convert-secret-key-to-password.py)",
|
||||
)
|
||||
parser.add_argument("--to", required=True, help="Recipient email address")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
send_test_email(args.login, args.password, args.to)
|
||||
except Exception as e:
|
||||
print(f"Error sending email: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
282
vars/secrets.yml
282
vars/secrets.yml
@@ -1,142 +1,142 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
62653431636461623338643536653736633166303934626565363963373637396534303130373035
|
||||
6565376162653735313737333439633862643366336264650a633265316463323062653032363861
|
||||
32626536343138663837633334316537373662653262366163633334623764633938323363363962
|
||||
6230333564643665320a613862653632363363616266336338346539323964383736366235306437
|
||||
33306363353163383663643062656330313134353836666232616532316264303564336235356661
|
||||
30653262363866653139646436333036393837383262643537313933613939326433313565393465
|
||||
31373036353133663337613935343038616164316132303833363338623863633234656537653039
|
||||
62626436346238636234393939366139363034306432326538656264343733356537393332633836
|
||||
38636639626665666238656338363633383566616638353235383465623232646537616230626630
|
||||
63303130316438353934656636393366306566346362356564393661643064323630636463383061
|
||||
37636461386432323136393739633862313337333261306664323361393835323034643134383461
|
||||
31313762616538336666656137373631336132383364646163633732323431613239333563653332
|
||||
65616664333839363834333362626238633833666430653738613636333432333430333861356339
|
||||
61323865663661383534343964346238383134613532616637346235616139383434623564333361
|
||||
31636165653261363830623162623738333937316664633434346431626630393837366666643434
|
||||
61643734653834326434353431393732376266626266313264376235323838313539306463653864
|
||||
36393461366230643234376161623330326365616539323965633431633238386262373562383161
|
||||
39323634633166643038356434616461613864303334393932663730303839373530643933323839
|
||||
66353337326336656635636362356531613634623633303461336565363564393964663430393666
|
||||
64326439346233346132653230343234653430653239636362616561636166343030303863373337
|
||||
36363633646432613138313062346164663730313061363432396138323561366430316439343036
|
||||
32353931393064666231323863656165363066313236613332356161363139616636333963386130
|
||||
37363030383765613132353161613766633635363033656561343038633839313933646264383730
|
||||
64336339646264383332373639326164373163383966626363653762643037353636376336626136
|
||||
33346533303036326531316332306461646361376435316438376161663162336335353938366565
|
||||
30633133653431393066393961313138383337313731653031323432633766356338316366373432
|
||||
32373937663961623739633439636661336461346132376533373961666432353937373066643165
|
||||
61663063363661633938373365393665356665636562646265313834373962336566393835633339
|
||||
34396666396162613162326331313037303933366564623837386338363063636564656339336639
|
||||
66346465366233663534373465313930323134313835316464363263383866313563396263616535
|
||||
63383265623865636162346635613863356266336664343434393437656134353639353535383332
|
||||
62623934643930313939646466663336633034343534396137333264623263663866663339663266
|
||||
30343234356536663262616363376663646264353331646164376331376639363135373137396437
|
||||
37363166386233356434656237373535326162303437346233623263663534383032363638376134
|
||||
61653939306433393437656465343066613530396265396262373433383637656266303064623234
|
||||
64333062353435373863636439663561393763333538303836303631666262326430623835656138
|
||||
37653562353562373935333235316430613737653862303933333062643663333364333966643461
|
||||
33323335346566363337643161303835356336306232653763346639323265373432376239363566
|
||||
64373562653238333865326335613133636335373739396335633631313431363061616139303463
|
||||
37333364393438666532396131343637373833353766396234383739306565646439366438653032
|
||||
33656330343061636338643465653664326338663233316631303465666632653436633135643664
|
||||
64616132366632666431653262393035393163343664303961396431666236303864303865343634
|
||||
35616634613165373637653235323164323666343436646339646637646234306163333462393063
|
||||
32346534636165656436353036316232303266616135303663343631303565623562616237306365
|
||||
65303938646239393564333461343238636335336533633265383066653734613332656563666434
|
||||
31316665613630336263613934316361383332363164323266373565323239343033666663396534
|
||||
39323739313636616232663535386439363065333766623837336230303334656466656262613363
|
||||
37386664336436376530373436353235616437333834646563353830626162336261333135383866
|
||||
64383930316531373366646335306131633166353161336463376530353066356530393665393063
|
||||
31613636386532623035373866373065633233633135343439616662616232366337313764646436
|
||||
64626262643532613136373238316561616361393433323066326333663663353236393662396539
|
||||
31653036303031303462643231333965653536666136313638613832393361666131363435633932
|
||||
31663864326563663230626237643763333737613239373134626433636564386231383961316162
|
||||
39383165336433626466393935383363396333636131643733663866356434366664613766396263
|
||||
34313934626133653361633665323131613736306331373732323434323535346136393964356231
|
||||
62346136356331393238346333393266613365633563626238353530333931613330663765393936
|
||||
32333261353634646366323238353238643837633735636662356630373464343330626630656130
|
||||
36356565356430643133386461313335343436316263303064366139316638663161356332386362
|
||||
37376431393661386231313763303266313630323362363664336366633035353562303439373630
|
||||
33343265633630343065363461363064653933303932613761303538393734373962613633386539
|
||||
66636534333537313135356665633966326430373062346136326532666638303334653263646431
|
||||
38393131653338316663313265653861663334326635353137623739396636333637343137636339
|
||||
32303836373535326363396434326233623532633931653039643763326263616232333462616631
|
||||
36666564623030396134346665386661386433366266363739626161653062323963313365353161
|
||||
35643530343439326133613939353737653165326538666530366530323963363839373032326462
|
||||
34666235376263616364656130633637346334353934396132353263313237316366303137386430
|
||||
64653563333963313361303239666361336136356363306266633833366262326431616161613238
|
||||
38653538613032386238623839663332613064333031303939363733396635373238666562386536
|
||||
32316566666435376239386637396334643861643634316338613063656465373164646530363865
|
||||
34373130636435326130633437303539646535336131393339613139383636333763336530636534
|
||||
34636666666265373636326666333130623863316465663333653466353063313134386262333739
|
||||
62626264393362353663303531313061643538663532333164336662343732373463623166396539
|
||||
39396531376338616538633633343733343765306237656466666232623163303738643431633763
|
||||
61656335616430653936303831393664653365363764333362373337323364323039363163353461
|
||||
61336536316466396636306266353830316665343739613033346538333830306263386134613737
|
||||
64316339613462346438656362346664303762643766373364343931626530626439336634666537
|
||||
31633964386564663531343764326666666261643464353438353035333665363434646661646663
|
||||
38636239373331623061343730376632393963303732393533396464633131633435373161303163
|
||||
66383461343861326665623463636262336562633936623563373136613063356362383862663232
|
||||
37333331373431393137363735613366656434323065346661366433663464666363343231393863
|
||||
64633530316230653065356165366135396531663731323866376162306238343962376362633234
|
||||
61626563306431623336623737353931316236623333623337383366613262346631646330313637
|
||||
39366239396330303461303666396431663062626533336136643039353034633230353765353334
|
||||
38613362653963336162326163356662356661386630353664333265373032316531656131376665
|
||||
37376262363130336161613230333863653662623436666361396561613935323432663665643138
|
||||
38616564636634613164313666393532396265396135326538336665373232316461326635306131
|
||||
34343632636637653835653131613161316237346239363830386536363933643532333533373333
|
||||
39643364306163666366376535653333323435383332633961343930633635383030356463333964
|
||||
39626130666166313234386439383833616265316265363430343134633730336261383435356138
|
||||
62373063346238613061363033343366623633373034346531303538396335653938646664303962
|
||||
31336634623135616237323837623831306535316463613266326262663934303938373132343735
|
||||
37656335333263326531646162393738653632376164323165393563656138613830633936396433
|
||||
61353332343134636564333233393863643837353366386234376237623435663765343366363033
|
||||
63326233383962633266303962613361643464613764303531333930363736323535386632393766
|
||||
61353666303134663466333330383031333933666137346364656364313965656164303065303530
|
||||
34616130653061613934393831373130333566363736626261316330303966656162326638333130
|
||||
66373133613536623566303432356666346535636237616561323063643439616436393666376536
|
||||
32613830343636393031333737376332396230313034393062663437613838363263333233613439
|
||||
30623039336339373234326261306435366332656164613439376139346333616331326561383963
|
||||
30643133376632656564616536323863373237623263366266396264633464373765316164346165
|
||||
37636233633661643362636630356333333766613036663335613264333439323239633861363034
|
||||
34663937376530653837653236303839336631313863363239626632646436653638366638366566
|
||||
39306538353231623434373537313862386335393262633062313432646232623863383731313031
|
||||
30656366363837366666393933346238363336363030373836386230343062363661306263633163
|
||||
33626562623935643665626239386133636531393536336661613430343630333961303233343430
|
||||
63656666346138643163393663316134666336323961626163376461663635633834333337393062
|
||||
61656163613234633965356133666335343065626137633137333266613561633936386136643134
|
||||
37383562663031393133326662623136386539633066323336306262346236613161613637626162
|
||||
36636133666334333636653535623732343233396430653566393165353431303739656239373738
|
||||
33323939633264303139323162613964306237376461383261646635343036313639626539373238
|
||||
32336537373436373338386432646139303831383138326564333739353761616336346461356532
|
||||
38303138656533386231303336336564656135346162376662663962663763353830663237323138
|
||||
33373331656637363139626132393231313136303936633161636261643264313230356261366165
|
||||
39666331306262643566663830626663656530303831343231323336306266363735393966613062
|
||||
63353938386263376166316335656164633233633465303065663565373764343031663866653135
|
||||
64663766386436653665356265333565323336636539656237303334383636353161643366656637
|
||||
66356532373130323236313936623964663433333965326662333833316437326461326165376661
|
||||
66396537653032346666363965313339323331303864616230646361386335663138613433326261
|
||||
35613430363864336635343434333761656639633863323534653862383936653762646134356664
|
||||
38326463326239636162333435656561343739366364313738663535636136323439373462643832
|
||||
62633661663337343538393466613734633531666532353161616231323161646237653736346561
|
||||
64323063656366373931396639393261643333393333626539663561636661393936316539633263
|
||||
63343331313464623636353031343232613534663565303538333164306531303438616539386364
|
||||
30376233333630336431336364663834633734636261353364343564333639623737363538313462
|
||||
61616233663335303062336635376435643965373039336231346234363436356238356162613138
|
||||
65326532663461616263626238346535623136633039613939353132313836373962646463333535
|
||||
65313562346631633435616232366166373763346337303561326130333936346130363431383036
|
||||
62356435616630396539303633343166646461393030336462366463636138316333633363643636
|
||||
65376131333731356566333237363266656466376539326438313930376363386231616138336335
|
||||
65333735653830373035656265336331346562353233663465343935383235303930633831613137
|
||||
64303130666532303733633133386334613733383562613661643931636136386264396438316366
|
||||
61653964643135646332343764666134336666336232376465353462356632346533633961636534
|
||||
32643234396636303135663562656435376561336235303837643932366334616265383639343733
|
||||
65633833653763643366646232343765306131313465326263623636386131376463356139623334
|
||||
39343163366439643334646663393434353333316234623530393431643539346435616263303734
|
||||
61633066653838363933646230623238653431393061646430383537343363643562653831336362
|
||||
37626630633161653763386663373630306564663339393265663732623434643231326335376562
|
||||
37663234643466366535326461396631633430613431346134316635653032663033623465346338
|
||||
61353331393631343365663233376330333730366161353362626166646232313666336333386265
|
||||
33373761313536326165343339346263316636363362393365663034353964373164643763383037
|
||||
3666
|
||||
39383739333834626566633766343639323331333132396231613638323463316361393939616532
|
||||
3632323939633533313766616630333137393962623433620a343062373935633966643933326263
|
||||
61316632373262323534636265356664636466643361656365303366616464373734653766373265
|
||||
3531356432303735640a343965613833616631653836656561656262656263626363333436383165
|
||||
39336332303365393562353036633033633064333961323735383239643533323038623739646134
|
||||
34326465393261323539386438323737653938366333306633613066363738646639323139306337
|
||||
62333966613033616535363830626661663066303838393366653834346136396339643136363238
|
||||
38336166373238393364616463633865633431396335343562323731636639343965346365333966
|
||||
30306335313337616161666535396236373465396239663966616532313731356566653733643239
|
||||
66366361666134323136626662323932386664386165663236366436376562373431613736343663
|
||||
35613738616364393138633762316265316236616136626131376332353133353666623330343763
|
||||
38313731663739346636306435623831313835363866383138633130336638633834616564313232
|
||||
61626239303162346138346138383131613135393035353435393331623135663734306530343434
|
||||
35613463356139313034656335303637386666643435306534363637653931616631613932383763
|
||||
34626331303232323964636631663537623638313538386336336666353262613062393365306161
|
||||
33663865356533396334656361376464356534313537313739616661353665333532343032303634
|
||||
61333334393432626366313836663762333965393133313163346338613662316462376438316564
|
||||
36396632646538663262643135663364373331623730303965326237336132356434653331393932
|
||||
38623561656263326265323337646430636363653966306234396330636661626566623936343361
|
||||
34646332313130393439386534663536303932383936623938633835363236303863363032393331
|
||||
39346335653836366634323736666234653239383730313964373265623036613666363136306433
|
||||
64653265623731376239616634353262383033663134323861343566306336386263303063303162
|
||||
65613631643666643134363738346235323632326639333465313239396163386438613136346435
|
||||
64393636386637306165336235346531313333393631323239393165306535353964646637343464
|
||||
63326530666365336633393736623863623061346436613362386262343039626438356538333432
|
||||
63306136383236346166616339643530383331373233663536626535373532643464616235333935
|
||||
39616562343063613437366238336366376636663137343830653330386635353838343338643735
|
||||
62613236363337613365633334613732326130343764636663313432636665363936616162316663
|
||||
62656331316233643437373762396265353537373937623036663661643036333331613363613764
|
||||
34663963323630613337303061393266643565346464316136356132383864636463313035363565
|
||||
64306562363338326430366561646132643539353636333563353664656637393664303534613262
|
||||
33303561343035636136333766303637656232663530646630336236633165373163366533366166
|
||||
37306165306437373931366530373161646165333336396132656264383638616164396164313362
|
||||
39356230623737373135643131313264623230353366396266623538623535646566353665343163
|
||||
65336530636661326234623934663861313131366635366431623266633130393061333466333637
|
||||
36336330646566346530303961356230383430373438643336376439363036306638626633326266
|
||||
30323932326537646363353533343865356135366636353037323463303738383739373736353431
|
||||
34333337313065383561383730383461626238633561353231336639323131326239623566363734
|
||||
66663836616536646162353836346266616366383664323365373730646537363938643834613239
|
||||
62333135616264663435626535363534313138613731656466316366313032623433393336666138
|
||||
32326163613232633433616232666635343964316466306266666665646261373637353464613564
|
||||
36646162626131346537636531333339666339396666663934656334326432396231633331333465
|
||||
30333163633464396130333061663865333165633531656662613666336438616639633566383538
|
||||
63386263346161383430326662353433316664663764643438353434303666343938636237353637
|
||||
32383335326632666232396332376531643438396332626334306333636662653263636262336362
|
||||
39313130363235323334323237623631333031626266643137623132623163633039356132316266
|
||||
38393136363235393833333962663834313138373239656366383265393238343062376531643734
|
||||
62363833633261333634656364383635346431383564386639323033393265383261653665333238
|
||||
62336465383265653538393332636336336464643732303234656438393838613537326234616335
|
||||
62663336316231326639653961353736336331303831316338306439386461636563623363363564
|
||||
30303937663064353738303762653636336134633262303939346535333531636530386561623738
|
||||
31313262323663333262613832326538383430653836313438343864626336643538313839666331
|
||||
66313137303331666434376662646266623963633533613939393565393834353139613032336633
|
||||
34366333326137306432313838313463643832363462336164353838663231616634626133323962
|
||||
39663864353166373236356334633039643531383631633431383532386530396161663638326266
|
||||
36303462336531313964383563346462376164333263643664653639353539376561353037326364
|
||||
65656431613035386461333731633165346134396436656638656635313761646161343061653134
|
||||
39663339323566363636656434613735663235323164363638353565613231343464373439313535
|
||||
61633736623232356166316237363435303036666461313138623632633962326265383262656466
|
||||
64346637636135643837393637343465303761643063663730303366313937303833613435613662
|
||||
64306662343464333435646261643239616636666134346161346365326361313966666134653366
|
||||
34343362653837396264643033383562616235656362323836336362346162333631643437366432
|
||||
61393731323561306263613764633061643131333564326666613833386561646131656233633135
|
||||
39356232313565336437396637643432363466313930623661383430623236333364303835653532
|
||||
65646632623362303437373230656330306531333963393232326337623865323262383938313739
|
||||
65383364383135366464666536313365643563393633623261623764346238313339663638343735
|
||||
37393331626230333761376133633335353035386438616566656334306235643436643030303737
|
||||
32303764636663663662396534396438356639633537356434656335396462336231366530643934
|
||||
30633831373731623065623631316164613166393134633738663432333936333832653462636565
|
||||
61366164626666643366626432343335616166623437306262363264623334636539643163383736
|
||||
34346636343432323534313631373666316666633638316530386638393166343166666236353433
|
||||
34636331393433393939656265616161316535396536633330366533643135346238386237663337
|
||||
35393333343338613435393266306665356432376564653439353563376363393561393035353234
|
||||
37613535343339623334356165383532313331386430333330666132376563326532643339386432
|
||||
34346633653362626239653133363765303965623233353630313936336333336634316464653565
|
||||
33346539656538326565323966393566396636326362623839396330336364363366396132636462
|
||||
32623138626337383533313739663066366562323237666666363836396639666430363232363461
|
||||
35383963643836633432613036643064666337336166333130393730313661623035616636653166
|
||||
39393936666436306234633863323562343337386336303337333235316438383430386562346437
|
||||
30613039376633393065353031313832643339386461373433656136306339306537323434383332
|
||||
30373935623537633432373637623536653838333239336634376265313437383632653030393761
|
||||
39323033653632386264343335626330333331653635343061353633643864623062663763643236
|
||||
32373564366165653538663263323139613533353566386162303336343662663430303030376234
|
||||
62376532343134643931373436356331383431386435613839633137656566623766653131626132
|
||||
61346538393335393461346538333866323033303431613965326532343761353133663930333835
|
||||
63393537343035393339636663383961353838646234626162656563353466393335343764626166
|
||||
34303731376165353737643131636334353562353735623764666130623263376363393330333733
|
||||
37323539313263643838613863336464653536396662393730333833633030353834306439616661
|
||||
61386165333964633765326163306437313161653730636261623463666530396634326461323232
|
||||
35633635323461636361333065663466626139306464383966303435653731333732343431356463
|
||||
65653534653762646666333934323564353332333135613066323262393162623463663530353265
|
||||
61366164616261386430363337623464353933646332626439323435346230393563633330633361
|
||||
33376632663963633237386136623333623762343233613161633832663536616564363536363363
|
||||
31353035346236336131643538326663646237646539326563363161313864656332623035363663
|
||||
33386336613662373266336537663038626666646337313532616464323737343661663338656235
|
||||
65366465633932396665353965646234653431396630386535366263363263663837643465393564
|
||||
61653638643662363036353033373963303131613536663837323934313131343438386163626461
|
||||
61383065313637396361333738663130316137656237306237636637326432646437663232396632
|
||||
66626664663231343135333964623234343037393366396465353865393532666130643437653334
|
||||
33613135356637383239303931396638393163643633653662323333363066333735336466613834
|
||||
63626136333865666130336361333465633361353032336430386263323461633634306461316136
|
||||
62386263383936316534313436646266663731666265643235643538336564313632663466323037
|
||||
32333262326539376139653166633362633765333830613134393032383161343236613639356161
|
||||
34653336363739313661386331313030323331623162333837326237656137636138303439326537
|
||||
61366266316339306237373732636564616135376361373964373962656365393532366133663333
|
||||
64376565613563386134373035643266346664626537363932636532613631313861353433663537
|
||||
35363764363361303564643330383063303637393265623138343961373261636131356231303630
|
||||
33643338376562343738663136643533663530343339383834633864393234613739633730306164
|
||||
65636535346562643939316339616537363238376266643331303564316235663866343539336638
|
||||
64636564626665326635656132353531633864343964633936396465313032663262373139643735
|
||||
39653232326130393461346331323336323163646661623333663830346535646164396364383463
|
||||
35333563383536306635666232653438373961626563663332363238666433303033376365396337
|
||||
30326639356265363630646134376335636136633536366539666430343834653031303139343164
|
||||
31666130663363373537613964393338633131383266346131623662346134353033323135313632
|
||||
37336630643534393663353535386134663666383762313230356537653834333463353661616134
|
||||
37613637636364316263663464363530373463363661333037653465383139303736376166333430
|
||||
32653533313262366165353163666161336564633435333765366536356662313661333866643962
|
||||
66396538386237636631363633643634326665306539663835393465646532646535386332313761
|
||||
30323232353535393936306162626665333161353836313031383533656632346163343636616235
|
||||
62663233666361623563643638663730346165323065356335306335343565626161663164613637
|
||||
37653430323937323535646236336464663832663334383361376634396236666662376661613132
|
||||
65316638636330643131313962373766353236306136393335393435303234303863356136353666
|
||||
39613266383465363766313230663038333135663632303033616462636235383561376166643433
|
||||
38633934613436343034663432313236396333336237326536346434313662643830383734643435
|
||||
62383764643964353831663839363032333961613535626136333834613661306635663262323835
|
||||
30623232373037313666323534346330306265383561646666616432623930353432363936393564
|
||||
30643435376531666234626439373561646561316265363466363632666338353536666361313936
|
||||
62613630316630343537623437333832623563376463646662636562333336623539653031636565
|
||||
64393535643562323362343534353563383030343439666539323038663837613065303762626366
|
||||
37376433376438656531396364353532353530663333343332633437656465353864313366646231
|
||||
62323033313834313264663662326363376136336237656332313230373537663836643333623262
|
||||
63653063656639663963643737643037363231626361616530323763623739366164393863373630
|
||||
31643230316162356431336435376138303631623065626261366330396363633265383839633931
|
||||
39313538663237353730346462343438643234376165333634663232636464643561346139356539
|
||||
63376466643833353032333230356439336234343866323639356533626465353538633363633361
|
||||
38383339366665366339653632373162363838366536343935316366303464623065376632646334
|
||||
63646539643832363865383534326662626132643232353735396237373731303865353538396432
|
||||
36376434323163346536353563386662356266306231323831353361383161633239643736313135
|
||||
37383362636339643737326562393433323633356137656563643838313432386337343266386230
|
||||
63636538633935323130663338653566326334613735393932303939316134326636346663613666
|
||||
3338
|
||||
|
Reference in New Issue
Block a user