@@ -828,9 +828,18 @@ Now that crontab handles scheduling, backup container should only run on-demand:
828828 - Container builds successfully with integrated testing
829829- [x] Step 1.1b: Manual E2E Integration Test ✅ **COMPLETE**
830830 - SQLite backup test: PASSED (see `docs/issues/315-phase-1.1b-results.md`)
831- - MySQL backup test: PASSED (see `docs/issues/315-phase-1.1b-results.md`)
831+ - MySQL backup test: PASSED - Full verification completed
832+ - Environment created, provisioned, configured, released, running
833+ - Backup executed via `docker compose run --rm backup`
834+ - MySQL backup file created: `mysql_20260203_194732.sql.gz` (961 bytes)
835+ - Config backup created: `config_20260203_194732.tar.gz` (6.5K)
836+ - SQL dump verified: Contains valid MySQL 8.4 database structure and table definitions
837+ - Expected "PROCESS privilege" warning is non-fatal and correctly documented
832838 - Both backup types verified with real deployments
833839 - All services remained healthy during backup operations
840+ - Fixed MySQL SSL/TLS connection issue by embedding `/etc/mysql/mysql-client.cnf` in Docker image
841+ - Simplified backup_mysql() function - removed runtime temp file creation
842+ - Configuration embedded at build time, not generated on the fly
834843- [x] Step 1.2: Create GitHub workflow for publishing ✅ **COMPLETE**
835844 - Created `.github/workflows/backup-container.yaml` following deployer workflow pattern
836845 - Uses `dockerhub-torrust-backup` environment for credentials
@@ -924,18 +933,22 @@ Now that crontab handles scheduling, backup container should only run on-demand:
924933
925934**Quality Checks**:
926935
927- - [ ] Pre-commit checks pass: `./scripts/pre-commit.sh`
936+ - [x ] Pre-commit checks pass: `./scripts/pre-commit.sh` ✅ **VERIFIED**
928937
929938**Task-Specific Criteria**:
930939
931- - [ ] Users can enable backup in environment configuration
932- - [ ] Backup container is deployed with docker-compose stack
933- - [ ] Crontab runs daily backups at configured time
934- - [ ] MySQL and SQLite databases are backed up correctly
935- - [ ] Configuration files are archived
936- - [ ] Old backups are cleaned up per retention policy
937- - [ ] Documentation covers backup usage and configuration
938- - [ ] All E2E tests pass
940+ - [x] Users can enable backup in environment configuration ✅ **VERIFIED**
941+ - [x] Backup container is deployed with docker-compose stack ✅ **VERIFIED**
942+ - [ ] Crontab runs daily backups at configured time (Phase 3)
943+ - [x] MySQL and SQLite databases are backed up correctly ✅ **VERIFIED**
944+ - SQLite: Valid compressed database file created
945+ - MySQL: Valid SQL dump created with proper headers and table definitions
946+ - [x] Configuration files are archived ✅ **VERIFIED**
947+ - [x] Old backups are cleaned up per retention policy ✅ **VERIFIED**
948+ - [x] Documentation covers backup usage and configuration ✅ **VERIFIED**
949+ - Updated: `docs/e2e-testing/manual/backup-verification.md`
950+ - Added: MySQL-specific warnings, SQL verification procedures, actual backup output examples
951+ - [ ] All E2E tests pass (depends on Phase 3 completion)
939952
940953## Technical Notes
941954
@@ -959,6 +972,42 @@ Key insights from Issue #310 research:
959972
9609735. **Log rotation**: Add logrotate config for `/var/log/tracker-backup.log`
961974
975+ ### MySQL SSL/TLS Configuration for Docker Backups
976+
977+ **Challenge**: MySQL 8.4 enforces SSL by default, but mysqldump was failing with:
978+
979+ ```text
980+ Got error: 2026: "TLS/SSL error: self-signed certificate in certificate chain"
981+ ```
982+
983+ **Root Cause**: Docker MySQL service uses self-signed certificates, and mysqldump
984+ tries to verify them by default. The backup user (`tracker_user`) doesn' t have
985+ PROCESS privilege needed for some advanced SSL verification.
986+
987+ ** Solution Implemented** :
988+
989+ - Embed MySQL client configuration in Docker image at build time: ` /etc/mysql/mysql-client.cnf`
990+ - Configuration includes: ` [mysqldump]` section with ` ssl=FALSE`
991+ - Backup script references config via: ` --defaults-file=/etc/mysql/mysql-client.cnf`
992+ - Use ` MYSQL_PWD` environment variable instead of command-line password
993+ - No runtime file creation or cleanup needed
994+
995+ ** Benefits** :
996+
997+ - ✅ Configuration managed at build time (better practice)
998+ - ✅ Cleaner runtime code (no temp file handling)
999+ - ✅ More maintainable and testable
1000+
1001+ ** Expected MySQL Backup Warning** (Non-Fatal):
1002+
1003+ ` ` ` text
1004+ mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s)
1005+ for this operation' when trying to dump tablespaces
1006+ ` ` `
1007+
1008+ This warning is expected because the backup user lacks PROCESS privilege for metadata-only
1009+ operations. The actual database backup completes successfully with all table data intact.
1010+
9621011# ## Related Files to Modify
9631012
9641013| File | Change |
0 commit comments