- Create dedicated apache/mpm_prefork.conf to override default MPM settings
- Mount mpm_prefork.conf to /etc/apache2/mods-available/ to properly apply limits
- Remove MPM config from nextcloud.conf (was being ignored)
- Set ServerLimit and MaxRequestWorkers to 400 (up from 150 default)
- Configure optimized worker settings for better concurrency
This fixes the "server reached MaxRequestWorkers" error that was causing
sync failures and 404 errors by properly overriding Apache's default
configuration file instead of trying to set it in conf-enabled.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Increase MaxRequestWorkers from 150 to 400 to prevent "server reached MaxRequestWorkers" errors
- Configure MPM Prefork module with optimized worker settings
- Add AllowEncodedSlashes NoDecode for special characters in filenames
- Increase Redis maxmemory from 512MB to 2GB for better caching
- Extend PHP execution times from 1800s to 7200s for large operations
- Increase MariaDB max_allowed_packet to 1GB for large file uploads
These changes resolve sync failures caused by Apache worker exhaustion.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Mount Apache logs directory to ./logs/apache
- Configure JSON file logging driver with rotation
- Set max log size to 10MB with 3 files retention
- Enable fail2ban to monitor access logs directly
- Prevents need for systemd service to export logs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Script not mounted in Docker container
- Cannot be executed from container
- Commands already documented in README
- Reduces maintenance overhead
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add Timeout 3600 (1h) for long-running uploads
- Enable KeepAlive with 300s timeout to maintain connections
- Set MaxKeepAliveRequests to 200 for chunked uploads
- Fixes sync client errors on files larger than 40MB
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add custom Apache configuration file to optimize Nextcloud performance and security.
Mount nextcloud.conf into Apache's conf-enabled directory for automatic loading.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added comprehensive documentation about debug mode:
In "Résolution de problèmes" section:
- How to check debug mode status
- How to disable debug mode (production)
- How to enable temporarily (development only)
- Security warnings and risks explained
In "Sécurité" section:
- Added to best practices checklist
- Reminder to verify debug mode is disabled
Key warnings included:
- Security: exposes sensitive information
- Performance: excessive logging slows down app
- Disk space: fills up disk quickly
- Compliance: may log personal data (GDPR)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed health check to measure the correct directory:
- Before: ./data (entire Docker volume including app code)
- After: ./data/data (actual Nextcloud user data)
Updated message from "Taille des données" to "Taille des données
utilisateurs" for clarity.
This provides more accurate metrics for monitoring actual user storage usage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed multiple issues in health check script:
1. Redis check failing due to missing .env loading
- Re-added .env sourcing at script start
- Redis container doesn't have REDIS_HOST_PASSWORD in env
- Script needs to load it from .env file
2. Script exiting early when du returns non-zero exit code
- du returns error code 1 when it can't read some subdirectories (permissions)
- Even though it outputs the size successfully
- Added || echo "" to handle non-zero exit codes gracefully
- Fixed for DATA_SIZE, DB_SIZE, and LOGS_SIZE checks
3. Fixed typo in DB_SIZE validation (was checking DATA_SIZE instead)
These fixes ensure:
- Complete health check output with summary section
- No premature script exits
- Proper Redis authentication testing
- Robust handling of permission errors in du commands
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed issue where "N/A" was being printed directly to stdout instead of
being captured in variables when du commands partially failed.
Changed from:
DATA_SIZE=$(du -sh ./data 2>/dev/null | cut -f1 || echo "N/A")
To:
DATA_SIZE=$(du -sh ./data 2>/dev/null | cut -f1)
if [ -z "$DATA_SIZE" ]; then
DATA_SIZE="N/A"
fi
This prevents spurious "N/A" lines appearing in the health check output.
Fixed for:
- DATA_SIZE (data directory size)
- DB_SIZE (database directory size)
- LOGS_SIZE (logs directory size)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The health check was failing when MySQL passwords contained special
characters like # because it was sourcing .env as a bash script,
where # is treated as a comment.
Solution: Remove unnecessary .env sourcing and use environment variables
directly from the db container, which Docker Compose has already correctly
parsed from .env.
This fixes the "Impossible de se connecter à MySQL" error when passwords
contain #, $, !, or other special characters.
Benefits:
- Works with any special characters in passwords
- Simpler code (removed 4 lines)
- More reliable (uses container's environment directly)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The MySQL connection test was failing because it didn't specify the
database name. MySQL requires a database to be selected when using
the -e flag with SELECT queries.
Changed:
mysql -u"$MYSQL_USER" -e 'SELECT 1'
To:
mysql -u"$MYSQL_USER" "$MYSQL_DATABASE" -e 'SELECT 1'
This fixes the "Impossible de se connecter à MySQL" error in production
even when MySQL is working correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement a dedicated Docker container (backup-cron) for automated daily
backups and maintenance tasks, eliminating the need for host cron configuration.
New features:
- backup-cron service: Alpine-based container with Docker CLI and cron
- Automated daily backup at 5:00 AM (Europe/Paris timezone)
- Automated health check at 6:00 AM (after backup)
- Weekly log cleanup on Sundays at 3:00 AM (removes logs >30 days)
Files added:
- cron/Dockerfile: Alpine Linux with docker-cli, bash, and tzdata
- cron/entrypoint.sh: Starts crond and displays configuration
- cron/crontab: Scheduled tasks configuration
- cron/README.md: Complete documentation for automated backups
- scripts/clean-old-logs.sh: Automated log cleanup script
Makefile enhancements:
- make cron-status: Display backup automation status and schedule
- make cron-logs: View logs from automated tasks
Configuration improvements:
- Auto-detect COMPOSE_PROJECT_NAME from directory name (portable)
- Fix df command to use POSIX format (-P flag) for consistent output
- Updated .env.example with COMPOSE_PROJECT_NAME documentation
Benefits:
- No host cron configuration required
- Portable across different environments
- Automatic timezone handling
- Integrated with existing backup/health check scripts
- Logs all automated tasks for monitoring
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed issue where log file redirections would fail when scripts change
directories. All scripts now use $PROJECT_ROOT/logs/... instead of
relative paths ./logs/...
This prevents errors like "Aucun fichier ou dossier de ce nom" when
scripts execute commands in different directories (e.g., checksum
verification in restore.sh).
Affected files:
- scripts/backup.sh
- scripts/restore.sh
- scripts/update.sh
- scripts/recover.sh
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Major improvements to the Makefile:
- Auto-detect Docker Compose v2 (docker compose) vs v1 (docker-compose)
- Add new utility commands:
* make logs-all: View logs from all containers
* make shell: Open bash in Nextcloud container
* make db-shell: Open MySQL shell
* make redis-shell: Open Redis CLI (with password support)
* make permissions: Fix file permissions
* make clean: Clean old logs (>30 days) and temp files
- Improve restore command:
* Now requires FILE= parameter for better UX
* Shows helpful error with list of available backups
* Example: make restore FILE=./backups/backup.tar.gz
- Better help organization:
* New "Monitoring" section
* Better documentation for all commands
* More detailed command descriptions
- Simplify health check:
* Use comprehensive check-health.sh script
* Remove duplicate check-health target
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The health check script was not using the REDIS_HOST_PASSWORD environment
variable when checking Redis connectivity, causing failures when Redis is
password-protected. Now properly detects and uses the password from .env
when available.
Also includes minor cleanup in backup.sh (formatting and redundant log removal).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Final optimizations based on real Nextcloud data characteristics:
Changes:
- Reduce DB estimate from 50MB to 10MB (mysqldump is tiny vs raw files)
- Adjust compression ratio from 90% to 30% (Nextcloud has pre-compressed files)
- Files are mostly images/PDFs already compressed, gzip gains are minimal
Results progression:
- Initial: 1.7GiB required → 55MB final (97% off)
- V2: 840MiB required → 55MB final (94% off)
- V3: 130MiB required → 55MB final (58% off)
- Final: 82MiB required → 55MB final (5% off) ✓
The estimation is now extremely accurate because it accounts for:
1. Excluded directories (preview, cache, thumbnails)
2. SQL dump vs raw MySQL files difference
3. Realistic compression ratio for already-compressed files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Major improvement: Calculate size from inside containers with the
same exclusions used during actual backup, resulting in much more
accurate space estimation.
Changes:
- Use docker-compose exec to calculate size from containers
- Apply same exclusions as tar backup (preview, cache, thumbnails)
- Calculate DB size from /var/lib/mysql directly
- Reduce default fallback from 2GB to 500MB (more realistic)
Results before/after:
- Before: 1.7GiB required → 55MB final (97% difference)
- After: 840MiB required → 55MB final (35% difference)
The estimation is now much closer to reality because we exclude
preview images, caches and thumbnails that aren't backed up.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add compressed size estimation and better error handling:
- Show both uncompressed (for safety) and estimated compressed size
- Handle calculation failure gracefully with clear message
- Estimate compression ratio at ~90% (divide by 10)
- Add conditional check to prevent arithmetic errors
Example output:
- Espace requis (non compressé + 20%): 1.7GiB
- Espace estimé après compression: 170MiB
- Archive finale: 55MiB (actual result)
This helps users understand why the required space seems larger
than the final backup size (compression factor).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Major fixes:
- Fix script structure: load .env before defining variables
- Remove duplicate color definitions (use common.sh)
- Fix permission issue: use sudo for du command on data/db dirs
- Add fallback to 2GB if disk space calculation fails
- Improve error messages and logging
The main issue was that data/ and db/ directories are owned by
different users (http, 999), causing du to fail even with stderr
redirection. Using sudo or || echo "0" fallback fixes this.
Tested: Backup now completes successfully with proper logging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The comparison was failing with "integer expression expected" error
because AVAILABLE_SPACE contained whitespace characters.
Changes:
- Add tr -d '[:space:]' to clean AVAILABLE_SPACE value
- Add validation for empty REQUIRED_SPACE (fallback to 1GB)
- Add validation for empty AVAILABLE_SPACE (exit with error)
- Add 2>/dev/null on comparison to prevent error messages
- Improve error handling for edge cases
Fixes: scripts/backup.sh: ligne 106 : [: 1712798932 0 : nombre entier attendu
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Update restore.sh to use common.sh instead of inline log function
- Update update.sh to use common.sh instead of inline log function
- Update recover.sh to use common.sh instead of inline log function
- Update check-health.sh to import colors from common.sh
Benefits:
- DRY principle: color definitions in one place
- Consistent logging across all scripts
- Easier maintenance: change log format once
- All scripts now have colored output in terminal
- Reduced code duplication (48 lines removed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create scripts/common.sh with reusable log() function and color definitions
- Refactor backup.sh to use common.sh for consistent logging
- Add color support: ERROR (red), WARN (yellow), SUCCESS (green), INFO (normal)
- Colors only appear in terminal, plain text in log files
- Improve code organization and DRY principle
- Fix shellcheck spacing warnings in backup.sh
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Security (CRITICAL):
- Add .env.example with strong password generation instructions
- Fix path traversal validation in restore.sh (now detects all .. patterns)
- Secure .env loading with set -a/set +a in all scripts
- Add logs/ to .gitignore to prevent credential leaks
Backup & Restore (IMPORTANT):
- Add file locking system to prevent concurrent backups
- Add disk space verification before backup operations
- Generate SHA256 checksums for all backups
- Verify checksums before restoration
- Create safety database backup before restore
- Implement comprehensive logging to ./logs/ directory
- Fix BACKUP_RETENTION_DAYS inconsistency
- Replace dangerous find -delete with safe iteration
Update & Recovery:
- Backup docker-compose.yml before updates with auto-rollback
- Add version display before/after updates
- Increase timeouts to 120s for slow containers
- Dynamic backup suggestion in recover.sh
Compatibility:
- Add Docker Compose v2 support with v1 fallback in all scripts
- Standardized log() function across all scripts
New Features:
- Add check-health.sh: comprehensive system health monitoring
- Add SECURITY.md: complete security documentation
- Update Makefile with check-health and recover commands
- Centralized logging with timestamps and levels
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace emoji-based prefixes with consistent [ERR], [WARN], and [*]
prefixes for better parsing and logging compatibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>