--- # Backup Forgejo data and database # Creates timestamped backups and optionally uploads to S3 - name: Backup Forgejo hosts: forgejo become: yes gather_facts: yes vars_files: - vars/main.yml - vars/secrets.yml vars: backup_timestamp: "{{ ansible_date_time.iso8601_basic_short }}" backup_filename: "forgejo-backup-{{ backup_timestamp }}.tar.gz" upload_to_s3: "{{ forgejo_backup_to_s3 | default(false) }}" pre_tasks: - name: Display backup information ansible.builtin.debug: msg: | Creating backup: {{ backup_filename }} Upload to S3: {{ upload_to_s3 }} Backup path: {{ forgejo_backup_path }} tasks: - name: Ensure backup directory exists ansible.builtin.file: path: "{{ forgejo_backup_path }}" state: directory owner: "{{ forgejo_user }}" group: "{{ forgejo_group }}" mode: '0750' - name: Create PostgreSQL backup community.postgresql.postgresql_db: name: "{{ forgejo_db_name }}" state: dump target: "{{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql" become_user: postgres when: forgejo_db_type == 'postgres' - name: Compress database backup community.general.archive: path: "{{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql" dest: "{{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql.gz" format: gz remove: yes when: forgejo_db_type == 'postgres' - name: Create Git repositories backup community.general.archive: path: "{{ forgejo_data_path }}/git" dest: "{{ forgejo_backup_path }}/repositories-{{ backup_timestamp }}.tar.gz" format: gz - name: Backup configuration files community.general.archive: path: - "{{ forgejo_config_path }}" - "{{ forgejo_base_path }}/docker-compose.yml" dest: "{{ forgejo_backup_path }}/config-{{ backup_timestamp }}.tar.gz" format: gz - name: Backup attachments and LFS community.general.archive: path: - "{{ forgejo_data_path }}/attachments" - "{{ forgejo_data_path }}/lfs" - "{{ forgejo_data_path }}/avatars" dest: "{{ forgejo_backup_path }}/data-{{ backup_timestamp }}.tar.gz" format: gz - name: Create backup manifest ansible.builtin.copy: dest: "{{ forgejo_backup_path }}/manifest-{{ backup_timestamp }}.json" content: | { "timestamp": "{{ ansible_date_time.iso8601 }}", "version": "{{ forgejo_version }}", "hostname": "{{ ansible_hostname }}", "database": "{{ forgejo_db_type }}", "files": { "database": "database-{{ backup_timestamp }}.sql.gz", "repositories": "repositories-{{ backup_timestamp }}.tar.gz", "config": "config-{{ backup_timestamp }}.tar.gz", "data": "data-{{ backup_timestamp }}.tar.gz" }, "sizes": {} } mode: '0644' - name: Get backup file sizes ansible.builtin.stat: path: "{{ forgejo_backup_path }}/{{ item }}" register: backup_files loop: - "database-{{ backup_timestamp }}.sql.gz" - "repositories-{{ backup_timestamp }}.tar.gz" - "config-{{ backup_timestamp }}.tar.gz" - "data-{{ backup_timestamp }}.tar.gz" - name: Display backup sizes ansible.builtin.debug: msg: "{{ item.item }}: {{ (item.stat.size / 1024 / 1024) | round(2) }} MB" loop: "{{ backup_files.results }}" when: item.stat.exists - name: Upload to S3 when: upload_to_s3 and forgejo_enable_s3 block: - name: Install AWS CLI ansible.builtin.pip: name: awscli state: present - name: Upload database backup to S3 ansible.builtin.command: cmd: > aws s3 cp {{ forgejo_backup_path }}/database-{{ backup_timestamp }}.sql.gz s3://{{ forgejo_backup_s3_bucket }}/backups/database-{{ backup_timestamp }}.sql.gz --endpoint-url {{ forgejo_s3_endpoint }} environment: AWS_ACCESS_KEY_ID: "{{ forgejo_s3_access_key }}" AWS_SECRET_ACCESS_KEY: "{{ forgejo_s3_secret_key }}" no_log: yes - name: Upload repositories backup to S3 ansible.builtin.command: cmd: > aws s3 cp {{ forgejo_backup_path }}/repositories-{{ backup_timestamp }}.tar.gz s3://{{ forgejo_backup_s3_bucket }}/backups/repositories-{{ backup_timestamp }}.tar.gz --endpoint-url {{ forgejo_s3_endpoint }} environment: AWS_ACCESS_KEY_ID: "{{ forgejo_s3_access_key }}" AWS_SECRET_ACCESS_KEY: "{{ forgejo_s3_secret_key }}" no_log: yes - name: Upload config backup to S3 ansible.builtin.command: cmd: > aws s3 cp {{ forgejo_backup_path }}/config-{{ backup_timestamp }}.tar.gz s3://{{ forgejo_backup_s3_bucket }}/backups/config-{{ backup_timestamp }}.tar.gz --endpoint-url {{ forgejo_s3_endpoint }} environment: AWS_ACCESS_KEY_ID: "{{ forgejo_s3_access_key }}" AWS_SECRET_ACCESS_KEY: "{{ forgejo_s3_secret_key }}" no_log: yes - name: Upload manifest to S3 ansible.builtin.command: cmd: > aws s3 cp {{ forgejo_backup_path }}/manifest-{{ backup_timestamp }}.json s3://{{ forgejo_backup_s3_bucket }}/backups/manifest-{{ backup_timestamp }}.json --endpoint-url {{ forgejo_s3_endpoint }} environment: AWS_ACCESS_KEY_ID: "{{ forgejo_s3_access_key }}" AWS_SECRET_ACCESS_KEY: "{{ forgejo_s3_secret_key }}" no_log: yes - name: Clean up old backups ansible.builtin.shell: | find {{ forgejo_backup_path }} -name "*.tar.gz" -o -name "*.sql.gz" -o -name "*.json" | \ grep -E "[0-9]{8}T[0-9]{6}" | \ sort -r | \ tail -n +{{ (forgejo_backup_retention_days | int * 4) + 1 }} | \ xargs -r rm -f args: executable: /bin/bash when: forgejo_backup_retention_days is defined post_tasks: - name: Calculate total backup size ansible.builtin.shell: | du -sh {{ forgejo_backup_path }} | cut -f1 register: total_backup_size changed_when: false - name: Display completion message ansible.builtin.debug: msg: | ======================================== Backup Complete! ======================================== Timestamp: {{ backup_timestamp }} Location: {{ forgejo_backup_path }} Total size: {{ total_backup_size.stdout }} Files created: - database-{{ backup_timestamp }}.sql.gz - repositories-{{ backup_timestamp }}.tar.gz - config-{{ backup_timestamp }}.tar.gz - data-{{ backup_timestamp }}.tar.gz - manifest-{{ backup_timestamp }}.json {% if upload_to_s3 %} Uploaded to S3: {{ forgejo_backup_s3_bucket }}/backups/ {% endif %} Retention: {{ forgejo_backup_retention_days }} days ========================================