Files
prod/infra/ansible/playbook.yml
Andrey f8d6b92fd2 feat: add Nginx reverse proxy and SSL configuration
- Introduce Nginx service in docker-compose for handling HTTP/HTTPS traffic.
- Configure Nginx with SSL support and health checks for Grafana and Prometheus.
- Update env.template to include SERVER_IP and STATUS_PAGE_PASSWORD variables.
- Enhance Ansible playbook with tasks for Nginx installation, SSL certificate generation, and configuration management.
2025-09-16 18:31:51 +03:00

870 lines
29 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- name: Полная миграция ботов на новый сервер
hosts: new_server
become: yes
vars:
# Основная директория проекта
project_root: "/home/prod"
# Пользователь и группа
deploy_user: "deploy"
uid: "1001"
gid: "1001"
# Старый сервер для копирования данных
old_server: "root@77.223.98.129"
# Опция: пересоздавать папку /home/prod (по умолчанию — нет)
recreate_project: false
# Grafana настройки
grafana_admin_user: "{{ lookup('env', 'GRAFANA_ADMIN_USER') | default('admin') }}"
grafana_admin_password: "{{ lookup('env', 'GRAFANA_ADMIN_PASSWORD') | default('admin') }}"
tasks:
- name: Обновить SSH host key для избежания ошибок при переустановке
known_hosts:
path: ~/.ssh/known_hosts
name: "{{ ansible_host }}"
key: "{{ lookup('pipe', 'ssh-keyscan -t rsa,ecdsa,ed25519 ' + ansible_host) }}"
state: present
delegate_to: localhost
run_once: true
ignore_errors: yes
- name: Обновить кэш пакетов
apt:
update_cache: yes
- name: Установить необходимые пакеты
apt:
name:
- docker.io
- docker-compose
- make
- git
- python3-pip
- curl
- sshpass
- rsync
- vim
- zsh
- ufw
- htop
- iotop
- traceroute
- ncdu
- prometheus-node-exporter
- fail2ban
- tzdata
- nginx
- openssl
- apache2-utils
state: present
- name: Установить часовой пояс Europe/Moscow
timezone:
name: Europe/Moscow
- name: Проверить существование swap-файла
stat:
path: /swapfile
register: swap_file_stat
- name: Создать swap-файл (2GB)
command: fallocate -l 2G /swapfile
when: not swap_file_stat.stat.exists
- name: Установить правильные права на swap-файл
file:
path: /swapfile
mode: '0600'
owner: root
group: root
- name: Настроить swap-файл
command: mkswap /swapfile
when: not swap_file_stat.stat.exists
- name: Включить swap-файл
command: swapon /swapfile
when: not swap_file_stat.stat.exists
- name: Настроить swappiness = 10 (временно)
sysctl:
name: vm.swappiness
value: '10'
state: present
reload: yes
- name: Настроить swappiness = 10 (постоянно)
lineinfile:
path: /etc/sysctl.conf
regexp: '^vm\.swappiness\s*='
line: 'vm.swappiness = 10'
state: present
- name: Добавить swap-файл в /etc/fstab для автоматического монтирования
lineinfile:
path: /etc/fstab
line: '/swapfile none swap sw 0 0'
state: present
create: yes
# --- НАСТРОЙКА БЕЗОПАСНОСТИ ЯДРА ---
- name: Настроить параметры безопасности ядра
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
state: present
reload: yes
loop:
# Защита от DDoS
- { name: "net.ipv4.tcp_syn_retries", value: "2" }
- { name: "net.ipv4.tcp_synack_retries", value: "2" }
- { name: "net.ipv4.tcp_max_syn_backlog", value: "2048" }
- { name: "net.ipv4.tcp_fin_timeout", value: "15" }
- { name: "net.ipv4.tcp_keepalive_time", value: "1200" }
- { name: "net.ipv4.tcp_keepalive_intvl", value: "15" }
- { name: "net.ipv4.tcp_keepalive_probes", value: "5" }
- { name: "net.core.netdev_max_backlog", value: "1000" }
- { name: "net.core.somaxconn", value: "65535" }
# Защита от IP спуфинга
- { name: "net.ipv4.conf.all.accept_source_route", value: "0" }
- { name: "net.ipv4.conf.default.accept_source_route", value: "0" }
- { name: "net.ipv6.conf.all.accept_source_route", value: "0" }
- { name: "net.ipv6.conf.default.accept_source_route", value: "0" }
# Защита от фрагментации
- { name: "net.ipv4.conf.all.log_martians", value: "1" }
- { name: "net.ipv4.conf.default.log_martians", value: "1" }
- { name: "net.ipv4.icmp_echo_ignore_broadcasts", value: "1" }
- { name: "net.ipv4.icmp_ignore_bogus_error_responses", value: "1" }
- { name: "net.ipv4.tcp_syncookies", value: "1" }
- { name: "net.ipv4.conf.all.rp_filter", value: "1" }
- { name: "net.ipv4.conf.default.rp_filter", value: "1" }
# Для Docker
- { name: "kernel.pid_max", value: "65536" }
- { name: "kernel.threads-max", value: "4096" }
- { name: "vm.max_map_count", value: "262144" }
- name: Сохранить параметры безопасности в /etc/sysctl.conf
lineinfile:
path: /etc/sysctl.conf
regexp: "^{{ item.name }}\\s*="
line: "{{ item.name }} = {{ item.value }}"
state: present
loop:
# Защита от DDoS
- { name: "net.ipv4.tcp_syn_retries", value: "2" }
- { name: "net.ipv4.tcp_synack_retries", value: "2" }
- { name: "net.ipv4.tcp_max_syn_backlog", value: "2048" }
- { name: "net.ipv4.tcp_fin_timeout", value: "15" }
- { name: "net.ipv4.tcp_keepalive_time", value: "1200" }
- { name: "net.ipv4.tcp_keepalive_intvl", value: "15" }
- { name: "net.ipv4.tcp_keepalive_probes", value: "5" }
- { name: "net.core.netdev_max_backlog", value: "1000" }
- { name: "net.core.somaxconn", value: "65535" }
# Защита от IP спуфинга
- { name: "net.ipv4.conf.all.accept_source_route", value: "0" }
- { name: "net.ipv4.conf.default.accept_source_route", value: "0" }
- { name: "net.ipv6.conf.all.accept_source_route", value: "0" }
- { name: "net.ipv6.conf.default.accept_source_route", value: "0" }
# Защита от фрагментации
- { name: "net.ipv4.conf.all.log_martians", value: "1" }
- { name: "net.ipv4.conf.default.log_martians", value: "1" }
- { name: "net.ipv4.icmp_echo_ignore_broadcasts", value: "1" }
- { name: "net.ipv4.icmp_ignore_bogus_error_responses", value: "1" }
- { name: "net.ipv4.tcp_syncookies", value: "1" }
- { name: "net.ipv4.conf.all.rp_filter", value: "1" }
- { name: "net.ipv4.conf.default.rp_filter", value: "1" }
# Для Docker
- { name: "kernel.pid_max", value: "65536" }
- { name: "kernel.threads-max", value: "4096" }
- { name: "vm.max_map_count", value: "262144" }
- name: Проверить статус swap
command: swapon --show
register: swap_status
changed_when: false
- name: Показать информацию о swap
debug:
var: swap_status.stdout_lines
- name: Включить и запустить prometheus-node-exporter
systemd:
name: prometheus-node-exporter
enabled: yes
state: started
- name: Проверить статус prometheus-node-exporter
command: systemctl status prometheus-node-exporter
register: node_exporter_status
changed_when: false
- name: Показать статус prometheus-node-exporter
debug:
var: node_exporter_status.stdout_lines
- name: Проверить, что node_exporter слушает на порту 9100
command: netstat -tulpn | grep 9100
register: node_exporter_port
changed_when: false
- name: Показать информацию о порте 9100
debug:
var: node_exporter_port.stdout_lines
- name: Обновить Docker Compose до последней версии
get_url:
url: "https://github.com/docker/compose/releases/latest/download/docker-compose-{{ ansible_system }}-{{ ansible_architecture }}"
dest: /usr/local/bin/docker-compose
mode: '0755'
become: yes
- name: Включить и запустить Docker
systemd:
name: docker
enabled: yes
state: started
- name: Разрешить SSH (порт 22) перед включением UFW
ufw:
rule: allow
port: "22"
proto: tcp
- name: Разрешить новый SSH порт (15722) перед включением UFW
ufw:
rule: allow
port: "15722"
proto: tcp
- name: Настроить политику UFW по умолчанию
ufw:
policy: deny
direction: incoming
- name: Включить UFW (файрвол)
ufw:
state: enabled
- name: Открыть порты для сервисов
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "8080" # Telegram Bot
- "8081" # AnonBot
- "9090" # Prometheus
- "3000" # Grafana
- "9100" # Node Exporter
- "80" # HTTP
- "443" # HTTPS
# --- НАСТРОЙКА NGINX ---
- name: Остановить nginx (если запущен)
systemd:
name: nginx
state: stopped
ignore_errors: yes
- name: Создать директории для nginx конфигураций
file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: '0755'
loop:
- "{{ project_root }}/infra/nginx"
- "{{ project_root }}/infra/nginx/ssl"
- "{{ project_root }}/infra/nginx/conf.d"
- name: Сгенерировать самоподписанный SSL сертификат
command: >
openssl req -x509 -newkey rsa:4096 -keyout {{ project_root }}/infra/nginx/ssl/key.pem
-out {{ project_root }}/infra/nginx/ssl/cert.pem -days 365 -nodes
-subj "/CN={{ ansible_host }}/O=Monitoring/C=RU"
args:
creates: "{{ project_root }}/infra/nginx/ssl/cert.pem"
- name: Установить права на SSL сертификаты
file:
path: "{{ item }}"
owner: root
group: root
mode: '0600'
loop:
- "{{ project_root }}/infra/nginx/ssl/cert.pem"
- "{{ project_root }}/infra/nginx/ssl/key.pem"
- name: Создать htpasswd файл для status page
htpasswd:
path: "{{ project_root }}/infra/nginx/.htpasswd"
name: "admin"
password: "{{ lookup('env', 'STATUS_PAGE_PASSWORD') | default('admin123') }}"
owner: root
group: root
mode: '0644'
- name: Скопировать основную конфигурацию nginx
copy:
src: "{{ project_root }}/infra/nginx/nginx.conf"
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
backup: yes
- name: Скопировать конфигурации nginx для сервисов
copy:
src: "{{ project_root }}/infra/nginx/conf.d/"
dest: /etc/nginx/conf.d/
owner: root
group: root
mode: '0644'
backup: yes
- name: Скопировать SSL сертификаты
copy:
src: "{{ project_root }}/infra/nginx/ssl/"
dest: /etc/nginx/ssl/
owner: root
group: root
mode: '0600'
backup: yes
- name: Скопировать htpasswd файл
copy:
src: "{{ project_root }}/infra/nginx/.htpasswd"
dest: /etc/nginx/.htpasswd
owner: root
group: root
mode: '0644'
backup: yes
- name: Проверить конфигурацию nginx
command: nginx -t
register: nginx_config_test
changed_when: false
- name: Показать результат проверки nginx
debug:
var: nginx_config_test.stdout_lines
- name: Включить и запустить nginx
systemd:
name: nginx
enabled: yes
state: started
- name: Проверить статус nginx
command: systemctl status nginx
register: nginx_status
changed_when: false
- name: Показать статус nginx
debug:
var: nginx_status.stdout_lines
- name: Проверить существование пользователя deploy
getent:
database: passwd
key: "{{ deploy_user }}"
register: user_exists
failed_when: false
- name: Создать группу deploy с GID 1001
group:
name: "{{ deploy_user }}"
gid: "{{ gid }}"
when: user_exists.ansible_facts.getent_passwd is not defined
- name: Создать пользователя deploy с UID 1001 (если не существует)
user:
name: "{{ deploy_user }}"
uid: "{{ uid }}"
group: "{{ gid }}"
shell: /bin/zsh
create_home: yes
system: no
groups: docker
append: yes
when: user_exists.ansible_facts.getent_passwd is not defined
- name: Установить zsh как оболочку по умолчанию для существующего пользователя deploy
user:
name: "{{ deploy_user }}"
shell: /bin/zsh
when: user_exists.ansible_facts.getent_passwd is defined
- name: Скопировать SSH ключ с локальной машины для пользователя deploy
authorized_key:
user: "{{ deploy_user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
- name: Настроить безопасный SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^{{ item.regexp }}"
line: "{{ item.line }}"
backup: yes
loop:
- { regexp: "Port", line: "Port 15722" }
- { regexp: "PermitRootLogin", line: "PermitRootLogin no" }
- { regexp: "PasswordAuthentication", line: "PasswordAuthentication no" }
- { regexp: "PubkeyAuthentication", line: "PubkeyAuthentication yes" }
- { regexp: "AllowUsers", line: "AllowUsers {{ deploy_user }}" }
notify: reload ssh
- name: Переподключиться по новому SSH порту
meta: reset_connection
- name: Удалить /home/prod, если требуется (чистое развертывание)
file:
path: "{{ project_root }}"
state: absent
when: recreate_project | bool
- name: Создать директорию проекта /home/prod
file:
path: "{{ project_root }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
- name: Настроить SSH ключи для GitHub
authorized_key:
user: "{{ deploy_user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
- name: Скопировать приватный SSH ключ для Git
copy:
src: "~/.ssh/id_rsa"
dest: "/home/{{ deploy_user }}/.ssh/id_rsa"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0600'
remote_src: no
- name: Настроить SSH config для GitHub
lineinfile:
path: "/home/{{ deploy_user }}/.ssh/config"
line: "Host github.com\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null"
create: yes
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0600'
- name: Переключиться на пользователя deploy
meta: reset_connection
- name: Клонировать основной репозиторий prod
git:
repo: git@github.com:KerradKerridi/prod.git
dest: "{{ project_root }}"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Клонировать AnonBot
git:
repo: git@github.com:KerradKerridi/AnonBot.git
dest: "{{ project_root }}/bots/AnonBot"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Клонировать telegram-helper-bot
git:
repo: git@github.com:KerradKerridi/telegram-helper-bot.git
dest: "{{ project_root }}/bots/telegram-helper-bot"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Установить правильные права на дашборд Node Exporter Full
file:
path: "{{ project_root }}/infra/grafana/provisioning/dashboards/node-exporter-full-dashboard.json"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Скопировать SSH ключ на старый сервер для копирования файлов
authorized_key:
user: root
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
delegate_to: "{{ old_server }}"
- name: Копировать .env для telegram-helper-bot со старого сервера
fetch:
src: "/home/prod/bots/telegram-helper-bot/.env"
dest: "/tmp/telegram-helper-bot.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить .env для telegram-helper-bot на новое место
copy:
src: "/tmp/telegram-helper-bot.env"
dest: "{{ project_root }}/bots/telegram-helper-bot/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Проверить размер БД для telegram-helper-bot
stat:
path: "/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db"
delegate_to: "{{ old_server }}"
register: db_size
- name: Показать размер БД для telegram-helper-bot
debug:
msg: "Размер БД: {{ (db_size.stat.size / 1024 / 1024) | round(2) }} MB"
- name: Копировать БД для telegram-helper-bot
fetch:
src: "/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db"
dest: "/tmp/tg-bot-database.db"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить БД для telegram-helper-bot на новое место
copy:
src: "/tmp/tg-bot-database.db"
dest: "{{ project_root }}/bots/telegram-helper-bot/database/tg-bot-database.db"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Создать папку voice_users на новом сервере
file:
path: "{{ project_root }}/bots/telegram-helper-bot/voice_users"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
become: yes
become_user: "{{ deploy_user }}"
- name: Создать временную папку для voice_users на локальной машине
file:
path: "/tmp/voice_users_migration"
state: directory
mode: '0755'
delegate_to: localhost
become: no
- name: Копировать voice_users со старого сервера на локальную машину
command: >
rsync -avz --progress --stats --partial --verbose
root@77.223.98.129:/home/prod/bots/telegram-helper-bot/voice_users/
/tmp/voice_users_migration/
delegate_to: localhost
become: no
- name: Копировать voice_users с локальной машины на новый сервер
synchronize:
src: "/tmp/voice_users_migration/"
dest: "{{ project_root }}/bots/telegram-helper-bot/voice_users/"
mode: push
rsync_opts: "--progress --stats --partial --verbose"
become: yes
become_user: "{{ deploy_user }}"
- name: Очистить временную папку на локальной машине
file:
path: "/tmp/voice_users_migration"
state: absent
delegate_to: localhost
become: no
- name: Копировать корневой .env файл
fetch:
src: "/home/prod/.env"
dest: "/tmp/root.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить корневой .env файл на новое место
copy:
src: "/tmp/root.env"
dest: "{{ project_root }}/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Копировать .env для AnonBot
fetch:
src: "/home/prod/bots/AnonBot/.env"
dest: "/tmp/anonbot.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить .env для AnonBot на новое место
copy:
src: "/tmp/anonbot.env"
dest: "{{ project_root }}/bots/AnonBot/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Проверить размер БД для AnonBot
stat:
path: "/home/prod/bots/AnonBot/database/anon_qna.db"
delegate_to: "{{ old_server }}"
register: anon_db_size
- name: Показать размер БД для AnonBot
debug:
msg: "Размер БД AnonBot: {{ (anon_db_size.stat.size / 1024 / 1024) | round(2) }} MB"
- name: Копировать БД для AnonBot
fetch:
src: "/home/prod/bots/AnonBot/database/anon_qna.db"
dest: "/tmp/anon_qna.db"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить БД для AnonBot на новое место
copy:
src: "/tmp/anon_qna.db"
dest: "{{ project_root }}/bots/AnonBot/database/anon_qna.db"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Установить права на скопированные файлы
file:
path: "{{ item }}"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
loop:
- "{{ project_root }}/bots/telegram-helper-bot/.env"
- "{{ project_root }}/bots/telegram-helper-bot/database/tg-bot-database.db"
- "{{ project_root }}/bots/AnonBot/.env"
- "{{ project_root }}/bots/AnonBot/database/anon_qna.db"
become: yes
- name: Исправить права доступа для voice_users (рекурсивно)
file:
path: "{{ project_root }}/bots/telegram-helper-bot/voice_users"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
recurse: yes
become: yes
- name: Запустить ботов через make up
command: make up
args:
chdir: "{{ project_root }}"
become: yes
become_user: "{{ deploy_user }}"
tags: ["start_bots"]
# --- НАСТРОЙКА FAIL2BAN ---
- name: Создать конфигурацию Fail2ban для SSH
copy:
content: |
[sshd]
enabled = true
port = 15722
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
dest: /etc/fail2ban/jail.d/sshd.local
owner: root
group: root
mode: '0644'
- name: Создать конфигурацию Fail2ban для Nginx
copy:
content: |
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
findtime = 600
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600
findtime = 600
dest: /etc/fail2ban/jail.d/nginx.local
owner: root
group: root
mode: '0644'
- name: Создать конфигурацию Fail2ban для Docker
copy:
content: |
[docker]
enabled = true
port = 2375,2376
filter = docker
logpath = /var/log/syslog
maxretry = 3
bantime = 3600
findtime = 600
dest: /etc/fail2ban/jail.d/docker.local
owner: root
group: root
mode: '0644'
- name: Включить и запустить Fail2ban
systemd:
name: fail2ban
enabled: yes
state: started
- name: Проверить статус Fail2ban
command: fail2ban-client status
register: fail2ban_status
changed_when: false
- name: Показать статус Fail2ban
debug:
var: fail2ban_status.stdout_lines
# --- НОВОЕ: Проверка портов ---
- name: Пауза на 30 секунд — дать контейнерам запуститься
pause:
seconds: 30
- name: Проверить, что порт 8080 (Telegram Bot) открыт
wait_for:
port: 8080
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 8081 (AnonBot) открыт
wait_for:
port: 8081
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 9090 (Prometheus) открыт
wait_for:
port: 9090
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 3000 (Grafana) открыт
wait_for:
port: 3000
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 9100 (Node Exporter) открыт
wait_for:
port: 9100
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 80 (Nginx HTTP) открыт
wait_for:
port: 80
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 443 (Nginx HTTPS) открыт
wait_for:
port: 443
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить доступность Nginx
uri:
url: "http://{{ ansible_host }}/nginx-health"
method: GET
status_code: 200
register: nginx_health
retries: 5
delay: 10
- name: Проверить доступность Grafana через Nginx
uri:
url: "https://{{ ansible_host }}/grafana/api/health"
method: GET
status_code: 200
validate_certs: no
register: grafana_nginx_health
retries: 5
delay: 10
- name: Проверить доступность Prometheus через Nginx
uri:
url: "https://{{ ansible_host }}/prometheus/-/healthy"
method: GET
status_code: 200
validate_certs: no
register: prometheus_nginx_health
retries: 5
delay: 10
- name: Проверить доступность Grafana API
uri:
url: "http://{{ ansible_host }}:3000/api/health"
method: GET
status_code: 200
register: grafana_health
retries: 5
delay: 10
- name: Закрыть старый SSH порт 22 в UFW (финальный шаг)
ufw:
rule: deny
port: "22"
proto: tcp
- name: Проверка запуска ботов завершена — всё работает 🟢
debug:
msg: "Все сервисы запущены и слушают нужные порты. SSH настроен на порт 15722, Fail2ban активен, параметры безопасности ядра применены. Порт 22 закрыт для безопасности."
# handlers для перезагрузки сервисов
handlers:
- name: reload ssh
systemd:
name: ssh
state: reloaded
- name: restart ufw
ufw:
state: reloaded