Compare commits

..

47 Commits

Author SHA1 Message Date
BeauTroll
fc1cac8e5a fix: properly configure Apache MPM Prefork with dedicated config file
- 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>
2026-01-03 04:14:41 +01:00
BeauTroll
5d610b9177 increase server limit 2026-01-03 04:07:31 +01:00
BeauTroll
8096d8985b Merge remote-tracking branch 'origin/main' 2026-01-03 04:03:16 +01:00
BeauTroll
8462b10e3b fix: increase Apache MaxRequestWorkers and optimize performance settings
- 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>
2026-01-03 04:00:12 +01:00
root
6bdd8e918c add traefik transport 2025-12-23 01:28:12 +01:00
root
44ec0a004a remove uncessary labels 2025-12-23 01:04:16 +01:00
root
c403419ea1 adapt for traefik labels 2025-12-23 00:23:18 +01:00
BeauTroll
a1b51599c6 feat: expose Apache logs to host for fail2ban integration
- 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>
2025-12-20 21:03:48 +01:00
BeauTroll
123f7b6a9c feat: add custom Docker image with ffmpeg for video previews
- Create Dockerfile extending nextcloud:latest with ffmpeg
- Add .dockerignore to optimize build context
- Update docker-compose.yml to use custom image build
- Modify update.sh to rebuild custom image on updates
- Document custom image setup in README
- Enable video preview generation for .mov, .mp4 files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 13:51:19 +01:00
BeauTroll
f02c9b36b2 chore: remove unused enable-modules.sh script
- 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>
2025-12-20 13:12:56 +01:00
BeauTroll
43517b36cc fix: increase Apache timeouts for large file uploads (>40MB)
- 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>
2025-12-20 13:03:19 +01:00
BeauTroll
57db8b6111 docs: add Apache/Traefik configuration and troubleshooting guides
Add comprehensive documentation for Apache configuration behind Traefik reverse proxy, including module activation, debug mode troubleshooting, and client sync error resolution.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 12:59:48 +01:00
BeauTroll
53cc23e153 chore: restore MultiViews and add all required Apache modules
- Restore MultiViews option in Directory configuration
- Add headers, rewrite, dir, and mime modules to enable script
- Keep remoteip and env modules for Traefik integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 12:51:36 +01:00
BeauTroll
a83426d198 feat: enhance Apache config for Traefik reverse proxy
- Add RemoteIP configuration to capture real client IPs
- Enable HTTPS detection via X-Forwarded-Proto header
- Add security headers (X-Frame-Options, CSP, etc.)
- Disable Apache WebDAV to prevent conflicts with Nextcloud
- Add module activation script for remoteip and env
- Optimize Directory options (FollowSymLinks without MultiViews)
- Add commented alternative PHP limits for reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 12:37:23 +01:00
BeauTroll
6fa7704c13 feat: add custom Apache configuration for Nextcloud
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>
2025-12-19 18:41:19 +01:00
BeauTroll
b802c8a5cd docs: add debug mode documentation to README
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>
2025-12-18 04:08:37 +01:00
BeauTroll
b3ae8a8622 fix: measure actual Nextcloud user data instead of entire volume
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>
2025-12-18 03:28:58 +01:00
BeauTroll
7dcffd2ae0 fix: resolve health check issues with Redis and du commands
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>
2025-12-18 03:24:50 +01:00
BeauTroll
08fdfc3a2e fix: prevent spurious N/A output in health check
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>
2025-12-18 03:12:37 +01:00
BeauTroll
51d42c6437 fix: handle passwords with special characters in health check
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>
2025-12-18 02:50:39 +01:00
BeauTroll
bd1e2dca27 fix: add database name to MySQL connection test in health check
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>
2025-12-18 02:42:09 +01:00
BeauTroll
e055d708a5 feat: add automated backup system with Docker-based cron
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>
2025-12-18 02:24:48 +01:00
BeauTroll
a7c14f9000 fix: use absolute paths for log files in all scripts
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>
2025-12-17 20:24:48 +01:00
BeauTroll
01c0db45f5 feat: enhance Makefile with Docker Compose v2 support and new utilities
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>
2025-12-17 20:19:23 +01:00
BeauTroll
b693ed1364 fix: add Redis password authentication support in health check
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>
2025-12-17 20:10:20 +01:00
BeauTroll
dd27bdebb5 Fine-tune disk space estimation for maximum accuracy
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>
2025-12-17 20:00:34 +01:00
BeauTroll
fcc60226ca Calculate accurate disk space by using same exclusions as backup
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>
2025-12-17 19:50:41 +01:00
BeauTroll
fb2a3585d4 Improve disk space estimation messages in backup
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>
2025-12-17 19:43:04 +01:00
BeauTroll
2ed5314537 Fix backup script - resolve permission issues and restructure
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>
2025-12-17 19:37:56 +01:00
BeauTroll
85ed35923c Fix disk space calculation in backup.sh
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>
2025-12-17 19:30:12 +01:00
BeauTroll
f3c74de015 Refactor all scripts to use common.sh for consistent colored logging
- 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>
2025-12-17 19:26:47 +01:00
BeauTroll
58bc9a47cc Add colored logging with shared common.sh library
- 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>
2025-12-17 19:24:19 +01:00
BeauTroll
c6de550329 Apply critical security fixes and major improvements to all scripts
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>
2025-12-17 18:27:00 +01:00
BeauTroll
701513ce15 Standardize error message prefixes in backup.sh
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>
2025-12-17 18:16:21 +01:00
BeauTroll
256d2632a1 fix escaping 2025-12-16 05:16:38 +01:00
BeauTroll
03821b5e18 fix quoted string 2025-12-16 05:15:04 +01:00
BeauTroll
b9c6122d4f add recover script 2025-12-16 05:09:47 +01:00
BeauTroll
f3655144a7 improve transparency and fix variable naming 2025-12-16 03:23:42 +01:00
BeauTroll
386f731c2b improve Makefile and secure bash scripts 2025-12-15 11:35:24 +01:00
BeauTroll
2dc57afab4 add backup to gitignore 2025-12-15 11:32:32 +01:00
BeauTroll
517e337a25 improve scripts security 2025-12-15 11:14:16 +01:00
BeauTroll
dc15b4665d fix env 2025-12-15 11:02:39 +01:00
BeauTroll
a7e6cf402d update readme 2025-12-15 11:00:58 +01:00
BeauTroll
db65cd7ec9 add dev/prod configuration 2025-12-15 03:47:03 +01:00
BeauTroll
764b78a12e fix indentation 2025-12-15 03:38:50 +01:00
BeauTroll
7c6a42587c add readme 2025-12-15 02:54:16 +01:00
BeauTroll
d0ce7d5185 remove redis host from env 2025-12-15 02:53:50 +01:00
23 changed files with 2526 additions and 167 deletions

17
.dockerignore Normal file
View File

@@ -0,0 +1,17 @@
# Données Nextcloud
data/
db/
backups/
logs/
# Docker
docker-compose*.yml
.env*
# Git
.git/
.gitignore
# Documentation
README.md
*.md

View File

@@ -1,11 +1,44 @@
MYSQL_DATABASE= # ============================================
MYSQL_ROOT_USER= # MODE: dev | prod
MYSQL_ROOT_PASSWORD= # ============================================
MYSQL_USER= # Copiez ce fichier vers .env et changez les valeurs
MYSQL_PASSWORD=
NEXTCLOUD_DOMAIN= # Base de données
# IMPORTANT: Utilisez des mots de passe forts (min 32 caractères aléatoires)
# Générez avec: openssl rand -base64 32
MYSQL_DATABASE=nextcloud
MYSQL_ROOT_USER=root
MYSQL_ROOT_PASSWORD=CHANGEME_GENERATE_STRONG_PASSWORD
MYSQL_USER=nextcloud_user
MYSQL_PASSWORD=CHANGEME_GENERATE_STRONG_PASSWORD
# Redis
# IMPORTANT: Utilisez un mot de passe fort
REDIS_HOST_PASSWORD=CHANGEME_GENERATE_STRONG_PASSWORD
# Backups
BACKUP_DESTINATION=./backups
BACKUP_RETENTION_DAYS=7
# Docker Compose
# Le nom du projet est auto-détecté depuis le nom du dossier
# Vous pouvez le surcharger ici si nécessaire:
# COMPOSE_PROJECT_NAME=mon-nextcloud
# ============================================
# DÉVELOPPEMENT (localhost)
# ============================================
NEXTCLOUD_DOMAIN=localhost:8888
TRUSTED_PROXIES= TRUSTED_PROXIES=
OVERWRITE_PROTOCOL=http
OVERWRITE_HOST=
OVERWRITE_CLI_URL=
REDIS_HOST= # ============================================
REDIS_HOST_PASSWORD= # PRODUCTION (avec Traefik et SSL)
# ============================================
#NEXTCLOUD_DOMAIN=domain.tld
#TRUSTED_PROXIES=172.16.0.0/12
#OVERWRITE_PROTOCOL=https
#OVERWRITE_HOST=domain.tld
#OVERWRITE_CLI_URL=https://domain.tld

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
.env .env
data/ data/
db/ db/
backups/
logs/

7
Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM nextcloud:latest
# Installer ffmpeg pour les previews vidéo
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*

159
Makefile
View File

@@ -1,46 +1,157 @@
.PHONY: help up down restart logs ps occ backup restore update health .PHONY: help up down restart logs logs-all ps shell db-shell redis-shell occ backup restore update health check-health recover clean permissions cron-logs cron-status
include .env
export
# Detect Docker Compose command
DOCKER_COMPOSE := $(shell command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1 && echo "docker compose" || echo "docker-compose")
help: help:
@echo "Nextcloud Docker - Commandes disponibles:" @echo "Nextcloud Docker - Commandes disponibles:"
@echo " make up - Démarrer les services" @echo ""
@echo " make down - Arrêter les services" @echo "Services:"
@echo " make restart - Redémarrer" @echo " make up - Démarrer tous les services Docker"
@echo " make logs - Voir les logs" @echo " make down - Arrêter et supprimer les containers"
@echo " make ps - Status des containers" @echo " make restart - Redémarrer tous les services"
@echo " make occ - Lancer une commande occ" @echo " make ps - Lister les containers actifs"
@echo " make backup - Backup complet" @echo " make logs - Afficher les logs Nextcloud en temps réel"
@echo " make restore - Restaurer un backup" @echo " make logs-all - Afficher les logs de tous les containers"
@echo " make update - Mettre à jour Nextcloud" @echo ""
@echo " make health - Vérifier la santé du système" @echo "Maintenance:"
@echo " make backup - Backup complet (DB + fichiers + config)"
@echo " → Active mode maintenance"
@echo " → Sauvegarde MariaDB, config, données, apps"
@echo " → Désactive mode maintenance"
@echo " → Archive dans ./backups/"
@echo ""
@echo " make update - Mise à jour Nextcloud (avec backup auto)"
@echo " → Backup de sécurité automatique"
@echo " → Pull nouvelle image Docker"
@echo " → Restart avec nouvelle version"
@echo " → Upgrade base de données"
@echo " → Optimisations post-update"
@echo ""
@echo " make restore FILE=<backup.tar.gz>"
@echo " - Restaurer depuis un backup"
@echo " → Arrêt des services"
@echo " → Restauration DB + fichiers"
@echo " → Redémarrage et réparation"
@echo ""
@echo " make recover - Récupération après erreur"
@echo " → Arrêt/nettoyage des containers"
@echo " → Redémarrage propre"
@echo " → Désactivation mode maintenance"
@echo ""
@echo "Monitoring:"
@echo " make health - Health check complet du système"
@echo " → Docker, containers, Nextcloud, DB, Redis"
@echo " → Espace disque, backups, logs"
@echo ""
@echo "Automatisation:"
@echo " make cron-status - Afficher le statut et le planning des backups auto"
@echo " make cron-logs - Afficher les logs des tâches cron"
@echo ""
@echo "Outils:"
@echo " make occ <cmd> - Exécuter une commande OCC Nextcloud"
@echo " make shell - Ouvrir un shell dans le container Nextcloud"
@echo " make db-shell - Ouvrir un shell MySQL/MariaDB"
@echo " make redis-shell - Ouvrir un shell Redis"
@echo " make permissions - Réparer les permissions des fichiers"
@echo " make clean - Nettoyer les logs et fichiers temporaires"
up: up:
docker-compose up -d $(DOCKER_COMPOSE) up -d
down: down:
docker-compose down $(DOCKER_COMPOSE) down
restart: restart:
docker-compose restart $(DOCKER_COMPOSE) restart
logs: logs:
docker-compose logs -f --tail=100 nextcloud $(DOCKER_COMPOSE) logs -f --tail=100 nextcloud
logs-all:
$(DOCKER_COMPOSE) logs -f --tail=50
ps: ps:
docker-compose ps $(DOCKER_COMPOSE) ps
shell:
$(DOCKER_COMPOSE) exec nextcloud /bin/bash
db-shell:
$(DOCKER_COMPOSE) exec db mysql -u"$$MYSQL_USER" -p"$$MYSQL_PASSWORD" "$$MYSQL_DATABASE"
redis-shell:
@if [ -n "$(REDIS_HOST_PASSWORD)" ]; then \
$(DOCKER_COMPOSE) exec redis redis-cli -a "$(REDIS_HOST_PASSWORD)"; \
else \
$(DOCKER_COMPOSE) exec redis redis-cli; \
fi
occ: occ:
@bash scripts/occ.sh $(filter-out $@,$(MAKECMDGOALS)) @bash scripts/occ.sh $(filter-out $@,$(MAKECMDGOALS))
backup: backup:
@bash scripts/backup.sh @bash scripts/backup.sh
restore: restore:
@bash scripts/restore.sh @if [ -z "$(FILE)" ]; then \
echo "❌ Erreur: Spécifiez le fichier de backup avec FILE=<fichier>"; \
echo "Exemple: make restore FILE=./backups/nextcloud_backup_20231217_123456.tar.gz"; \
echo ""; \
echo "Backups disponibles:"; \
find ./backups -name "nextcloud_backup_*.tar.gz" -type f -printf '%T+ %p\n' 2>/dev/null | sort -r | head -5; \
exit 1; \
fi
@bash scripts/restore.sh "$(FILE)"
update: update:
@bash scripts/update.sh @bash scripts/update.sh
health: health:
@docker-compose exec nextcloud php occ status @bash scripts/check-health.sh
@docker-compose exec nextcloud php occ config:list system
@docker-compose exec db mysql -u$$MYSQL_USER -p$$MYSQL_PASSWORD -e "SELECT 1" recover:
@bash scripts/recover.sh
permissions:
@echo "Réparation des permissions..."
$(DOCKER_COMPOSE) exec -u root nextcloud chown -R www-data:www-data /var/www/html/data /var/www/html/config /var/www/html/custom_apps
@echo "✅ Permissions réparées"
clean:
@echo "Nettoyage des logs et fichiers temporaires..."
@find ./logs -type f -mtime +30 -delete 2>/dev/null && echo "✅ Logs > 30 jours supprimés" || true
@rm -f /tmp/nextcloud_*.lock 2>/dev/null && echo "✅ Fichiers lock supprimés" || true
@$(DOCKER_COMPOSE) exec -T nextcloud php occ files:cleanup 2>/dev/null && echo "✅ Fichiers orphelins nettoyés" || true
@echo "✅ Nettoyage terminé"
cron-status:
@echo "=== Statut du service de backup automatique ==="
@echo ""
@echo "Container backup-cron:"
@$(DOCKER_COMPOSE) ps backup-cron
@echo ""
@echo "Planning des tâches:"
@$(DOCKER_COMPOSE) exec -T backup-cron cat /etc/crontabs/root 2>/dev/null | grep -v "^#" | grep -v "^$$" || echo "⚠ Container non démarré"
@echo ""
@echo "Heure du container:"
@$(DOCKER_COMPOSE) exec -T backup-cron date 2>/dev/null || echo "⚠ Container non démarré"
cron-logs:
@echo "=== Logs des tâches automatiques ==="
@echo ""
@echo "Logs de backup (10 dernières lignes):"
@tail -n 10 ./logs/cron_backup.log 2>/dev/null || echo "Aucun log de backup"
@echo ""
@echo "Logs de health check (10 dernières lignes):"
@tail -n 10 ./logs/cron_health.log 2>/dev/null || echo "Aucun log de health check"
@echo ""
@echo "Logs de nettoyage (10 dernières lignes):"
@tail -n 10 ./logs/cron_clean.log 2>/dev/null || echo "Aucun log de nettoyage"
# Catch-all target pour permettre les arguments aux commandes occ et restore
%:
@:

665
README.md Normal file
View File

@@ -0,0 +1,665 @@
# Nextcloud Docker Deployment
Déploiement Nextcloud avec Docker Compose comprenant MariaDB 10.11, Redis (cache), service cron intégré et support Traefik pour le reverse proxy.
## Table des matières
- [Architecture](#architecture)
- [Prérequis](#prérequis)
- [Installation](#installation)
- [Configuration](#configuration)
- [Démarrage](#démarrage)
- [Maintenance](#-maintenance)
- [Résolution de problèmes](#-résolution-de-problèmes)
- [Monitoring](#-monitoring)
- [Sécurité](#-sécurité)
## Architecture
Le déploiement comprend 5 services:
- **nextcloud**: Application Nextcloud avec image personnalisée (inclut ffmpeg) - port 127.0.0.1:8888:80
- **db**: MariaDB 10.11 avec healthcheck
- **redis**: Cache Redis avec politique LRU (512MB max)
- **cron**: Tâches planifiées Nextcloud (préviews, nettoyage, etc.)
- **backup-cron**: Système de backup automatisé (quotidien)
**Réseaux**:
- `nextcloud-net`: Réseau interne pour la communication entre services
- `traefik-net`: Réseau externe pour Traefik (reverse proxy)
## Prérequis
- Docker >= 20.10
- Docker Compose >= 2.0
- Traefik configuré avec réseau `traefik-net` (pour exposition HTTPS)
- Nom de domaine configuré avec certificat SSL
- Minimum 2GB RAM recommandé
- Minimum 10GB d'espace disque
## Installation
1. **Cloner le dépôt**
```bash
git clone <repository-url>
cd agence66-nextcloud-docker
```
2. **Configurer l'environnement**
```bash
cp .env.example .env
nano .env
```
3. **Générer des mots de passe sécurisés**
```bash
# Génération pour chaque secret requis
openssl rand -base64 32
```
Variables importantes à configurer dans `.env`:
- `MYSQL_DATABASE`: Nom de la base de données (défaut: nextcloud)
- `MYSQL_USER`: Utilisateur de la base de données
- `MYSQL_PASSWORD`: Mot de passe de la base de données
- `MYSQL_ROOT_PASSWORD`: Mot de passe root MariaDB
- `REDIS_HOST_PASSWORD`: Mot de passe Redis
- `NEXTCLOUD_DOMAIN`: Votre nom de domaine
- `OVERWRITE_PROTOCOL`: Protocole (http/https)
- `OVERWRITE_HOST`: Hôte public (optionnel)
## Configuration
### Variables d'environnement
Créez votre fichier `.env` basé sur `.env.example`:
| Variable | Description | Exemple |
| ---------------------- | --------------------------- | ------------------- |
| `MYSQL_DATABASE` | Nom de la base de données | `nextcloud` |
| `MYSQL_USER` | Utilisateur base de données | `nextcloud` |
| `MYSQL_PASSWORD` | Mot de passe utilisateur DB | `********` |
| `MYSQL_ROOT_PASSWORD` | Mot de passe root MariaDB | `********` |
| `REDIS_HOST_PASSWORD` | Mot de passe Redis | `********` |
| `NEXTCLOUD_DOMAIN` | Domaine de confiance | `cloud.example.com` |
| `OVERWRITE_PROTOCOL` | Protocole (http/https) | `https` |
| `OVERWRITE_HOST` | Hôte public | `cloud.example.com` |
| `TRUSTED_PROXIES` | Proxies de confiance | `172.18.0.0/16` |
| `OVERWRITE_CLI_URL` | URL pour CLI (optionnel) | `https://...` |
### Volumes
Les données persistantes sont stockées dans:
- `./data`: Fichiers Nextcloud et données utilisateurs
- `./db`: Base de données MariaDB
- `./db-config`: Configuration MariaDB personnalisée
### Configuration PHP
Les paramètres PHP sont préconfigurés dans docker-compose.yml:
| Paramètre | Valeur | Description |
| ------------------------- | ------ | ------------------------------- |
| `PHP_MEMORY_LIMIT` | 4096M | Mémoire allouée à PHP |
| `PHP_UPLOAD_MAX_FILESIZE` | 2G | Taille max d'upload |
| `PHP_POST_MAX_SIZE` | 2G | Taille max POST |
| `PHP_MAX_EXECUTION_TIME` | 1800s | Timeout d'exécution (30min) |
| `PHP_MAX_INPUT_TIME` | 1800s | Timeout lecture données (30min) |
| `APACHE_BODY_LIMIT` | 2GB | Limite Apache pour le body |
Ces valeurs permettent l'upload de fichiers jusqu'à 2GB.
### Image Docker personnalisée
Le projet utilise une image Docker personnalisée basée sur `nextcloud:latest` qui inclut **ffmpeg** pour la génération de previews vidéo (.mov, .mp4, etc.).
**Dockerfile:**
```dockerfile
FROM nextcloud:latest
# Installer ffmpeg pour les previews vidéo
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
```
**Builder l'image:**
```bash
# Builder l'image custom
docker compose build nextcloud
# Ou forcer le rebuild
docker compose build --no-cache nextcloud
```
**Vérifier ffmpeg:**
```bash
docker compose exec nextcloud ffmpeg -version
```
**Activer les previews vidéo:**
Après le premier démarrage, activez les providers de preview pour les vidéos:
```bash
docker compose exec -u www-data nextcloud php occ config:system:set enabledPreviewProviders 0 --value="OC\\Preview\\Movie"
docker compose exec -u www-data nextcloud php occ config:system:set enabledPreviewProviders 1 --value="OC\\Preview\\PNG"
docker compose exec -u www-data nextcloud php occ config:system:set enabledPreviewProviders 2 --value="OC\\Preview\\JPEG"
docker compose exec -u www-data nextcloud php occ config:system:set enabledPreviewProviders 3 --value="OC\\Preview\\GIF"
docker compose exec -u www-data nextcloud php occ config:system:set enabledPreviewProviders 4 --value="OC\\Preview\\BMP"
# Générer les previews pour un utilisateur
docker compose exec -u www-data nextcloud php occ preview:generate-all nom_utilisateur
```
**Note:** L'image est buildée localement et taguée `nextcloud-custom:latest`. Lors des mises à jour Nextcloud, pensez à rebuild l'image.
# Server Transport Traefik
Ajouter à traefik.yml :
```yml
serversTransport:
nextcloud-transport:
forwardingTimeouts:
dialTimeout: 30s
responseHeaderTimeout: 0s
idleConnTimeout: 3600s
```
OU au docker-compose.yml
```yml
command:
- "--serverstransport.forwardingtimeouts.dialtimeout=30s"
- "--serverstransport.forwardingtimeouts.responseheadertimeout=0"
- "--serverstransport.forwardingtimeouts.idleconntimeout=3600s"
```
### Configuration Apache pour Traefik
Le fichier `apache/nextcloud.conf` configure Apache pour fonctionner correctement derrière le reverse proxy Traefik.
**Configuration incluse:**
- **RemoteIP**: Récupération de l'IP réelle du client (pas celle de Traefik)
- **X-Forwarded-Proto**: Détection automatique HTTPS depuis Traefik
- **Headers de sécurité**: X-Frame-Options, X-Content-Type-Options, etc.
- **WebDAV désactivé**: Évite les conflits (Nextcloud gère son propre WebDAV)
**Activation des modules Apache:**
Lors du premier déploiement, activez les modules nécessaires:
```bash
# Activer tous les modules en une commande
docker compose exec nextcloud bash -c "a2enmod headers rewrite dir mime remoteip env && apache2ctl graceful"
# Redémarrer Nextcloud pour appliquer les changements
docker compose restart nextcloud
```
**Modules activés:**
| Module | Utilité |
| ---------- | ---------------------------------------------------- |
| `headers` | Gestion des headers HTTP (sécurité) |
| `rewrite` | URL rewriting (requis pour .htaccess) |
| `dir` | DirectoryIndex (index.php, etc.) |
| `mime` | Types MIME (CSS, JS, etc.) |
| `remoteip` | Récupération IP client via X-Forwarded-For |
| `env` | Variables d'environnement (détection HTTPS) |
**Note**: Les modules `headers`, `rewrite`, `dir`, et `mime` sont normalement activés par défaut dans l'image `nextcloud:latest`. Seuls `remoteip` et `env` doivent être activés manuellement.
**Vérification:**
```bash
# Vérifier qu'Apache utilise bien la configuration
docker compose exec nextcloud apache2ctl -M | grep -E "(headers|rewrite|remoteip|env)"
# Vérifier les logs avec IP réelle
docker compose logs nextcloud --tail=20
```
## Démarrage
### Première installation
```bash
# Builder l'image personnalisée (inclut ffmpeg)
docker compose build nextcloud
# Démarrer tous les services
make up
# Vérifier que tous les containers sont actifs
make ps
# Vérifier l'état de Nextcloud
make health
```
**Accès à l'instance**:
- **Via Traefik** (production): `https://votre-domaine.com` (recommandé)
- **Accès direct** (développement): `http://localhost:8888`
**Note**: En production, Traefik doit être configuré pour exposer Nextcloud via HTTPS. Le port 8888 n'écoute que sur 127.0.0.1 pour des raisons de sécurité.
### Arrêter les services
```bash
make down
```
### Redémarrer les services
```bash
make restart
```
## 🛠️ Maintenance
### Backup pré-mise à jour
Créer une sauvegarde de sécurité avant une mise à jour:
```bash
make backup
```
**Actions effectuées par le script:**
1. ⏸️ Active le mode maintenance Nextcloud
2. 💾 Sauvegarde la base de données MariaDB (mysqldump avec transactions)
3. ⚙️ Sauvegarde la configuration (`/var/www/html/config`)
4. 📁 Sauvegarde les données utilisateurs (avec exclusions: previews, cache, thumbnails)
5. 📦 Sauvegarde les apps personnalisées (`custom_apps`)
6. ▶️ Désactive le mode maintenance
7. 🗜️ Compresse le tout en `.tar.gz` dans `./backups/`
8. 🧹 Nettoie les backups de plus de 7 jours
**Sécurité:**
- Tous les tar s'exécutent dans le container en tant que `www-data`
- Mots de passe sécurisés via `MYSQL_PWD` (pas visible dans `ps`)
- Cleanup automatique en cas d'erreur avec trap handler
**Note**: Un service cron intégré est déjà configuré dans docker-compose.yml pour les tâches planifiées Nextcloud (préviews, nettoyage, etc.)
### Restauration
```bash
# Lister les backups disponibles
ls -lh backups/
# Restaurer depuis une sauvegarde
make restore backups/nextcloud_backup_YYYYMMDD_HHMMSS.tar.gz
```
**Actions effectuées par le script:**
1. ⚠️ Demande confirmation (opération destructive!)
2. 📂 Extrait l'archive dans un répertoire temporaire
3. ✅ Valide le contenu de l'archive (type MIME, fichiers requis)
4. ⏹️ Arrête tous les services Docker
5. 💾 Restaure la base de données MariaDB
- Démarre uniquement le container DB
- Attend que MariaDB soit prêt (health check)
- Importe le dump SQL
6. ▶️ Démarre tous les services
7. 📁 Restaure les fichiers (config, données, apps) via le container
8. 🔧 Exécute `maintenance:repair` pour corriger les éventuels problèmes
9. ▶️ Désactive le mode maintenance
10. 🔍 Scanne tous les fichiers avec `files:scan --all`
11. 🧹 Nettoie le répertoire temporaire
**Sécurité:**
- Validation du chemin (protection path traversal)
- Vérification du type de fichier (gzip)
- Restauration via container en tant que `www-data`
- Cleanup garanti avec trap handler
### Mise à jour
Mettre à jour Nextcloud vers la dernière version:
```bash
make update
```
**Le script effectue automatiquement un backup avant la mise à jour!**
**Actions effectuées par le script:**
1. 💾 **Backup automatique de sécurité**
- Exécute `scripts/backup.sh` complet
- Archive créée dans `./backups/`
2. 🔨 Rebuild l'image personnalisée avec la nouvelle version Nextcloud
3. ⏸️ Active le mode maintenance
4. 🔄 Redémarre les containers avec `--force-recreate`
5. ⏳ Attend que Nextcloud soit prêt (health check jusqu'à 60s)
6. ▶️ Désactive temporairement le mode maintenance
7. ⬆️ Exécute `occ upgrade` (migrations base de données)
8. 🔍 Scanne tous les fichiers (`files:scan --all`)
9. 📊 Ajoute les indices manquants (`db:add-missing-indices`)
10. 🔧 Convertit les colonnes en bigint (`db:convert-filecache-bigint`)
11. ▶️ Désactive le mode maintenance
12. ✅ Affiche le statut final
**Vérification post-update:**
```bash
# Vérifier la version et l'état
make occ status
# Vérifier la santé globale
make health
```
**En cas de problème:**
Si la mise à jour échoue, restaurez le backup automatique créé à l'étape 1:
```bash
# Lister les backups (le plus récent est celui de l'update)
ls -lht backups/ | head
# Restaurer
make restore backups/nextcloud_backup_YYYYMMDD_HHMMSS.tar.gz
```
**Sécurité:**
- Backup automatique avant toute modification
- Trap handler pour cleanup en cas d'erreur
- Mode maintenance automatiquement désactivé même en cas d'échec
- Instructions de rollback affichées en cas d'erreur
### Commandes OCC
OCC (occ = ownCloud Console) est l'interface en ligne de commande de Nextcloud:
```bash
# Vérifier le status de l'instance
make occ status
# Lister les utilisateurs
make occ user:list
# Scanner tous les fichiers
make occ files:scan --all
# Lister les applications installées
make occ app:list
# Activer/désactiver le mode maintenance
make occ maintenance:mode --on
make occ maintenance:mode --off
```
## 🔧 Résolution de problèmes
### Erreur 423 WebDAV Locked
Si vous rencontrez des erreurs de fichiers verrouillés:
```bash
make occ files:cleanup
```
### Performance lente
Optimisations recommandées:
```bash
# Ajouter les indices manquants en base de données
make occ db:add-missing-indices
# Convertir les colonnes en big int si nécessaire
make occ db:convert-filecache-bigint
# Nettoyer les fichiers supprimés
make occ files:cleanup
# Optimiser la génération des previews
make occ config:app:set previewgenerator squareSizes --value="256 512"
make occ config:app:set previewgenerator widthSizes --value="256 512 1024"
make occ config:app:set previewgenerator heightSizes --value="256 512 1024"
# Générer les previews
make occ preview:generate-all
```
### Problèmes de permissions
```bash
# Réparer les permissions des fichiers
docker compose exec -u www-data nextcloud chown -R www-data:www-data /var/www/html/data
```
### Espace disque insuffisant
```bash
# Nettoyer les anciennes versions de fichiers
make occ versions:cleanup
# Nettoyer la corbeille
make occ trashbin:cleanup --all-users
# Vérifier l'utilisation de l'espace
du -sh ./data # Données Nextcloud
du -sh ./db # Base de données MariaDB
```
### Mode débogage
⚠️ **IMPORTANT**: Le mode débogage ne doit **JAMAIS** être activé en production!
**Vérifier l'état du mode débogage:**
```bash
make occ config:system:get debug
```
**Désactiver le mode débogage (PRODUCTION):**
```bash
# Via OCC (recommandé)
make occ config:system:set debug --value=false --type=boolean
# OU éditer manuellement config.php
docker-compose exec nextcloud nano /var/www/html/config/config.php
# Chercher 'debug' => true, et changer en false ou supprimer la ligne
```
**Activer temporairement pour diagnostiquer un problème (DÉVELOPPEMENT UNIQUEMENT):**
```bash
# Activer
make occ config:system:set debug --value=true --type=boolean
# IMPORTANT: Désactiver immédiatement après le diagnostic!
make occ config:system:set debug --value=false --type=boolean
```
**Pourquoi c'est dangereux en production:**
- 🚨 **Sécurité**: Expose des informations sensibles (chemins, configuration, requêtes SQL)
- 🐌 **Performance**: Génère énormément de logs et ralentit l'application
- 💾 **Espace disque**: Remplit rapidement le disque avec des logs détaillés
- 📊 **Conformité**: Peut logger des données personnelles (RGPD)
### Messages de debug dans la console navigateur
Si vous voyez des messages `[DEBUG]` dans la console JavaScript du navigateur (F12), même avec `debug => false`:
**1. Vider tous les caches:**
```bash
# Cache Nextcloud
make occ maintenance:repair --include-expensive
# Cache Redis
docker compose exec redis redis-cli -a VOTRE_PASSWORD_REDIS FLUSHALL
```
**2. Vérifier le niveau de log:**
```bash
# Niveau recommandé pour production: 2 (Warning)
make occ config:system:set loglevel --value=2 --type=integer
```
**Niveaux de log disponibles:**
- 0 = Debug (tous les messages)
- 1 = Info
- 2 = Warning (recommandé production)
- 3 = Error
- 4 = Fatal
**3. Hard refresh dans le navigateur:**
```bash
# Firefox/Chrome: Ctrl + Shift + R
# Ou vider le cache du navigateur pour le domaine Nextcloud
```
**4. Redémarrer les services:**
```bash
docker compose restart nextcloud redis
```
### Problèmes de synchronisation client
Si le client de synchronisation Nextcloud affiche "error transfering, server replied not found":
**1. Scanner les fichiers pour mettre à jour l'index:**
```bash
# Scanner tous les fichiers d'un utilisateur
make occ files:scan nom_utilisateur
# Scanner uniquement un dossier spécifique
make occ files:scan --path="/nom_utilisateur/files/Dossier"
```
**2. Nettoyer les verrous de fichiers:**
```bash
make occ files:cleanup
```
**3. Vérifier les logs pour identifier le fichier problématique:**
```bash
# Logs en temps réel
docker compose logs -f nextcloud --tail=50
# Rechercher les erreurs 404
docker compose logs nextcloud | grep "404"
```
**4. En dernier recours, réinitialiser la synchronisation:**
- Dans le client Nextcloud: supprimer le compte et le re-configurer
- Cela forcera une synchronisation complète
## 📊 Monitoring
### Vérifications de santé
```bash
# Status général
make health
# Vérifier les containers actifs
make ps
# Voir les logs en temps réel
make logs
# Logs d'un service spécifique
docker compose logs -f nextcloud
docker compose logs -f db
docker compose logs -f redis
```
### Métriques de performance
```bash
# Statistiques système
make occ status
# Informations sur la base de données MariaDB
docker compose exec db mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} -e "SELECT table_schema AS 'Database', ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)' FROM information_schema.TABLES WHERE table_schema = 'nextcloud';"
# Utilisation Redis
docker compose exec redis redis-cli -a ${REDIS_HOST_PASSWORD} INFO stats
```
## 🔒 Sécurité
### Bonnes pratiques
1. **Mots de passe forts**: Utilisez `openssl rand -base64 32` pour tous les secrets
2. **HTTPS obligatoire**: Configurez SSL/TLS avec Let's Encrypt ou certificats valides
3. **Mises à jour régulières**: Exécutez `make backup` puis `make update` mensuellement
4. **Sauvegardes**: Utilisez `make backup` avant toute mise à jour (backup serveur quotidien géré au niveau système)
5. **Monitoring**: Vérifiez les logs régulièrement pour détecter les activités suspectes
6. **Mode débogage désactivé**: Vérifiez avec `make occ config:system:get debug` (doit être `false` ou absent)
### Sécuriser l'accès
```bash
# Activer l'authentification à deux facteurs
make occ app:enable twofactor_totp
# Forcer HTTPS
make occ config:system:set overwriteprotocol --value="https"
# Limiter les tentatives de connexion
make occ app:enable bruteforcesettings
```
## Commandes Make disponibles
| Commande | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------ |
| `make up` | Démarrer tous les services Docker (nextcloud, db, redis, cron) |
| `make down` | Arrêter et supprimer tous les containers |
| `make restart` | Redémarrer tous les services |
| `make ps` | Lister les containers actifs avec leur état |
| `make logs` | Afficher les logs Nextcloud en temps réel (tail -100) |
| `make health` | Vérifier l'état: statut Nextcloud + config système + connexion MariaDB |
| `make backup` | Backup complet: DB + config + données + apps (avec mode maintenance) |
| `make restore <file>` | Restaurer depuis un backup (destructif - demande confirmation) |
| `make update` | Mise à jour complète: backup auto + pull + upgrade + optimisations |
| `make occ <commande>` | Exécuter une commande OCC Nextcloud (ex: `make occ user:list`) |
**Exemples d'utilisation:**
```bash
# Backup et update
make backup
make update
# Restaurer un backup spécifique
make restore backups/nextcloud_backup_20251215_112450.tar.gz
# Commandes OCC
make occ status
make occ user:list
make occ files:scan --all
```
## Support
Pour toute question ou problème:
1. Consultez la [documentation officielle Nextcloud](https://docs.nextcloud.com/)
2. Vérifiez les logs: `make logs`
3. Consultez les issues du projet

227
SECURITY.md Normal file
View File

@@ -0,0 +1,227 @@
# Sécurité et Best Practices
Ce document décrit les mesures de sécurité et les best practices implémentées dans ce projet Nextcloud.
## ✅ Corrections de Sécurité Appliquées
### 🔒 Gestion des Secrets
#### Fichier .env
-`.env` ajouté au `.gitignore` pour éviter de commiter les secrets
-`.env.example` créé avec des instructions claires
- ✅ Instructions pour générer des mots de passe forts (min 32 caractères)
- ⚠️ **IMPORTANT**: Changez tous les mots de passe par défaut avec:
```bash
openssl rand -base64 32
```
#### Gestion des Mots de Passe
- ✅ `MYSQL_PWD` utilisé pour éviter l'exposition des mots de passe dans les commandes
- ✅ Pas de mots de passe en clair dans les logs
- ✅ Variables d'environnement chargées de manière sécurisée avec `set -a`
### 🛡️ Protection des Scripts
#### Validation des Entrées
- ✅ **backup.sh**: Variables requises validées avec `${VAR:?message}`
- ✅ **restore.sh**: Protection contre path traversal améliorée
- ✅ **restore.sh**: Validation du type de fichier (gzip)
- ✅ **restore.sh**: Utilisation de `realpath` pour résoudre les chemins
#### Sécurité des Opérations
- ✅ `set -euo pipefail` dans tous les scripts
- ✅ Protection `${VAR:?}` pour éviter les suppressions accidentelles
- ✅ Système de lock pour empêcher les backups simultanés
- ✅ Fonctions de cleanup avec `trap` pour gérer les erreurs
### 📊 Logging et Audit
#### Traçabilité
- ✅ Logs centralisés dans `./logs/` avec timestamps
- ✅ Fonction `log()` standardisée dans tous les scripts
- ✅ Tous les scripts créent des logs horodatés
- ✅ Codes de sortie et erreurs loggés
#### Monitoring
- ✅ Script `check-health.sh` pour vérifier l'état du système
- ✅ Vérification de l'espace disque avant backup
- ✅ Vérification de l'âge des backups
### 🔐 Intégrité des Données
#### Checksums
- ✅ Génération automatique de checksums SHA256 pour les backups
- ✅ Vérification des checksums avant restauration
- ✅ Détection de fichiers corrompus
#### Backups de Sécurité
- ✅ Backup automatique de la DB avant restauration
- ✅ Backup du `docker-compose.yml` avant mise à jour
- ✅ Option de créer un backup avant restauration
### 🚀 Docker Compose
#### Compatibilité
- ✅ Support de Docker Compose v2 (`docker compose`)
- ✅ Fallback vers Docker Compose v1 (`docker-compose`)
- ✅ Détection automatique de la version disponible
## 📋 Checklist de Sécurité
### Configuration Initiale
- [ ] Copier `.env.example` vers `.env`
- [ ] Générer des mots de passe forts avec `openssl rand -base64 32`
- [ ] Modifier tous les mots de passe dans `.env`:
- `MYSQL_ROOT_PASSWORD`
- `MYSQL_PASSWORD`
- `REDIS_HOST_PASSWORD`
- [ ] Vérifier que `.env` n'est PAS dans git: `git status`
- [ ] Configurer les paramètres de production (domaine, SSL, etc.)
### Maintenance Régulière
- [ ] Exécuter `make check-health` régulièrement
- [ ] Vérifier les logs dans `./logs/`
- [ ] S'assurer que les backups sont créés (< 24h)
- [ ] Vérifier l'espace disque disponible
- [ ] Tester les restaurations périodiquement
### Avant une Mise en Production
- [ ] Tous les mots de passe sont forts et uniques
- [ ] SSL/TLS configuré (via Traefik ou autre)
- [ ] Domaine configuré dans `TRUSTED_DOMAINS`
- [ ] Backups automatiques configurés (cron)
- [ ] Logs configurés et monitorés
- [ ] Health checks configurés
## 🔧 Scripts et Outils
### Scripts de Maintenance
| Script | Description | Sécurité |
|--------|-------------|----------|
| `backup.sh` | Backup complet | Lock, checksum, vérif espace disque |
| `restore.sh` | Restauration | Vérif checksum, backup sécurité DB |
| `update.sh` | Mise à jour | Backup auto, rollback docker-compose |
| `recover.sh` | Récupération d'erreur | Logs, suggestions dynamiques |
| `occ.sh` | Wrapper OCC | Support Docker Compose v2 |
| `check-health.sh` | Health check complet | Vérifications système complètes |
### Commandes Make
```bash
make backup # Créer un backup complet
make restore <file> # Restaurer un backup
make update # Mettre à jour Nextcloud
make check-health # Vérifier l'état du système
make recover # Récupérer après une erreur
```
## 🚨 Gestion des Incidents
### En cas d'erreur
1. **Consulter les logs**:
```bash
ls -lth ./logs/
tail -f ./logs/backup_*.log
```
2. **Vérifier l'état du système**:
```bash
make check-health
```
3. **Tenter une récupération**:
```bash
make recover
```
4. **Si nécessaire, restaurer un backup**:
```bash
make restore backups/nextcloud_backup_YYYYMMDD_HHMMSS.tar.gz
```
### Récupération après Compromission
Si vous soupçonnez une compromission:
1. **Arrêter les services immédiatement**:
```bash
make down
```
2. **Analyser les logs**:
```bash
docker-compose logs > incident_logs.txt
cat ./logs/*.log > app_logs.txt
```
3. **Restaurer depuis un backup propre**:
```bash
make restore <backup_avant_incident>
```
4. **Changer TOUS les mots de passe**
5. **Vérifier les utilisateurs et permissions**
6. **Mettre à jour vers la dernière version**
## 📚 Références
### Best Practices
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Docker Security Best Practices](https://docs.docker.com/engine/security/)
- [Nextcloud Security Hardening](https://docs.nextcloud.com/server/latest/admin_manual/installation/harden_server.html)
### Commandes Utiles
```bash
# Générer un mot de passe fort
openssl rand -base64 32
# Vérifier les permissions
ls -la .env
# Devrait être: -rw------- (600)
# Vérifier qu'aucun secret n'est dans git
git grep -i password
git grep -i secret
# Audit de sécurité basique
make check-health
```
## 📝 Notes de Version
### Version actuelle
**Améliorations de sécurité**:
- ✅ Protection des secrets (.env hors git)
- ✅ Validation des entrées utilisateur
- ✅ Checksums pour intégrité des backups
- ✅ Logging complet pour audit
- ✅ Protection contre path traversal
- ✅ Vérifications d'espace disque
- ✅ Backups de sécurité automatiques
- ✅ Support Docker Compose v2
**Bugs corrigés**:
- ✅ Incohérence BACKUP_RETENTION_DAYS
- ✅ Protection find -delete dangereuse
- ✅ Path traversal incomplet
- ✅ Pas de vérification checksums
- ✅ Pas de backup avant restore
**Fonctionnalités ajoutées**:
- ✅ Script de health check complet
- ✅ Système de lock pour backups
- ✅ Génération automatique de checksums
- ✅ Logs centralisés avec timestamps
- ✅ Backup dynamique suggéré dans recover
---
**Date de dernière mise à jour**: 2025-12-17

16
apache/mpm_prefork.conf Normal file
View File

@@ -0,0 +1,16 @@
# prefork MPM
# StartServers: number of server processes to start
# MinSpareServers: minimum number of server processes which are kept spare
# MaxSpareServers: maximum number of server processes which are kept spare
# ServerLimit: maximum value for MaxRequestWorkers (must be set before MaxRequestWorkers)
# MaxRequestWorkers: maximum number of server processes allowed to start
# MaxConnectionsPerChild: maximum number of requests a server process serves
<IfModule mpm_prefork_module>
ServerLimit 400
StartServers 10
MinSpareServers 10
MaxSpareServers 20
MaxRequestWorkers 400
MaxConnectionsPerChild 1000
</IfModule>

48
apache/nextcloud.conf Normal file
View File

@@ -0,0 +1,48 @@
# Configuration pour reverse proxy Traefik
# Récupération de l'IP réelle du client via X-Forwarded-For
ServerName cloud.agence66.fr
# Autoriser les caractères spéciaux encodés dans les noms de fichiers
AllowEncodedSlashes NoDecode
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 172.16.0.0/12
RemoteIPTrustedProxy 10.0.0.0/8
RemoteIPTrustedProxy 192.168.0.0/16
# Activer la confiance des en-têtes X-Forwarded-Proto
SetEnvIf X-Forwarded-Proto "https" HTTPS=on
# Timeouts pour gros fichiers (>40MB)
Timeout 3600
KeepAlive On
KeepAliveTimeout 300
MaxKeepAliveRequests 200
<Directory /var/www/html/>
Options FollowSymLinks MultiViews
AllowOverride All
Require all granted
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
# Headers de sécurité (si non gérés par Traefik)
<IfModule mod_headers.c>
# HSTS sera géré par Traefik
# Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
# Autres headers de sécurité
Header always set Referrer-Policy "no-referrer-when-downgrade"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Robots-Tag "noindex, nofollow"
</IfModule>
# Logs avec IP réelle (pas l'IP de Traefik)
<IfModule mod_remoteip.c>
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
</IfModule>

24
cron/Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
FROM alpine:latest
# Installer les dépendances nécessaires
RUN apk add --no-cache \
docker-cli \
docker-cli-compose \
bash \
tzdata
# Configurer le fuseau horaire
ENV TZ=Europe/Paris
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Copier le fichier crontab
COPY crontab /etc/crontabs/root
# Copier le script d'entrée
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Créer le répertoire pour les logs
RUN mkdir -p /logs
ENTRYPOINT ["/entrypoint.sh"]

147
cron/README.md Normal file
View File

@@ -0,0 +1,147 @@
# Backup Automatique Nextcloud
Ce dossier contient la configuration pour les backups automatiques via un container Docker dédié.
## Architecture
Le service `backup-cron` est un container Alpine Linux léger qui exécute des tâches planifiées:
- **Image**: Alpine Linux avec Docker CLI et docker-compose
- **Fuseau horaire**: Europe/Paris (configurable via `TZ`)
- **Montages**:
- `/project`: Projet complet (scripts, config, etc.)
- `/var/run/docker.sock`: Socket Docker pour exécuter docker-compose
- `/logs`: Répertoire des logs partagé avec l'hôte
## Planning par défaut
| Tâche | Fréquence | Heure | Description |
|-------|-----------|-------|-------------|
| Backup | Quotidien | 5h00 | Backup complet (DB + fichiers) |
| Health check | Quotidien | 6h00 | Vérification après backup |
| Nettoyage | Hebdomadaire | Dimanche 3h00 | Suppression logs > 30 jours |
## Utilisation
### Démarrer le service
```bash
# Build et démarrage
docker-compose up -d backup-cron
# Ou reconstruire si modifié
docker-compose up -d --build backup-cron
```
### Vérifier le statut
```bash
# Via Makefile
make cron-status
# Ou directement
docker-compose ps backup-cron
docker-compose exec backup-cron cat /etc/crontabs/root
```
### Consulter les logs
```bash
# Via Makefile
make cron-logs
# Ou directement
tail -f logs/cron_backup.log
tail -f logs/cron_health.log
tail -f logs/cron_clean.log
```
### Tester manuellement
```bash
# Exécuter un backup immédiatement
docker-compose exec backup-cron /bin/bash -c "cd /project && bash scripts/backup.sh"
# Vérifier l'heure du container
docker-compose exec backup-cron date
```
## Personnalisation
### Modifier le planning
Éditez `cron/crontab` puis reconstruisez:
```bash
# Format cron: minute hour day month weekday command
# Exemple: backup toutes les 6 heures
0 */6 * * * cd /project && bash scripts/backup.sh >> /logs/cron_backup.log 2>&1
# Reconstruire
docker-compose up -d --build backup-cron
```
### Changer le fuseau horaire
Modifiez `docker-compose.yml`:
```yaml
environment:
- TZ=America/New_York # ou autre fuseau
```
## Sécurité
⚠️ **Important**: Le container a accès au socket Docker (`/var/run/docker.sock`), ce qui lui permet d'exécuter des commandes docker-compose. Cela est nécessaire pour les backups mais donne des privilèges élevés.
**Bonnes pratiques**:
- N'exposez pas ce service sur le réseau externe
- Gardez les scripts de backup en lecture seule si possible
- Surveillez les logs régulièrement
- Limitez les ressources du container si nécessaire
## Dépannage
### Le container ne démarre pas
```bash
# Vérifier les logs
docker-compose logs backup-cron
# Reconstruire from scratch
docker-compose build --no-cache backup-cron
docker-compose up -d backup-cron
```
### Les tâches ne s'exécutent pas
```bash
# Vérifier que crond tourne
docker-compose exec backup-cron ps aux | grep crond
# Vérifier le crontab
docker-compose exec backup-cron cat /etc/crontabs/root
# Vérifier l'heure du container
docker-compose exec backup-cron date
```
### Problèmes de permissions
```bash
# Le container doit pouvoir écrire dans ./backups et ./logs
chmod 755 backups logs
# Vérifier les montages
docker-compose exec backup-cron ls -la /project/backups
```
## Logs
Tous les logs sont stockés dans `./logs/`:
- `cron_backup.log`: Sorties des backups quotidiens
- `cron_health.log`: Résultats des health checks
- `cron_clean.log`: Logs de nettoyage hebdomadaire
Les logs sont automatiquement nettoyés après 30 jours.

11
cron/crontab Normal file
View File

@@ -0,0 +1,11 @@
# Nextcloud Docker - Tâches automatisées
# Format: minute hour day month weekday command
# Backup quotidien à 5h00 du matin (heure de Paris)
0 5 * * * cd /project && bash scripts/backup.sh >> /logs/cron_backup.log 2>&1
# Health check quotidien à 6h00 (après le backup)
0 6 * * * cd /project && bash scripts/check-health.sh >> /logs/cron_health.log 2>&1
# Nettoyage hebdomadaire le dimanche à 3h00
0 3 * * 0 cd /project && bash scripts/clean-old-logs.sh >> /logs/cron_clean.log 2>&1

18
cron/entrypoint.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
set -e
echo "========================================="
echo "Nextcloud Backup Cron Container"
echo "========================================="
echo "Fuseau horaire: ${TZ:-UTC}"
echo "Heure actuelle: $(date)"
echo ""
echo "Tâches programmées:"
cat /etc/crontabs/root | grep -v "^#" | grep -v "^$"
echo ""
echo "Logs disponibles dans /logs/"
echo "========================================="
echo ""
# Démarrer crond en mode foreground
exec crond -f -l 2

View File

@@ -13,3 +13,6 @@ binlog_format = ROW
# Connections # Connections
max_connections = 200 max_connections = 200
# Gros fichiers - augmenter la taille max des paquets
max_allowed_packet = 1G

View File

@@ -1,12 +1,21 @@
services: services:
nextcloud: nextcloud:
image: nextcloud:latest build: .
container_name: nextcloud image: nextcloud-custom:latest
restart: unless-stopped restart: unless-stopped
ports: ports:
- "127.0.0.1:8888:80" - "127.0.0.1:8888:80"
volumes: volumes:
- ./data:/var/www/html - ./data:/var/www/html
- ./apache/nextcloud.conf:/etc/apache2/conf-enabled/nextcloud.conf:ro
- ./apache/mpm_prefork.conf:/etc/apache2/mods-available/mpm_prefork.conf:ro
- ./logs/apache:/var/log/apache2
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
tag: "nextcloud"
environment: environment:
# Database # Database
- MYSQL_HOST=db - MYSQL_HOST=db
@@ -15,21 +24,25 @@ services:
- MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_PASSWORD=${MYSQL_PASSWORD}
# Domaine # Domaine
- NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN} - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN}
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-172.16.0.0/12} - TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
- OVERWRITEPROTOCOL=https - OVERWRITEPROTOCOL=${OVERWRITE_PROTOCOL:-http}
- OVERWRITEHOST=${NEXTCLOUD_DOMAIN} - OVERWRITEHOST=${OVERWRITE_HOST:-}
- OVERWRITECLIURL=https://${NEXTCLOUD_DOMAIN} - OVERWRITECLIURL=${OVERWRITE_CLI_URL:-}
# Redis # Redis
- REDIS_HOST=${REDIS_HOST} - REDIS_HOST=redis
- REDIS_HOST_PASSWORD=${REDIS_HOST_PASSWORD} - REDIS_HOST_PASSWORD=${REDIS_HOST_PASSWORD}
# PHP # PHP
- PHP_MEMORY_LIMIT=4096M - PHP_MEMORY_LIMIT=4096M
- PHP_UPLOAD_MAX_FILESIZE=2G - PHP_UPLOAD_MAX_FILESIZE=10G
- PHP_POST_MAX_SIZE=2G - PHP_POST_MAX_SIZE=10G
- PHP_MAX_EXECUTION_TIME=1800 - PHP_MAX_EXECUTION_TIME=7200
- PHP_MAX_INPUT_TIME=1800 - PHP_MAX_INPUT_TIME=7200
# - PHP_UPLOAD_MAX_FILESIZE=1024G
# - PHP_POST_MAX_SIZE=1024G
# - PHP_MAX_EXECUTION_TIME=86400
# - PHP_MAX_INPUT_TIME=86400
# Apache # Apache
- APACHE_BODY_LIMIT=2147483648 - APACHE_BODY_LIMIT=0
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/status.php"] test: ["CMD", "curl", "-f", "http://localhost/status.php"]
interval: 30s interval: 30s
@@ -43,16 +56,32 @@ services:
networks: networks:
- nextcloud-net - nextcloud-net
- traefik-net - traefik-net
labels:
- "traefik.enable=true"
# Router configuration
- "traefik.http.routers.cloud.rule=Host(`${NEXTCLOUD_DOMAIN}`)"
- "traefik.http.routers.cloud.entrypoints=websecure"
- "traefik.http.routers.cloud.tls.certresolver=letsencrypt"
- "traefik.http.routers.cloud.middlewares=nextcloud-headers,nextcloud-redirect"
# Service configuration
- "traefik.http.services.cloud.loadbalancer.server.port=80"
- "traefik.http.services.cloud.loadbalancer.serverstransport=nextcloud-transport"
# Middleware: Headers
- "traefik.http.middlewares.nextcloud-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.nextcloud-headers.headers.customresponseheaders.Strict-Transport-Security=max-age=15552000"
# Middleware: Redirect pour CalDAV/CardDAV
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav"
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.replacement=https://$$1/remote.php/dav/"
- "traefik.http.middlewares.nextcloud-redirect.redirectregex.permanent=true"
redis: redis:
image: redis:alpine image: redis:alpine
restart: unless-stopped restart: unless-stopped
command: redis-server --requirepass ${REDIS_HOST_PASSWORD} --maxmemory 512mb --maxmemory-policy allkeys-lru command: redis-server --requirepass ${REDIS_HOST_PASSWORD} --maxmemory 2gb --maxmemory-policy allkeys-lru
networks: networks:
- nextcloud-net - nextcloud-net
cron: cron:
image: nextcloud:latest image: nextcloud-custom:latest
restart: always restart: always
volumes_from: volumes_from:
- nextcloud - nextcloud
@@ -64,6 +93,28 @@ services:
networks: networks:
- nextcloud-net - nextcloud-net
backup-cron:
build: ./cron
restart: unless-stopped
volumes:
# Monter le projet complet pour accéder aux scripts
- .:/project
# Monter Docker socket pour exécuter les commandes docker-compose
- /var/run/docker.sock:/var/run/docker.sock
# Partager les volumes avec nextcloud pour les backups
- ./data:/var/www/html
- ./db:/var/lib/mysql
- ./backups:/project/backups
- ./logs:/logs
environment:
- TZ=Europe/Paris
- COMPOSE_PROJECT_NAME
depends_on:
- nextcloud
- db
networks:
- nextcloud-net
db: db:
image: mariadb:10.11 image: mariadb:10.11
restart: unless-stopped restart: unless-stopped
@@ -71,7 +122,7 @@ services:
- ./db:/var/lib/mysql - ./db:/var/lib/mysql
- ./db-config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro - ./db-config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
environment: environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_USER} - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=nextcloud - MYSQL_DATABASE=nextcloud
- MYSQL_USER=${MYSQL_USER} - MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_PASSWORD=${MYSQL_PASSWORD}

282
scripts/backup.sh Normal file → Executable file
View File

@@ -1,75 +1,267 @@
#!/bin/bash #!/bin/bash
# scripts/backup.sh - Backup complet Nextcloud # scripts/backup.sh - Backup complet Nextcloud
set -e set -euo pipefail
# Variables globales
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
# Charger .env en premier
if [ ! -f .env ]; then
echo "ERROR: Fichier .env introuvable"
exit 1
fi
set -a
# shellcheck disable=SC1091
source .env source .env
set +a
BACKUP_DIR="${BACKUP_DESTINATION:-./backups}" # Configuration
DATE=$(date +%Y%m%d_%H%M%S) DATE=$(date +%Y%m%d_%H%M%S)
LOCK_FILE="/tmp/nextcloud_backup.lock"
LOG_DIR="./logs"
LOG_FILE="$PROJECT_ROOT/logs/backup_$(date +%Y%m%d_%H%M%S).log"
BACKUP_DIR="${BACKUP_DESTINATION:-./backups}"
BACKUP_RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-7}"
BACKUP_NAME="nextcloud_backup_$DATE" BACKUP_NAME="nextcloud_backup_$DATE"
BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME" BACKUP_PATH="$BACKUP_DIR/$BACKUP_NAME"
MAINTENANCE_ENABLED=false
echo "🔧 Démarrage du backup: $BACKUP_NAME" mkdir -p "$LOG_DIR"
# Charger les fonctions communes (log avec couleurs)
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common.sh"
if [ -z "${MYSQL_DATABASE:-}" ] || [ -z "${MYSQL_USER:-}" ] || [ -z "${MYSQL_PASSWORD:-}" ]; then
log "ERROR" "Variables MysqlSQL non définies dans .env"
exit 1
fi
# Vérifier qu'un backup n'est pas déjà en cours
if [ -f "$LOCK_FILE" ]; then
log "ERROR" "Une sauvegarde est déjà en cours. Si aucune sauvegarde n'est en cours, supprimez le fichier: $LOCK_FILE"
exit 1
fi
touch "$LOCK_FILE"
mkdir -p "$LOG_DIR"
# Fonction de nettoyage en cas d'erreur
cleanup() {
local exit_code=$?
if [ "$exit_code" -ne 0 ]; then
log "ERROR" "Erreur détectée (code: $exit_code), nettoyage..."
fi
# Désactiver le mode maintenance si activé
if [ "$MAINTENANCE_ENABLED" = true ]; then
log "INFO" "Désactivation du mode maintenance..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE" || true
fi
# Nettoyer le backup partiel
if [ -d "$BACKUP_PATH" ]; then
log "INFO" "Nettoyage du backup partiel..."
rm -rf "${BACKUP_PATH:?}"
fi
# Supprimer le lock
rm -f "$LOCK_FILE"
if [ "$exit_code" -eq 0 ]; then
log "SUCCESS" "Backup terminé avec succès"
else
log "ERROR" "Backup échoué avec code: $exit_code"
fi
exit "$exit_code"
}
trap cleanup EXIT INT TERM
log "INFO" "=== Démarrage du backup: $BACKUP_NAME ==="
log "INFO" "Log file: $LOG_FILE"
# Vérifier l'espace disque disponible
log "INFO" "Vérification de l'espace disque..."
# Calculer l'espace requis (taille data + db avec 20% de marge)
# Calculer depuis le container avec les mêmes exclusions que le backup
log "INFO" "Calcul de la taille réelle (avec exclusions)..."
DATA_SIZE=$(docker-compose exec -T nextcloud du -sb \
--exclude='appdata_*/preview' \
--exclude='*/cache' \
--exclude='*/thumbnails' \
/var/www/html/data 2>/dev/null | awk '{print $1}' || echo "0")
# Note: On n'inclut pas la DB car mysqldump est beaucoup plus petit que les fichiers MySQL bruts
# Typiquement: fichiers MySQL = 650MB → dump SQL = 500KB (compression ~99%)
# On ajoute juste 10MB fixe pour DB + config + apps (généralement < 1MB au final)
DB_ESTIMATE=10485760 # 10MB
# Additionner avec 20% de marge
REQUIRED_SPACE=$(echo "$DATA_SIZE + $DB_ESTIMATE" | awk '{total=$1+$3; print int(total*1.2)}')
if [ -z "$REQUIRED_SPACE" ] || [ "$REQUIRED_SPACE" = "0" ]; then
log "WARN" "Impossible de calculer l'espace requis, estimation à 500MB"
REQUIRED_SPACE=500000000 # 500MB par défaut (plus réaliste que 2GB)
fi
# Obtenir l'espace disponible (enlever les espaces/newlines)
# Utiliser -P pour format POSIX (garantit une ligne par système de fichiers)
AVAILABLE_SPACE=$(df -P -B1 "$BACKUP_DIR" | awk 'NR==2 {print $4}' | tr -d '[:space:]')
if [ -z "$AVAILABLE_SPACE" ]; then
log "ERROR" "Impossible de déterminer l'espace disque disponible"
exit 1
fi
# Calculer estimation avec compression
# Note: Nextcloud a beaucoup de fichiers déjà compressés (images, PDFs)
# donc la compression gzip est peu efficace (~30% au lieu de 90%)
if [ "$REQUIRED_SPACE" -gt 0 ] 2>/dev/null; then
ESTIMATED_COMPRESSED=$((REQUIRED_SPACE * 7 / 10)) # 70% de la taille (30% de compression)
log "INFO" "Espace requis (non compressé + 20%): $(numfmt --to=iec-i --suffix=B "$REQUIRED_SPACE" 2>/dev/null || echo "$REQUIRED_SPACE bytes")"
log "INFO" "Espace estimé après compression: $(numfmt --to=iec-i --suffix=B "$ESTIMATED_COMPRESSED" 2>/dev/null || echo "$ESTIMATED_COMPRESSED bytes")"
else
log "INFO" "Espace requis: Impossible à calculer (utilisation du fallback)"
fi
log "INFO" "Espace disponible: $(numfmt --to=iec-i --suffix=B "$AVAILABLE_SPACE" 2>/dev/null || echo "$AVAILABLE_SPACE bytes")"
# Comparaison sécurisée avec validation
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_SPACE" ] 2>/dev/null; then
log "ERROR" "Espace disque insuffisant"
exit 1
fi
# Créer le dossier de backup # Créer le dossier de backup
mkdir -p "$BACKUP_PATH" mkdir -p "$BACKUP_PATH"
# 1. Activer le mode maintenance # 1. Activer le mode maintenance
echo "⏸️ Activation du mode maintenance..." log "INFO" "Activation du mode maintenance..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --on if docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --on 2>>"$LOG_FILE"; then
MAINTENANCE_ENABLED=true
log "INFO" "Mode maintenance activé"
else
log "ERROR" "Impossible d'activer le mode maintenance"
exit 1
fi
# 2. Backup de la base de données # 2. Backup de la base de données
echo "💾 Backup de la base de données..." log "INFO" "Backup de la base de données..."
docker-compose exec -T db mysqldump \ START_TIME=$(date +%s)
-u"$MYSQL_USER" \ if ! docker-compose exec -T db sh -c "MYSQL_PWD=\"\$MYSQL_PASSWORD\" mysqldump \
-p"$MYSQL_PASSWORD" \ -u\"\$MYSQL_USER\" \
"$MYSQL_DATABASE" \ \"\$MYSQL_DATABASE\" \
--single-transaction \ --single-transaction \
--quick \ --quick \
--lock-tables=false \ --lock-tables=false" >"$BACKUP_PATH/database.sql" 2>>"$LOG_FILE"; then
> "$BACKUP_PATH/database.sql" log "ERROR" "Erreur lors du backup de la base de données"
exit 1
fi
END_TIME=$(date +%s)
DB_SIZE=$(du -h "$BACKUP_PATH/database.sql" | cut -f1)
log "INFO" "Base de données sauvegardée: $DB_SIZE ($((END_TIME - START_TIME))s)"
# 3. Backup des fichiers de config # 3. Backup des fichiers de config
echo "⚙️ Backup de la configuration..." log "INFO" "Backup de la configuration..."
tar -czf "$BACKUP_PATH/config.tar.gz" \ START_TIME=$(date +%s)
-C ./data/config . if ! docker-compose exec -T -u www-data nextcloud tar -czf - -C /var/www/html/config . >"$BACKUP_PATH/config.tar.gz" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors du backup de la configuration"
exit 1
fi
END_TIME=$(date +%s)
CONFIG_SIZE=$(du -h "$BACKUP_PATH/config.tar.gz" | cut -f1)
log "INFO" "Configuration sauvegardée: $CONFIG_SIZE ($((END_TIME - START_TIME))s)"
# 4. Backup des données utilisateurs (optionnel, peut être énorme) # 4. Backup des données utilisateurs
echo "📁 Backup des données utilisateurs..." log "INFO" "Backup des données utilisateurs..."
# Pour un backup incrémental, utilisez rsync START_TIME=$(date +%s)
rsync -a --info=progress2 \ if ! docker-compose exec -T -u www-data nextcloud tar -czf - \
./data/data/ \ -C /var/www/html/data \
"$BACKUP_PATH/data/" \ --exclude='appdata_*/preview' \
--exclude 'appdata_*/preview' \ --exclude='*/cache' \
--exclude '*/cache' \ --exclude='*/thumbnails' \
--exclude '*/thumbnails' . >"$BACKUP_PATH/data.tar.gz" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors du backup des données"
exit 1
fi
END_TIME=$(date +%s)
DATA_SIZE=$(du -h "$BACKUP_PATH/data.tar.gz" | cut -f1)
log "INFO" "Données sauvegardées: $DATA_SIZE ($((END_TIME - START_TIME))s)"
# Ou pour un tar compressé (long): # 5. Backup des apps personnalisées
# tar -czf "$BACKUP_PATH/data.tar.gz" \ log "INFO" "Backup des apps personnalisées..."
# --exclude='appdata_*/preview' \ if docker-compose exec -T nextcloud [ -d /var/www/html/custom_apps ] 2>>"$LOG_FILE"; then
# -C ./data/data . if docker-compose exec -T -u www-data nextcloud tar -czf - \
-C /var/www/html/custom_apps . >"$BACKUP_PATH/apps.tar.gz" 2>>"$LOG_FILE"; then
# 5. Backup des apps APPS_SIZE=$(du -h "$BACKUP_PATH/apps.tar.gz" | cut -f1)
echo "📦 Backup des apps personnalisées..." log "INFO" "Apps sauvegardées: $APPS_SIZE"
if [ -d "./data/custom_apps" ]; then else
tar -czf "$BACKUP_PATH/apps.tar.gz" \ log "WARN" "Erreur lors du backup des apps personnalisées"
-C ./data/custom_apps . fi
else
log "INFO" "Pas d'apps personnalisées à sauvegarder"
fi fi
# 6. Désactiver le mode maintenance # 6. Désactiver le mode maintenance
echo "▶️ Désactivation du mode maintenance..." log "INFO" "Désactivation du mode maintenance..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off if docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE"; then
MAINTENANCE_ENABLED=false
log "INFO" "Mode maintenance désactivé"
else
log "WARN" "Impossible de désactiver le mode maintenance"
fi
# 7. Créer une archive complète # 7. Créer une archive complète
echo "🗜️ Compression finale..." log "INFO" "Compression finale..."
cd "$BACKUP_DIR" START_TIME=$(date +%s)
tar -czf "$BACKUP_NAME.tar.gz" "$BACKUP_NAME/" if ! tar -czf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" -C "$BACKUP_DIR" "$BACKUP_NAME/" 2>>"$LOG_FILE"; then
rm -rf "$BACKUP_NAME" log "ERROR" "Erreur lors de la compression"
exit 1
fi
END_TIME=$(date +%s)
ARCHIVE_SIZE=$(du -h "$BACKUP_DIR/$BACKUP_NAME.tar.gz" | cut -f1)
log "INFO" "Archive créée: $ARCHIVE_SIZE ($((END_TIME - START_TIME))s)"
# 8. Nettoyer les vieux backups # 8. Générer le checksum SHA256
echo "🧹 Nettoyage des backups > ${BACKUP_RETENTION_DAYS:-30} jours..." log "INFO" "Génération du checksum SHA256..."
find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -mtime +${BACKUP_RETENTION_DAYS:-30} -delete if cd "$BACKUP_DIR" && sha256sum "$BACKUP_NAME.tar.gz" >"$BACKUP_NAME.tar.gz.sha256"; then
cd "$PROJECT_ROOT"
CHECKSUM=$(cut -d' ' -f1 "$BACKUP_DIR/$BACKUP_NAME.tar.gz.sha256")
else
cd "$PROJECT_ROOT"
log "WARN" "Impossible de générer le checksum"
fi
echo "✅ Backup terminé: $BACKUP_DIR/$BACKUP_NAME.tar.gz" # Supprimer le dossier temporaire après compression réussie
du -h "$BACKUP_DIR/$BACKUP_NAME.tar.gz" rm -rf "${BACKUP_PATH:?}"
# 9. Nettoyer les vieux backups
log "INFO" "Nettoyage des backups > $BACKUP_RETENTION_DAYS jours..."
DELETED_COUNT=0
while IFS= read -r -d '' file; do
CHECKSUM_FILE="${file}.sha256"
log "INFO" "Suppression: $(basename "$file")"
rm -f "$file" "$CHECKSUM_FILE" 2>>"$LOG_FILE" || true
DELETED_COUNT=$((DELETED_COUNT + 1))
done < <(find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -type f -mtime +"$BACKUP_RETENTION_DAYS" -print0 2>/dev/null || true)
if [ "$DELETED_COUNT" -gt 0 ]; then
log "INFO" "$DELETED_COUNT ancien(s) backup(s) supprimé(s)"
else
log "INFO" "Aucun ancien backup à supprimer"
fi
# 10. Statistiques finales
log "INFO" "=== Statistiques du backup ==="
log "INFO" "Archive: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
log "INFO" "Taille: $ARCHIVE_SIZE"
log "INFO" "Checksum: ${CHECKSUM:-N/A}"
log "INFO" "Rétention: $BACKUP_RETENTION_DAYS jours"
log "INFO" "Backups disponibles: $(find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -type f 2>/dev/null | wc -l)"

283
scripts/check-health.sh Executable file
View File

@@ -0,0 +1,283 @@
#!/bin/bash
# scripts/check-health.sh - Vérification complète de la santé du système
set -euo pipefail
# Variables globales
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
# Charger .env pour accéder aux variables (Redis password, etc.)
if [ -f .env ]; then
set -a
# shellcheck disable=SC1091
source .env
set +a
fi
# Charger les couleurs depuis common.sh
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common.sh"
# Compteurs
CHECKS_PASSED=0
CHECKS_FAILED=0
CHECKS_WARNING=0
# Fonction de logging
check_ok() {
echo -e "${GREEN}${NC} $*"
CHECKS_PASSED=$((CHECKS_PASSED + 1))
}
check_fail() {
echo -e "${RED}${NC} $*"
CHECKS_FAILED=$((CHECKS_FAILED + 1))
}
check_warn() {
echo -e "${YELLOW}${NC} $*"
CHECKS_WARNING=$((CHECKS_WARNING + 1))
}
echo "=== Health Check Nextcloud ==="
echo ""
# 1. Vérifier que Docker est disponible
echo "▶ Vérifications système:"
if command -v docker >/dev/null 2>&1; then
check_ok "Docker installé: $(docker --version | head -1)"
else
check_fail "Docker non installé"
fi
# Vérifier Docker Compose
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
check_ok "Docker Compose v2 installé: $(docker compose version --short)"
elif command -v docker-compose >/dev/null 2>&1; then
check_warn "Docker Compose v1 installé (obsolète): $(docker-compose --version)"
else
check_fail "Docker Compose non installé"
fi
echo ""
# 2. Vérifier les fichiers de configuration
echo "▶ Fichiers de configuration:"
if [ -f .env ]; then
check_ok "Fichier .env présent"
# Vérifier les mots de passe faibles
if grep -qE "(userpassword|rootpassword|redispassword)" .env 2>/dev/null; then
check_warn "Mots de passe faibles détectés dans .env - Changez-les!"
else
check_ok "Pas de mots de passe faibles détectés"
fi
else
check_fail "Fichier .env manquant"
fi
if [ -f docker-compose.yml ]; then
check_ok "Fichier docker-compose.yml présent"
else
check_fail "Fichier docker-compose.yml manquant"
fi
echo ""
# 3. Vérifier l'état des containers
echo "▶ État des containers:"
CONTAINERS=("nextcloud" "db" "redis" "cron")
for container in "${CONTAINERS[@]}"; do
if docker-compose ps "$container" 2>/dev/null | grep -q "Up"; then
check_ok "Container $container: actif"
else
check_fail "Container $container: inactif ou manquant"
fi
done
echo ""
# 4. Vérifier Nextcloud
echo "▶ Application Nextcloud:"
if docker-compose exec -T nextcloud curl -f http://localhost/status.php >/dev/null 2>&1; then
check_ok "Nextcloud répond aux requêtes HTTP"
# Vérifier le statut via OCC
if STATUS=$(docker-compose exec -T -u www-data nextcloud php occ status 2>/dev/null); then
check_ok "Commande OCC accessible"
if echo "$STATUS" | grep -q "installed: true"; then
check_ok "Nextcloud installé"
else
check_fail "Nextcloud non installé"
fi
if echo "$STATUS" | grep -q "maintenance: false"; then
check_ok "Mode maintenance: désactivé"
else
check_warn "Mode maintenance: activé"
fi
# Afficher la version
VERSION=$(echo "$STATUS" | grep "versionstring:" | awk '{print $3}')
if [ -n "$VERSION" ]; then
check_ok "Version: $VERSION"
fi
else
check_fail "Impossible d'accéder aux commandes OCC"
fi
else
check_fail "Nextcloud ne répond pas"
fi
echo ""
# 5. Vérifier la base de données
echo "▶ Base de données:"
if docker-compose exec -T db mysqladmin ping -h localhost --silent 2>/dev/null; then
check_ok "MariaDB répond"
# Tester la connexion MySQL (utilise les variables d'environnement du container)
if docker-compose exec -T db sh -c 'MYSQL_PWD="$MYSQL_PASSWORD" mysql -u"$MYSQL_USER" "$MYSQL_DATABASE" -e "SELECT 1"' >/dev/null 2>&1; then
check_ok "Connexion MySQL fonctionnelle"
else
check_fail "Impossible de se connecter à MySQL"
fi
else
check_fail "MariaDB ne répond pas"
fi
echo ""
# 6. Vérifier Redis
echo "▶ Cache Redis:"
if [ -n "${REDIS_HOST_PASSWORD:-}" ]; then
if docker-compose exec -T redis redis-cli -a "$REDIS_HOST_PASSWORD" ping 2>/dev/null | grep -q "PONG"; then
check_ok "Redis répond (avec authentification)"
else
check_fail "Redis ne répond pas ou mot de passe incorrect"
fi
else
if docker-compose exec -T redis redis-cli ping 2>/dev/null | grep -q "PONG"; then
check_ok "Redis répond (sans authentification)"
else
check_fail "Redis ne répond pas"
fi
fi
echo ""
# 7. Vérifier l'espace disque
echo "▶ Espace disque:"
DISK_USAGE=$(df -h . | awk 'NR==2 {print $5}' | sed 's/%//')
DISK_AVAIL=$(df -h . | awk 'NR==2 {print $4}')
if [ "$DISK_USAGE" -lt 80 ]; then
check_ok "Utilisation disque: ${DISK_USAGE}% (${DISK_AVAIL} disponible)"
elif [ "$DISK_USAGE" -lt 90 ]; then
check_warn "Utilisation disque: ${DISK_USAGE}% (${DISK_AVAIL} disponible) - Attention"
else
check_fail "Utilisation disque: ${DISK_USAGE}% (${DISK_AVAIL} disponible) - CRITIQUE"
fi
# Vérifier la taille des données utilisateurs
if [ -d ./data/data ]; then
DATA_SIZE=$(du -sh ./data/data 2>/dev/null | cut -f1 || echo "")
if [ -z "$DATA_SIZE" ]; then
DATA_SIZE="N/A"
fi
check_ok "Taille des données utilisateurs: $DATA_SIZE"
fi
if [ -d ./db ]; then
DB_SIZE=$(du -sh ./db 2>/dev/null | cut -f1 || echo "")
if [ -z "$DB_SIZE" ]; then
DB_SIZE="N/A"
fi
check_ok "Taille de la base: $DB_SIZE"
fi
echo ""
# 8. Vérifier les backups
echo "▶ Backups:"
BACKUP_DIR="${BACKUP_DESTINATION:-./backups}"
if [ -d "$BACKUP_DIR" ]; then
BACKUP_COUNT=$(find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -type f 2>/dev/null | wc -l)
if [ "$BACKUP_COUNT" -gt 0 ]; then
check_ok "$BACKUP_COUNT backup(s) disponible(s)"
# Trouver le backup le plus récent
LATEST_BACKUP=$(find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -n "$LATEST_BACKUP" ]; then
BACKUP_AGE=$(find "$LATEST_BACKUP" -mtime +1 2>/dev/null)
if [ -z "$BACKUP_AGE" ]; then
check_ok "Dernier backup: < 24h"
else
BACKUP_DAYS=$(find "$LATEST_BACKUP" -mtime +0 -printf '%Td' 2>/dev/null || echo "?")
if [ "$BACKUP_DAYS" -lt 7 ]; then
check_warn "Dernier backup: il y a ${BACKUP_DAYS} jour(s)"
else
check_fail "Dernier backup: il y a ${BACKUP_DAYS} jour(s) - Trop ancien!"
fi
fi
# Vérifier le checksum
if [ -f "${LATEST_BACKUP}.sha256" ]; then
check_ok "Checksum présent pour le dernier backup"
else
check_warn "Pas de checksum pour le dernier backup"
fi
fi
else
check_warn "Aucun backup trouvé dans $BACKUP_DIR"
fi
else
check_warn "Dossier de backup introuvable: $BACKUP_DIR"
fi
echo ""
# 9. Vérifier les logs
echo "▶ Logs:"
if [ -d ./logs ]; then
LOG_COUNT=$(find ./logs -type f 2>/dev/null | wc -l)
check_ok "$LOG_COUNT fichier(s) de log"
LOGS_SIZE=$(du -sh ./logs 2>/dev/null | cut -f1 || echo "")
if [ -z "$LOGS_SIZE" ]; then
LOGS_SIZE="N/A"
fi
check_ok "Taille des logs: $LOGS_SIZE"
else
check_warn "Dossier de logs introuvable"
fi
echo ""
# Résumé final
echo "=== Résumé ==="
echo -e "${GREEN}Réussi:${NC} $CHECKS_PASSED"
if [ "$CHECKS_WARNING" -gt 0 ]; then
echo -e "${YELLOW}Avertissements:${NC} $CHECKS_WARNING"
fi
if [ "$CHECKS_FAILED" -gt 0 ]; then
echo -e "${RED}Échecs:${NC} $CHECKS_FAILED"
fi
echo ""
# Code de sortie
if [ "$CHECKS_FAILED" -gt 0 ]; then
echo -e "${RED}❌ Système non sain - Des problèmes nécessitent votre attention${NC}"
exit 1
elif [ "$CHECKS_WARNING" -gt 0 ]; then
echo -e "${YELLOW}⚠ Système fonctionnel avec avertissements${NC}"
exit 0
else
echo -e "${GREEN}✓ Système en bonne santé${NC}"
exit 0
fi

26
scripts/clean-old-logs.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
# scripts/clean-old-logs.sh - Nettoyage automatique des vieux logs
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
LOG_DIR="./logs"
RETENTION_DAYS=30
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nettoyage des logs > ${RETENTION_DAYS} jours..."
# Compter les fichiers avant nettoyage
BEFORE=$(find "$LOG_DIR" -type f -name "*.log" 2>/dev/null | wc -l)
# Supprimer les logs plus vieux que RETENTION_DAYS jours
DELETED=$(find "$LOG_DIR" -type f -name "*.log" -mtime +${RETENTION_DAYS} -delete -print 2>/dev/null | wc -l)
# Compter les fichiers après nettoyage
AFTER=$(find "$LOG_DIR" -type f -name "*.log" 2>/dev/null | wc -l)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Fichiers supprimés: $DELETED"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Fichiers restants: $AFTER"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Nettoyage terminé"

33
scripts/common.sh Normal file
View File

@@ -0,0 +1,33 @@
# scripts/common.sh - Fonctions communes à tous les scripts
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Fonction de logging
log() {
local level="$1"
shift
local message="$*"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local color=""
case "$level" in
ERROR) color="${RED}" ;;
WARN) color="${YELLOW}" ;;
SUCCESS) color="${GREEN}" ;;
INFO) color="" ;;
esac
echo "[$timestamp] [$level] $message" >>"${LOG_FILE:-/tmp/script.log}"
if [ -t 1 ]; then
echo -e "${color}[$timestamp] [$level] $message${NC}"
else
echo "[$timestamp] [$level] $message"
fi
}

25
scripts/occ.sh Normal file → Executable file
View File

@@ -1,6 +1,27 @@
#!/bin/bash #!/bin/bash
# scripts/occ.sh - Wrapper pour commandes OCC # scripts/occ.sh - Wrapper pour commandes OCC
set -e set -euo pipefail
docker-compose exec -u www-data nextcloud php occ "$@" # Détecter docker-compose v1 ou docker compose v2
DOCKER_COMPOSE=""
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
DOCKER_COMPOSE="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DOCKER_COMPOSE="docker-compose"
else
echo "❌ Erreur: Ni 'docker compose' (v2) ni 'docker-compose' (v1) n'est disponible"
echo " Installez Docker Compose: https://docs.docker.com/compose/install/"
exit 1
fi
# Vérifier que le container nextcloud est actif
if ! $DOCKER_COMPOSE ps nextcloud 2>/dev/null | grep -q "Up"; then
echo "❌ Erreur: Le container nextcloud n'est pas actif"
echo " Démarrez-le avec: make up"
exit 1
fi
# Exécuter la commande OCC
# Le "$@" est sûr ici car il est passé directement à PHP OCC qui gère la validation
$DOCKER_COMPOSE exec -u www-data nextcloud php occ "$@"

97
scripts/recover.sh Executable file
View File

@@ -0,0 +1,97 @@
#!/bin/bash
# scripts/recover.sh - Script de récupération après erreur
set -euo pipefail
# Variables globales
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
# Configuration des logs
LOG_DIR="./logs"
LOG_FILE="$PROJECT_ROOT/logs/recover_$(date +%Y%m%d_%H%M%S).log"
mkdir -p "$LOG_DIR"
# Charger les fonctions communes (log avec couleurs)
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common.sh"
log "INFO" "=== Script de récupération Nextcloud ==="
log "INFO" "Log file: $LOG_FILE"
# 1. Arrêter tous les conteneurs
log "INFO" "Arrêt de tous les conteneurs..."
if docker-compose down --remove-orphans 2>>"$LOG_FILE"; then
log "INFO" "Conteneurs arrêtés"
else
log "WARN" "Erreur lors de l'arrêt normal, tentative de force..."
docker-compose kill 2>>"$LOG_FILE" || true
docker-compose rm -f 2>>"$LOG_FILE" || true
fi
# 2. Nettoyer les conteneurs orphelins
log "INFO" "Nettoyage des conteneurs orphelins..."
docker container prune -f 2>>"$LOG_FILE" || log "WARN" "Impossible de nettoyer les conteneurs"
# 3. Redémarrer les services
log "INFO" "Redémarrage des services..."
if ! docker-compose up -d 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors du redémarrage"
log "ERROR" "Vérifiez les logs: docker-compose logs"
exit 1
fi
# 4. Attendre que Nextcloud soit prêt
log "INFO" "Attente du démarrage de Nextcloud (max 2 minutes)..."
for i in {1..120}; do
if docker-compose exec -T nextcloud curl -f http://localhost/status.php >/dev/null 2>&1; then
log "INFO" "Nextcloud prêt (${i}s)"
break
fi
if [ "$i" -eq 120 ]; then
log "ERROR" "Timeout: Nextcloud n'est pas prêt après 2 minutes"
log "ERROR" "Logs des conteneurs:"
docker-compose logs --tail=50 nextcloud 2>&1 | tee -a "$LOG_FILE"
exit 1
fi
sleep 1
done
# 5. Désactiver le mode maintenance
log "INFO" "Désactivation du mode maintenance..."
if docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE"; then
log "INFO" "Mode maintenance désactivé"
else
log "WARN" "Impossible de désactiver le mode maintenance"
fi
# 6. Vérifier le statut
log "INFO" "Statut final:"
docker-compose exec -T -u www-data nextcloud php occ status 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Impossible d'obtenir le statut"
# 7. Suggérer les prochaines étapes
log "INFO" "=== Récupération terminée ==="
echo ""
echo "Prochaines étapes:"
echo " 1. Vérifiez que tout fonctionne: make health"
echo " 2. Consultez les logs si nécessaire: make logs"
# Lister les backups disponibles
BACKUP_DIR="${BACKUP_DESTINATION:-./backups}"
if [ -d "$BACKUP_DIR" ]; then
LATEST_BACKUP=$(find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)
if [ -n "$LATEST_BACKUP" ]; then
echo " 3. Si problème persiste, restaurez le backup le plus récent:"
echo " make restore \"$LATEST_BACKUP\""
log "INFO" "Backup le plus récent: $LATEST_BACKUP"
else
echo " 3. Aucun backup disponible dans $BACKUP_DIR"
fi
else
echo " 3. Dossier de backup introuvable: $BACKUP_DIR"
fi
log "SUCCESS" "Script de récupération terminé"

295
scripts/restore.sh Normal file → Executable file
View File

@@ -1,70 +1,277 @@
#!/bin/bash #!/bin/bash
# scripts/restore.sh - Restauration d'un backup # scripts/restore.sh - Restauration d'un backup
set -e set -euo pipefail
if [ -z "$1" ]; then # Variables globales
echo "Usage: $0 <backup_file.tar.gz>" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
# Charger .env en premier
if [ ! -f .env ]; then
echo "ERROR: Fichier .env introuvable"
exit 1
fi
set -a
# shellcheck disable=SC1091
source .env
set +a
# Configuration des logs
LOG_DIR="./logs"
LOG_FILE="$PROJECT_ROOT/logs/restore_$(date +%Y%m%d_%H%M%S).log"
TEMP_DIR=""
mkdir -p "$LOG_DIR"
# Charger les fonctions communes (log avec couleurs)
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common.sh"
# Vérifier les variables requises
if [ -z "${MYSQL_USER:-}" ] || [ -z "${MYSQL_PASSWORD:-}" ] || [ -z "${MYSQL_DATABASE:-}" ]; then
log "ERROR" "Variables MySQL non définies dans .env"
exit 1
fi
# Vérifier les arguments
if [ -z "${1:-}" ]; then
log "ERROR" "Usage: $0 <backup_file.tar.gz>"
exit 1 exit 1
fi fi
BACKUP_FILE="$1" BACKUP_FILE="$1"
if [ ! -f "$BACKUP_FILE" ]; then # Valider le chemin du fichier (éviter path traversal)
echo "❌ Fichier introuvable: $BACKUP_FILE" if [[ "$BACKUP_FILE" =~ \.\. ]] || [[ "$BACKUP_FILE" == /* && ! "$BACKUP_FILE" =~ ^/home/ && ! "$BACKUP_FILE" =~ ^/tmp/ ]]; then
log "ERROR" "Chemin de fichier invalide ou non autorisé"
exit 1 exit 1
fi fi
echo "⚠️ ATTENTION: Cette opération va écraser les données actuelles !" # Résoudre le chemin absolu
read -p "Continuer? (yes/no): " confirm BACKUP_FILE=$(realpath "$BACKUP_FILE" 2>/dev/null) || {
log "ERROR" "Impossible de résoudre le chemin: $1"
exit 1
}
if [ ! -f "$BACKUP_FILE" ]; then
log "ERROR" "Fichier introuvable: $BACKUP_FILE"
exit 1
fi
# Vérifier que c'est bien un fichier tar.gz
if ! file "$BACKUP_FILE" | grep -q "gzip compressed"; then
log "ERROR" "Le fichier n'est pas une archive gzip valide"
exit 1
fi
# Vérifier le checksum si disponible
CHECKSUM_FILE="${BACKUP_FILE}.sha256"
if [ -f "$CHECKSUM_FILE" ]; then
log "INFO" "Vérification du checksum..."
BACKUP_DIR=$(dirname "$BACKUP_FILE")
BACKUP_NAME=$(basename "$BACKUP_FILE")
if cd "$BACKUP_DIR" && sha256sum -c "$BACKUP_NAME.sha256" 2>>"$LOG_FILE"; then
cd "$PROJECT_ROOT"
log "INFO" "Checksum valide"
else
cd "$PROJECT_ROOT"
log "ERROR" "Checksum invalide! Le fichier pourrait être corrompu"
exit 1
fi
else
log "WARN" "Pas de fichier checksum trouvé, impossible de vérifier l'intégrité"
fi
log "INFO" "=== Restauration depuis: $BACKUP_FILE ==="
log "INFO" "Log file: $LOG_FILE"
echo ""
log "WARN" "ATTENTION: Cette opération va écraser les données actuelles!"
read -r -p "Voulez-vous créer un backup de sécurité avant de continuer? (yes/no): " create_backup
if [ "$create_backup" = "yes" ]; then
log "INFO" "Création du backup de sécurité..."
if bash scripts/backup.sh 2>&1 | tee -a "$LOG_FILE"; then
log "INFO" "Backup de sécurité créé avec succès"
else
log "ERROR" "Échec du backup de sécurité"
read -r -p "Continuer quand même? (yes/no): " force_continue
if [ "$force_continue" != "yes" ]; then
log "INFO" "Restauration annulée"
exit 0
fi
fi
fi
echo ""
read -r -p "Continuer la restauration? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then if [ "$confirm" != "yes" ]; then
echo "Annulé." log "INFO" "Restauration annulée"
exit 0 exit 0
fi fi
# Fonction de nettoyage
cleanup() {
local exit_code=$?
if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
log "INFO" "Nettoyage du répertoire temporaire..."
rm -rf "${TEMP_DIR:?}"
fi
if [ "$exit_code" -eq 0 ]; then
log "SUCCESS" "Restauration terminée avec succès"
else
log "ERROR" "Restauration échouée avec code: $exit_code"
log "ERROR" "Pour récupérer, utilisez: bash scripts/recover.sh"
fi
exit "$exit_code"
}
trap cleanup EXIT INT TERM
# Extraire le backup # Extraire le backup
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
echo "📂 Extraction vers $TEMP_DIR..." log "INFO" "Extraction vers $TEMP_DIR..."
tar -xzf "$BACKUP_FILE" -C "$TEMP_DIR"
BACKUP_DIR=$(ls -1 "$TEMP_DIR" | head -n1) if ! tar -xzf "$BACKUP_FILE" -C "$TEMP_DIR" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors de l'extraction"
# Arrêter les services exit 1
echo "⏹️ Arrêt des services..."
docker-compose down
# Restaurer la base de données
echo "💾 Restauration de la base de données..."
docker-compose up -d db
sleep 10
docker-compose exec -T db mysql \
-u"$MYSQL_USER" \
-p"$MYSQL_PASSWORD" \
"$MYSQL_DATABASE" \
< "$TEMP_DIR/$BACKUP_DIR/database.sql"
# Restaurer les fichiers
echo "📁 Restauration des fichiers..."
tar -xzf "$TEMP_DIR/$BACKUP_DIR/config.tar.gz" -C ./data/config
tar -xzf "$TEMP_DIR/$BACKUP_DIR/data.tar.gz" -C ./data/data
if [ -f "$TEMP_DIR/$BACKUP_DIR/apps.tar.gz" ]; then
tar -xzf "$TEMP_DIR/$BACKUP_DIR/apps.tar.gz" -C ./data/custom_apps
fi fi
# Redémarrer # Trouver le répertoire de backup
echo "▶️ Redémarrage des services..." BACKUP_DIR=$(find "$TEMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n1)
docker-compose up -d if [ -z "$BACKUP_DIR" ]; then
log "ERROR" "Aucun répertoire trouvé dans l'archive"
exit 1
fi
log "INFO" "Backup extrait: $(basename "$BACKUP_DIR")"
# Vérifier que les fichiers requis existent
if [ ! -f "$BACKUP_DIR/database.sql" ]; then
log "ERROR" "Fichier database.sql manquant dans l'archive"
exit 1
fi
if [ ! -f "$BACKUP_DIR/config.tar.gz" ]; then
log "ERROR" "Fichier config.tar.gz manquant dans l'archive"
exit 1
fi
# Arrêter les services
log "INFO" "Arrêt des services..."
docker-compose down 2>>"$LOG_FILE"
# Démarrer uniquement la base de données
log "INFO" "Démarrage de la base de données..."
docker-compose up -d db 2>>"$LOG_FILE"
# Attendre que la base de données soit prête
log "INFO" "Attente de la base de données..."
for i in {1..30}; do
if docker-compose exec -T db mysqladmin ping -h localhost --silent 2>>"$LOG_FILE"; then
log "INFO" "Base de données prête"
break
fi
if [ "$i" -eq 30 ]; then
log "ERROR" "Timeout: La base de données n'est pas prête"
exit 1
fi
sleep 1
done
# Backup de sécurité de la DB actuelle
log "INFO" "Backup de sécurité de la base de données actuelle..."
SAFETY_BACKUP="$TEMP_DIR/safety_db_backup.sql"
if docker-compose exec -T db sh -c "MYSQL_PWD=\"\$MYSQL_PASSWORD\" mysqldump \
-u\"\$MYSQL_USER\" \
\"\$MYSQL_DATABASE\" \
--single-transaction \
--quick" > "$SAFETY_BACKUP" 2>>"$LOG_FILE"; then
log "INFO" "Backup de sécurité créé: $SAFETY_BACKUP"
else
log "WARN" "Impossible de créer un backup de sécurité de la DB"
fi
# Restaurer la base de données
log "INFO" "Restauration de la base de données..."
if ! docker-compose exec -T db sh -c "MYSQL_PWD=\"\$MYSQL_PASSWORD\" mysql \
-u\"\$MYSQL_USER\" \
\"\$MYSQL_DATABASE\"" < "$BACKUP_DIR/database.sql" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors de la restauration de la base de données"
log "ERROR" "Backup de sécurité disponible: $SAFETY_BACKUP"
exit 1
fi
log "INFO" "Base de données restaurée"
# Démarrer tous les services
log "INFO" "Démarrage de tous les services..."
docker-compose up -d 2>>"$LOG_FILE"
# Attendre que Nextcloud soit prêt
log "INFO" "Attente du démarrage de Nextcloud..."
for i in {1..60}; do
if docker-compose exec -T nextcloud curl -f http://localhost/status.php >/dev/null 2>&1; then
log "INFO" "Nextcloud prêt"
break
fi
if [ "$i" -eq 60 ]; then
log "ERROR" "Timeout: Nextcloud n'est pas prêt"
log "ERROR" "Vérifiez les logs: docker-compose logs nextcloud"
exit 1
fi
sleep 1
done
# Restaurer la configuration
log "INFO" "Restauration de la configuration..."
if ! docker-compose exec -T -u www-data nextcloud tar -xzf - -C /var/www/html/config < "$BACKUP_DIR/config.tar.gz" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors de la restauration de la configuration"
exit 1
fi
log "INFO" "Configuration restaurée"
# Restaurer les données
if [ -f "$BACKUP_DIR/data.tar.gz" ]; then
log "INFO" "Restauration des données utilisateurs..."
if ! docker-compose exec -T -u www-data nextcloud tar -xzf - -C /var/www/html/data < "$BACKUP_DIR/data.tar.gz" 2>>"$LOG_FILE"; then
log "ERROR" "Erreur lors de la restauration des données"
exit 1
fi
log "INFO" "Données restaurées"
else
log "WARN" "Pas de fichier data.tar.gz trouvé"
fi
# Restaurer les apps personnalisées
if [ -f "$BACKUP_DIR/apps.tar.gz" ]; then
log "INFO" "Restauration des apps personnalisées..."
if docker-compose exec -T -u www-data nextcloud tar -xzf - -C /var/www/html/custom_apps < "$BACKUP_DIR/apps.tar.gz" 2>>"$LOG_FILE"; then
log "INFO" "Apps restaurées"
else
log "WARN" "Erreur lors de la restauration des apps"
fi
else
log "INFO" "Pas d'apps personnalisées à restaurer"
fi
# Désactiver le mode maintenance
log "INFO" "Désactivation du mode maintenance..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE" || log "WARN" "Impossible de désactiver le mode maintenance"
# Réparer et scanner # Réparer et scanner
echo "🔧 Réparation..." log "INFO" "Réparation de l'installation..."
sleep 30 docker-compose exec -T -u www-data nextcloud php occ maintenance:repair 2>>"$LOG_FILE" || log "WARN" "Erreur lors de la réparation"
docker-compose exec -u www-data nextcloud php occ maintenance:repair
docker-compose exec -u www-data nextcloud php occ files:scan --all
# Nettoyer log "INFO" "Scan des fichiers..."
rm -rf "$TEMP_DIR" docker-compose exec -T -u www-data nextcloud php occ files:scan --all 2>>"$LOG_FILE" || log "WARN" "Erreur lors du scan"
echo " Restauration terminée !" log "INFO" "=== Restauration terminée ==="
log "INFO" "Vérifiez que tout fonctionne: make health"

176
scripts/update.sh Normal file → Executable file
View File

@@ -1,47 +1,167 @@
#!/bin/bash #!/bin/bash
# scripts/update.sh - Mise à jour Nextcloud # scripts/update.sh - Mise à jour Nextcloud
set -e set -euo pipefail
echo "🔄 Mise à jour de Nextcloud" # Variables globales
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
# Configuration des logs
LOG_DIR="./logs"
LOG_FILE="$PROJECT_ROOT/logs/update_$(date +%Y%m%d_%H%M%S).log"
MAINTENANCE_ENABLED=false
COMPOSE_BACKUP=""
mkdir -p "$LOG_DIR"
# Charger les fonctions communes (log avec couleurs)
# shellcheck disable=SC1091
source "$SCRIPT_DIR/common.sh"
# Fonction de nettoyage en cas d'erreur
cleanup() {
local exit_code=$?
if [ "$exit_code" -ne 0 ]; then
log "ERROR" "Erreur détectée lors de la mise à jour (code: $exit_code)"
log "WARN" "IMPORTANT: Vérifiez les logs et considérez une restauration si nécessaire"
# Restaurer le docker-compose.yml si backup existe
if [ -n "$COMPOSE_BACKUP" ] && [ -f "$COMPOSE_BACKUP" ]; then
log "INFO" "Restauration du docker-compose.yml..."
cp "$COMPOSE_BACKUP" docker-compose.yml || log "ERROR" "Impossible de restaurer docker-compose.yml"
fi
fi
# Désactiver le mode maintenance si activé
if [ "$MAINTENANCE_ENABLED" = true ]; then
log "INFO" "Tentative de désactivation du mode maintenance..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE" || true
fi
# Nettoyer le backup temporaire
if [ -n "$COMPOSE_BACKUP" ] && [ -f "$COMPOSE_BACKUP" ]; then
rm -f "$COMPOSE_BACKUP"
fi
if [ "$exit_code" -eq 0 ]; then
log "SUCCESS" "Mise à jour terminée avec succès"
else
log "ERROR" "Mise à jour échouée avec code: $exit_code"
fi
exit "$exit_code"
}
trap cleanup EXIT INT TERM
log "INFO" "=== Mise à jour de Nextcloud ==="
log "INFO" "Log file: $LOG_FILE"
# Afficher la version actuelle
log "INFO" "Version actuelle:"
docker-compose exec -T -u www-data nextcloud php occ status 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Impossible d'obtenir le statut actuel"
# Backup avant update # Backup avant update
echo "💾 Backup de sécurité..." log "INFO" "Création du backup de sécurité..."
bash scripts/backup.sh if ! bash scripts/backup.sh 2>&1 | tee -a "$LOG_FILE"; then
log "ERROR" "Erreur lors du backup, abandon de la mise à jour"
exit 1
fi
# Mode maintenance # Sauvegarder le docker-compose.yml
echo "⏸️ Mode maintenance activé" log "INFO" "Sauvegarde de docker-compose.yml..."
docker-compose exec -u www-data nextcloud php occ maintenance:mode --on COMPOSE_BACKUP="/tmp/docker-compose.yml.backup.$$"
cp docker-compose.yml "$COMPOSE_BACKUP" || {
log "ERROR" "Impossible de sauvegarder docker-compose.yml"
exit 1
}
log "INFO" "docker-compose.yml sauvegardé: $COMPOSE_BACKUP"
# Pull nouvelle image # Pull nouvelle image de base et rebuild image custom
echo "📥 Téléchargement de la nouvelle version..." log "INFO" "Téléchargement de la nouvelle version de base..."
docker-compose pull nextcloud if ! docker pull nextcloud:latest 2>&1 | tee -a "$LOG_FILE"; then
log "ERROR" "Erreur lors du téléchargement de l'image de base"
exit 1
fi
log "INFO" "Rebuild de l'image personnalisée (avec ffmpeg)..."
if ! docker-compose build --no-cache nextcloud 2>&1 | tee -a "$LOG_FILE"; then
log "ERROR" "Erreur lors du rebuild de l'image personnalisée"
exit 1
fi
# Mode maintenance avant le restart
log "INFO" "Activation du mode maintenance..."
if docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --on 2>>"$LOG_FILE"; then
MAINTENANCE_ENABLED=true
log "INFO" "Mode maintenance activé"
else
log "ERROR" "Impossible d'activer le mode maintenance"
exit 1
fi
# Restart # Restart
echo "🔄 Redémarrage..." log "INFO" "Redémarrage des services..."
docker-compose up -d --force-recreate nextcloud cron if ! docker-compose up -d --force-recreate nextcloud cron 2>&1 | tee -a "$LOG_FILE"; then
log "ERROR" "Erreur lors du redémarrage"
exit 1
fi
# Attendre que Nextcloud soit prêt # Attendre que Nextcloud soit prêt
echo "Attente du démarrage..." log "INFO" "Attente du démarrage de Nextcloud (max 2 minutes)..."
sleep 30 for i in {1..120}; do
if docker-compose exec -T nextcloud curl -f http://localhost/status.php >/dev/null 2>&1; then
log "INFO" "Nextcloud prêt (${i}s)"
break
fi
if [ "$i" -eq 120 ]; then
log "ERROR" "Timeout: Nextcloud n'est pas prêt après 2 minutes"
log "ERROR" "Vérifiez les logs: docker-compose logs nextcloud"
exit 1
fi
sleep 1
done
# Désactiver temporairement le mode maintenance pour permettre l'upgrade
log "INFO" "Préparation de l'upgrade..."
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE" || true
MAINTENANCE_ENABLED=false
# Upgrade via OCC # Upgrade via OCC
echo "⬆️ Lancement de l'upgrade..." log "INFO" "Lancement de l'upgrade..."
docker-compose exec -u www-data nextcloud php occ upgrade if ! docker-compose exec -T -u www-data nextcloud php occ upgrade 2>&1 | tee -a "$LOG_FILE"; then
log "ERROR" "Erreur lors de l'upgrade"
exit 1
fi
# Scan et indices # Afficher la nouvelle version
echo "🔍 Scan des fichiers..." log "INFO" "Nouvelle version:"
docker-compose exec -u www-data nextcloud php occ files:scan --all docker-compose exec -T -u www-data nextcloud php occ status 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Impossible d'obtenir le nouveau statut"
echo "📊 Ajout des indices manquants..." # Opérations de maintenance post-upgrade (non bloquantes)
docker-compose exec -u www-data nextcloud php occ db:add-missing-indices log "INFO" "Scan des fichiers..."
docker-compose exec -T -u www-data nextcloud php occ files:scan --all 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Erreur lors du scan"
echo "🔧 Conversion des colonnes..." log "INFO" "Ajout des indices manquants..."
docker-compose exec -u www-data nextcloud php occ db:convert-filecache-bigint --no-interaction docker-compose exec -T -u www-data nextcloud php occ db:add-missing-indices 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Erreur lors de l'ajout des indices"
# Désactiver maintenance log "INFO" "Conversion des colonnes BigInt..."
echo "▶️ Désactivation du mode maintenance" docker-compose exec -T -u www-data nextcloud php occ db:convert-filecache-bigint --no-interaction 2>&1 | tee -a "$LOG_FILE" || log "WARN" "Erreur lors de la conversion"
docker-compose exec -u www-data nextcloud php occ maintenance:mode --off
echo "✅ Mise à jour terminée !" # Désactiver le mode maintenance
docker-compose exec -u www-data nextcloud php occ status log "INFO" "Désactivation du mode maintenance..."
if docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off 2>>"$LOG_FILE"; then
MAINTENANCE_ENABLED=false
log "INFO" "Mode maintenance désactivé"
else
log "WARN" "Impossible de désactiver le mode maintenance"
log "WARN" "Exécutez manuellement: make occ maintenance:mode --off"
fi
# Statut final
log "INFO" "=== Mise à jour terminée ==="
log "INFO" "Vérifiez que tout fonctionne: make health"
docker-compose exec -T -u www-data nextcloud php occ status 2>&1 | tee -a "$LOG_FILE" || true