--- # Backup Before Redeploy # Creates comprehensive backup of Gitea data, SSL certificates, and configurations # before redeploying Traefik and Gitea stacks - name: Backup Before Redeploy hosts: production gather_facts: yes become: no vars: gitea_stack_path: "{{ stacks_base_path }}/gitea" traefik_stack_path: "{{ stacks_base_path }}/traefik" backup_base_path: "{{ backups_path | default('/home/deploy/backups') }}" backup_name: "redeploy-backup-{{ ansible_date_time.epoch }}" tasks: - name: Display backup plan ansible.builtin.debug: msg: | ================================================================================ BACKUP BEFORE REDEPLOY ================================================================================ This playbook will backup: 1. Gitea data (volumes) 2. SSL certificates (acme.json) 3. Gitea configuration (app.ini) 4. Traefik configuration 5. PostgreSQL data (if applicable) Backup location: {{ backup_base_path }}/{{ backup_name }} ================================================================================ - name: Ensure backup directory exists ansible.builtin.file: path: "{{ backup_base_path }}/{{ backup_name }}" state: directory mode: '0755' become: yes - name: Create backup timestamp file ansible.builtin.copy: content: | Backup created: {{ ansible_date_time.iso8601 }} Backup name: {{ backup_name }} Purpose: Before Traefik/Gitea redeploy dest: "{{ backup_base_path }}/{{ backup_name }}/backup-info.txt" mode: '0644' become: yes # ======================================== # Backup Gitea Data # ======================================== - name: Check Gitea volumes ansible.builtin.shell: | docker volume ls --filter name=gitea --format "{{ '{{' }}.Name{{ '}}' }}" register: gitea_volumes changed_when: false failed_when: false - name: Backup Gitea volumes ansible.builtin.shell: | for volume in {{ gitea_volumes.stdout_lines | join(' ') }}; do if [ -n "$volume" ]; then echo "Backing up volume: $volume" docker run --rm \ -v "$volume:/source:ro" \ -v "{{ backup_base_path }}/{{ backup_name }}:/backup" \ alpine tar czf "/backup/gitea-volume-${volume}.tar.gz" -C /source . fi done when: gitea_volumes.stdout_lines | length > 0 register: gitea_volumes_backup changed_when: gitea_volumes_backup.rc == 0 # ======================================== # Backup SSL Certificates # ======================================== - name: Check if acme.json exists ansible.builtin.stat: path: "{{ traefik_stack_path }}/acme.json" register: acme_json_stat - name: Backup acme.json ansible.builtin.copy: src: "{{ traefik_stack_path }}/acme.json" dest: "{{ backup_base_path }}/{{ backup_name }}/acme.json" remote_src: yes mode: '0600' when: acme_json_stat.stat.exists register: acme_backup changed_when: acme_backup.changed | default(false) # ======================================== # Backup Gitea Configuration # ======================================== - name: Backup Gitea app.ini ansible.builtin.shell: | cd {{ gitea_stack_path }} docker compose exec -T gitea cat /data/gitea/conf/app.ini > "{{ backup_base_path }}/{{ backup_name }}/gitea-app.ini" 2>/dev/null || echo "Could not read app.ini" register: gitea_app_ini_backup changed_when: false failed_when: false - name: Backup Gitea docker-compose.yml ansible.builtin.copy: src: "{{ gitea_stack_path }}/docker-compose.yml" dest: "{{ backup_base_path }}/{{ backup_name }}/gitea-docker-compose.yml" remote_src: yes mode: '0644' register: gitea_compose_backup changed_when: gitea_compose_backup.changed | default(false) # ======================================== # Backup Traefik Configuration # ======================================== - name: Backup Traefik configuration files ansible.builtin.shell: | cd {{ traefik_stack_path }} tar czf "{{ backup_base_path }}/{{ backup_name }}/traefik-config.tar.gz" \ traefik.yml \ docker-compose.yml \ dynamic/ 2>/dev/null || echo "Some files may be missing" register: traefik_config_backup changed_when: traefik_config_backup.rc == 0 failed_when: false # ======================================== # Backup PostgreSQL Data (if applicable) # ======================================== - name: Check if PostgreSQL stack exists ansible.builtin.stat: path: "{{ stacks_base_path }}/postgresql/docker-compose.yml" register: postgres_compose_exists - name: Backup PostgreSQL database (if running) ansible.builtin.shell: | cd {{ stacks_base_path }}/postgresql if docker compose ps postgres | grep -q "Up"; then docker compose exec -T postgres pg_dumpall -U postgres | gzip > "{{ backup_base_path }}/{{ backup_name }}/postgresql-all-{{ ansible_date_time.epoch }}.sql.gz" echo "PostgreSQL backup created" else echo "PostgreSQL not running, skipping backup" fi when: postgres_compose_exists.stat.exists register: postgres_backup changed_when: false failed_when: false # ======================================== # Verify Backup # ======================================== - name: List backup contents ansible.builtin.shell: | ls -lh "{{ backup_base_path }}/{{ backup_name }}/" register: backup_contents changed_when: false - name: Calculate backup size ansible.builtin.shell: | du -sh "{{ backup_base_path }}/{{ backup_name }}" | awk '{print $1}' register: backup_size changed_when: false - name: Summary ansible.builtin.debug: msg: | ================================================================================ BACKUP SUMMARY ================================================================================ Backup location: {{ backup_base_path }}/{{ backup_name }} Backup size: {{ backup_size.stdout }} Backed up: - Gitea volumes: {% if gitea_volumes_backup.changed %}✅{% else %}ℹ️ No volumes found{% endif %} - SSL certificates (acme.json): {% if acme_backup.changed | default(false) %}✅{% else %}ℹ️ Not found{% endif %} - Gitea app.ini: {% if gitea_app_ini_backup.rc == 0 %}✅{% else %}⚠️ Could not read{% endif %} - Gitea docker-compose.yml: {% if gitea_compose_backup.changed | default(false) %}✅{% else %}ℹ️ Not found{% endif %} - Traefik configuration: {% if traefik_config_backup.rc == 0 %}✅{% else %}⚠️ Some files may be missing{% endif %} - PostgreSQL data: {% if postgres_backup.rc == 0 and 'created' in postgres_backup.stdout %}✅{% else %}ℹ️ Not running or not found{% endif %} Backup contents: {{ backup_contents.stdout }} ================================================================================ NEXT STEPS ================================================================================ Backup completed successfully. You can now proceed with redeploy: ansible-playbook -i inventory/production.yml playbooks/setup/redeploy-traefik-gitea-clean.yml \ --vault-password-file secrets/.vault_pass \ -e "backup_name={{ backup_name }}" ================================================================================