From 94dd61b20cb8efc13701927e5e1593da50b7c9bb Mon Sep 17 00:00:00 2001 From: administrator Date: Mon, 17 Aug 2026 13:43:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20'sync=5Fcerts.yml'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit деплой сертификатов letsencrypt по хостам --- sync_certs.yml | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 sync_certs.yml diff --git a/sync_certs.yml b/sync_certs.yml new file mode 100644 index 0000000..1e9ed59 --- /dev/null +++ b/sync_certs.yml @@ -0,0 +1,117 @@ +--- +- name: Универсальная динамическая синхронизация всех SSL-сертификатов Let's Encrypt + hosts: mail_servers + become: true + vars: + local_tmp_dir: "/tmp/ansible_certs" + # Имя вашего старого сервера, как оно записано в файле inventory Ansible + source_host_inventory_name: "old_server" + + tasks: + - name: БЛОК АВТОМАТИЧЕСКОГО СБОРА (Выполняется на сервере-источнике) + block: + - name: Динамический поиск только папок доменов (игнорируем README и файлы) + ansible.builtin.find: + paths: "/etc/letsencrypt/live" + file_type: directory + recurse: false + excludes: "all,README" + register: found_live_dirs + + - name: Формирование чистого списка доменов + ansible.builtin.set_fact: + dynamic_domains: "{{ found_live_dirs.files | map(attribute='path') | map('basename') | list }}" + + - name: Создание локальной структуры папок на управляющей машине (Ansible Host) + ansible.builtin.file: + path: "{{ local_tmp_dir }}/{{ item }}" + state: directory + mode: '0755' + delegate_to: localhost + run_once: true + loop: [ 'archive', 'live', 'renewal' ] + + - name: Скачивание папок archive (сохраняем оригиналы файлов) + ansible.builtin.fetch: + src: "/etc/letsencrypt/archive/{{ item }}/" + dest: "{{ local_tmp_dir }}/archive/{{ item }}/" + flat: false + loop: "{{ dynamic_domains }}" + + - name: Скачивание конфигураций обновления renewal + ansible.builtin.fetch: + src: "/etc/letsencrypt/renewal/{{ item }}.conf" + dest: "{{ local_tmp_dir }}/renewal/{{ item }}.conf" + flat: true + loop: "{{ dynamic_domains }}" + + - name: Скачивание папок live (копируем исходное содержимое) + ansible.builtin.fetch: + src: "/etc/letsencrypt/live/{{ item.0 }}/{{ item.1 }}.pem" + dest: "{{ local_tmp_dir }}/live/{{ item.0 }}/{{ item.1 }}.pem" + flat: true + loop: "{{ dynamic_domains | product(['cert', 'chain', 'fullchain', 'privkey']) | list }}" + delegate_to: "{{ source_host_inventory_name }}" + run_once: true + + - name: БЛОК НАКАТЫВАНИЯ И АДАПТИВНОГО ПЕРЕЗАПУСКА (Выполняется на удаленных хостах) + block: + - name: Сбор информации о запущенных сервисах на целевом хосте + ansible.builtin.service_facts: + + - name: Автоматическое создание всей иерархии папок Let's Encrypt на целевом хосте + ansible.builtin.file: + path: "/etc/letsencrypt/{{ item }}" + state: directory + owner: root + group: root + mode: '0755' + loop: [ 'archive', 'live', 'renewal' ] + + - name: Копирование содержимого папки archive на целевой сервер + ansible.builtin.copy: + src: "{{ local_tmp_dir }}/archive/{{ hostvars[source_host_inventory_name]['inventory_hostname'] }}/etc/letsencrypt/archive/{{ item }}/" + dest: "/etc/letsencrypt/archive/{{ item }}/" + owner: root + group: root + mode: '0600' + loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" + + - name: Копирование конфигураций renewal на целевой сервер + ansible.builtin.copy: + src: "{{ local_tmp_dir }}/renewal/{{ item }}.conf" + dest: "/etc/letsencrypt/renewal/{{ item }}.conf" + owner: root + group: root + mode: '0644' + loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" + + - name: Создание папок доменов внутри директории live + ansible.builtin.file: + path: "/etc/letsencrypt/live/{{ item }}" + state: directory + owner: root + group: root + mode: '0700' + loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] }}" + + - name: Нативная сборка относительных символических ссылок в папке live + ansible.builtin.file: + src: "../../archive/{{ item.0 }}/{{ item.1 }}1.pem" + dest: "/etc/letsencrypt/live/{{ item.0 }}/{{ item.1 }}.pem" + state: link + force: true + loop: "{{ hostvars[source_host_inventory_name]['dynamic_domains'] | product(['cert', 'chain', 'fullchain', 'privkey']) | list }}" + + - name: Автоматический перезапуск активных веб- и почтовых служб (только если они запущены) + ansible.builtin.systemd: + name: "{{ item }}" + state: restarted + loop: + - dovecot + - nginx + - apache2 + - httpd + when: + - ansible_facts.services[item + '.service'] is defined + - ansible_facts.services[item + '.service'].state == 'running' \ No newline at end of file