Compare commits
47 Commits
ddc99b914f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc1cac8e5a | ||
|
|
5d610b9177 | ||
|
|
8096d8985b | ||
|
|
8462b10e3b | ||
|
|
6bdd8e918c | ||
|
|
44ec0a004a | ||
|
|
c403419ea1 | ||
|
|
a1b51599c6 | ||
|
|
123f7b6a9c | ||
|
|
f02c9b36b2 | ||
|
|
43517b36cc | ||
|
|
57db8b6111 | ||
|
|
53cc23e153 | ||
|
|
a83426d198 | ||
|
|
6fa7704c13 | ||
|
|
b802c8a5cd | ||
|
|
b3ae8a8622 | ||
|
|
7dcffd2ae0 | ||
|
|
08fdfc3a2e | ||
|
|
51d42c6437 | ||
|
|
bd1e2dca27 | ||
|
|
e055d708a5 | ||
|
|
a7c14f9000 | ||
|
|
01c0db45f5 | ||
|
|
b693ed1364 | ||
|
|
dd27bdebb5 | ||
|
|
fcc60226ca | ||
|
|
fb2a3585d4 | ||
|
|
2ed5314537 | ||
|
|
85ed35923c | ||
|
|
f3c74de015 | ||
|
|
58bc9a47cc | ||
|
|
c6de550329 | ||
|
|
701513ce15 | ||
|
|
256d2632a1 | ||
|
|
03821b5e18 | ||
|
|
b9c6122d4f | ||
|
|
f3655144a7 | ||
|
|
386f731c2b | ||
|
|
2dc57afab4 | ||
|
|
517e337a25 | ||
|
|
dc15b4665d | ||
|
|
a7e6cf402d | ||
|
|
db65cd7ec9 | ||
|
|
764b78a12e | ||
|
|
7c6a42587c | ||
|
|
d0ce7d5185 |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
||||
# Données Nextcloud
|
||||
data/
|
||||
db/
|
||||
backups/
|
||||
logs/
|
||||
|
||||
# Docker
|
||||
docker-compose*.yml
|
||||
.env*
|
||||
|
||||
# Git
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Documentation
|
||||
README.md
|
||||
*.md
|
||||
49
.env.example
49
.env.example
@@ -1,11 +1,44 @@
|
||||
MYSQL_DATABASE=
|
||||
MYSQL_ROOT_USER=
|
||||
MYSQL_ROOT_PASSWORD=
|
||||
MYSQL_USER=
|
||||
MYSQL_PASSWORD=
|
||||
# ============================================
|
||||
# MODE: dev | prod
|
||||
# ============================================
|
||||
# Copiez ce fichier vers .env et changez les valeurs
|
||||
|
||||
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=
|
||||
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
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.env
|
||||
data/
|
||||
db/
|
||||
backups/
|
||||
logs/
|
||||
|
||||
7
Dockerfile
Normal file
7
Dockerfile
Normal 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/*
|
||||
151
Makefile
151
Makefile
@@ -1,32 +1,94 @@
|
||||
.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:
|
||||
@echo "Nextcloud Docker - Commandes disponibles:"
|
||||
@echo " make up - Démarrer les services"
|
||||
@echo " make down - Arrêter les services"
|
||||
@echo " make restart - Redémarrer"
|
||||
@echo " make logs - Voir les logs"
|
||||
@echo " make ps - Status des containers"
|
||||
@echo " make occ - Lancer une commande occ"
|
||||
@echo " make backup - Backup complet"
|
||||
@echo " make restore - Restaurer un backup"
|
||||
@echo " make update - Mettre à jour Nextcloud"
|
||||
@echo " make health - Vérifier la santé du système"
|
||||
@echo ""
|
||||
@echo "Services:"
|
||||
@echo " make up - Démarrer tous les services Docker"
|
||||
@echo " make down - Arrêter et supprimer les containers"
|
||||
@echo " make restart - Redémarrer tous les services"
|
||||
@echo " make ps - Lister les containers actifs"
|
||||
@echo " make logs - Afficher les logs Nextcloud en temps réel"
|
||||
@echo " make logs-all - Afficher les logs de tous les containers"
|
||||
@echo ""
|
||||
@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:
|
||||
docker-compose up -d
|
||||
$(DOCKER_COMPOSE) up -d
|
||||
|
||||
down:
|
||||
docker-compose down
|
||||
$(DOCKER_COMPOSE) down
|
||||
|
||||
restart:
|
||||
docker-compose restart
|
||||
$(DOCKER_COMPOSE) restart
|
||||
|
||||
logs:
|
||||
docker-compose logs -f --tail=100 nextcloud
|
||||
$(DOCKER_COMPOSE) logs -f --tail=100 nextcloud
|
||||
|
||||
logs-all:
|
||||
$(DOCKER_COMPOSE) logs -f --tail=50
|
||||
|
||||
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:
|
||||
@bash scripts/occ.sh $(filter-out $@,$(MAKECMDGOALS))
|
||||
@@ -35,12 +97,61 @@ backup:
|
||||
@bash scripts/backup.sh
|
||||
|
||||
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:
|
||||
@bash scripts/update.sh
|
||||
|
||||
health:
|
||||
@docker-compose exec nextcloud php occ status
|
||||
@docker-compose exec nextcloud php occ config:list system
|
||||
@docker-compose exec db mysql -u$$MYSQL_USER -p$$MYSQL_PASSWORD -e "SELECT 1"
|
||||
@bash scripts/check-health.sh
|
||||
|
||||
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
665
README.md
Normal 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
227
SECURITY.md
Normal 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
16
apache/mpm_prefork.conf
Normal 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
48
apache/nextcloud.conf
Normal 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
24
cron/Dockerfile
Normal 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
147
cron/README.md
Normal 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
11
cron/crontab
Normal 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
18
cron/entrypoint.sh
Executable 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
|
||||
@@ -13,3 +13,6 @@ binlog_format = ROW
|
||||
|
||||
# Connections
|
||||
max_connections = 200
|
||||
|
||||
# Gros fichiers - augmenter la taille max des paquets
|
||||
max_allowed_packet = 1G
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
services:
|
||||
nextcloud:
|
||||
image: nextcloud:latest
|
||||
container_name: nextcloud
|
||||
build: .
|
||||
image: nextcloud-custom:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8888:80"
|
||||
volumes:
|
||||
- ./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:
|
||||
# Database
|
||||
- MYSQL_HOST=db
|
||||
@@ -15,21 +24,25 @@ services:
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||
# Domaine
|
||||
- NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN}
|
||||
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-172.16.0.0/12}
|
||||
- OVERWRITEPROTOCOL=https
|
||||
- OVERWRITEHOST=${NEXTCLOUD_DOMAIN}
|
||||
- OVERWRITECLIURL=https://${NEXTCLOUD_DOMAIN}
|
||||
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
|
||||
- OVERWRITEPROTOCOL=${OVERWRITE_PROTOCOL:-http}
|
||||
- OVERWRITEHOST=${OVERWRITE_HOST:-}
|
||||
- OVERWRITECLIURL=${OVERWRITE_CLI_URL:-}
|
||||
# Redis
|
||||
- REDIS_HOST=${REDIS_HOST}
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_HOST_PASSWORD=${REDIS_HOST_PASSWORD}
|
||||
# PHP
|
||||
- PHP_MEMORY_LIMIT=4096M
|
||||
- PHP_UPLOAD_MAX_FILESIZE=2G
|
||||
- PHP_POST_MAX_SIZE=2G
|
||||
- PHP_MAX_EXECUTION_TIME=1800
|
||||
- PHP_MAX_INPUT_TIME=1800
|
||||
- PHP_UPLOAD_MAX_FILESIZE=10G
|
||||
- PHP_POST_MAX_SIZE=10G
|
||||
- PHP_MAX_EXECUTION_TIME=7200
|
||||
- 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_BODY_LIMIT=2147483648
|
||||
- APACHE_BODY_LIMIT=0
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/status.php"]
|
||||
interval: 30s
|
||||
@@ -43,16 +56,32 @@ services:
|
||||
networks:
|
||||
- nextcloud-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:
|
||||
image: redis:alpine
|
||||
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:
|
||||
- nextcloud-net
|
||||
|
||||
cron:
|
||||
image: nextcloud:latest
|
||||
image: nextcloud-custom:latest
|
||||
restart: always
|
||||
volumes_from:
|
||||
- nextcloud
|
||||
@@ -64,6 +93,28 @@ services:
|
||||
networks:
|
||||
- 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:
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
@@ -71,7 +122,7 @@ services:
|
||||
- ./db:/var/lib/mysql
|
||||
- ./db-config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_USER}
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||
- MYSQL_DATABASE=nextcloud
|
||||
- MYSQL_USER=${MYSQL_USER}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||
|
||||
282
scripts/backup.sh
Normal file → Executable file
282
scripts/backup.sh
Normal file → Executable file
@@ -1,75 +1,267 @@
|
||||
#!/bin/bash
|
||||
# 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
|
||||
set +a
|
||||
|
||||
BACKUP_DIR="${BACKUP_DESTINATION:-./backups}"
|
||||
# Configuration
|
||||
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_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
|
||||
mkdir -p "$BACKUP_PATH"
|
||||
|
||||
# 1. Activer le mode maintenance
|
||||
echo "⏸️ Activation du mode maintenance..."
|
||||
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --on
|
||||
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
|
||||
|
||||
# 2. Backup de la base de données
|
||||
echo "💾 Backup de la base de données..."
|
||||
docker-compose exec -T db mysqldump \
|
||||
-u"$MYSQL_USER" \
|
||||
-p"$MYSQL_PASSWORD" \
|
||||
"$MYSQL_DATABASE" \
|
||||
log "INFO" "Backup de la base de données..."
|
||||
START_TIME=$(date +%s)
|
||||
if ! docker-compose exec -T db sh -c "MYSQL_PWD=\"\$MYSQL_PASSWORD\" mysqldump \
|
||||
-u\"\$MYSQL_USER\" \
|
||||
\"\$MYSQL_DATABASE\" \
|
||||
--single-transaction \
|
||||
--quick \
|
||||
--lock-tables=false \
|
||||
> "$BACKUP_PATH/database.sql"
|
||||
--lock-tables=false" >"$BACKUP_PATH/database.sql" 2>>"$LOG_FILE"; then
|
||||
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
|
||||
echo "⚙️ Backup de la configuration..."
|
||||
tar -czf "$BACKUP_PATH/config.tar.gz" \
|
||||
-C ./data/config .
|
||||
log "INFO" "Backup de la configuration..."
|
||||
START_TIME=$(date +%s)
|
||||
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)
|
||||
echo "📁 Backup des données utilisateurs..."
|
||||
# Pour un backup incrémental, utilisez rsync
|
||||
rsync -a --info=progress2 \
|
||||
./data/data/ \
|
||||
"$BACKUP_PATH/data/" \
|
||||
--exclude 'appdata_*/preview' \
|
||||
--exclude '*/cache' \
|
||||
--exclude '*/thumbnails'
|
||||
# 4. Backup des données utilisateurs
|
||||
log "INFO" "Backup des données utilisateurs..."
|
||||
START_TIME=$(date +%s)
|
||||
if ! docker-compose exec -T -u www-data nextcloud tar -czf - \
|
||||
-C /var/www/html/data \
|
||||
--exclude='appdata_*/preview' \
|
||||
--exclude='*/cache' \
|
||||
--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):
|
||||
# tar -czf "$BACKUP_PATH/data.tar.gz" \
|
||||
# --exclude='appdata_*/preview' \
|
||||
# -C ./data/data .
|
||||
|
||||
# 5. Backup des apps
|
||||
echo "📦 Backup des apps personnalisées..."
|
||||
if [ -d "./data/custom_apps" ]; then
|
||||
tar -czf "$BACKUP_PATH/apps.tar.gz" \
|
||||
-C ./data/custom_apps .
|
||||
# 5. Backup des apps personnalisées
|
||||
log "INFO" "Backup des apps personnalisées..."
|
||||
if docker-compose exec -T nextcloud [ -d /var/www/html/custom_apps ] 2>>"$LOG_FILE"; then
|
||||
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
|
||||
APPS_SIZE=$(du -h "$BACKUP_PATH/apps.tar.gz" | cut -f1)
|
||||
log "INFO" "Apps sauvegardées: $APPS_SIZE"
|
||||
else
|
||||
log "WARN" "Erreur lors du backup des apps personnalisées"
|
||||
fi
|
||||
else
|
||||
log "INFO" "Pas d'apps personnalisées à sauvegarder"
|
||||
fi
|
||||
|
||||
# 6. Désactiver le mode maintenance
|
||||
echo "▶️ Désactivation du mode maintenance..."
|
||||
docker-compose exec -T -u www-data nextcloud php occ maintenance:mode --off
|
||||
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"
|
||||
fi
|
||||
|
||||
# 7. Créer une archive complète
|
||||
echo "🗜️ Compression finale..."
|
||||
cd "$BACKUP_DIR"
|
||||
tar -czf "$BACKUP_NAME.tar.gz" "$BACKUP_NAME/"
|
||||
rm -rf "$BACKUP_NAME"
|
||||
log "INFO" "Compression finale..."
|
||||
START_TIME=$(date +%s)
|
||||
if ! tar -czf "$BACKUP_DIR/$BACKUP_NAME.tar.gz" -C "$BACKUP_DIR" "$BACKUP_NAME/" 2>>"$LOG_FILE"; then
|
||||
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
|
||||
echo "🧹 Nettoyage des backups > ${BACKUP_RETENTION_DAYS:-30} jours..."
|
||||
find "$BACKUP_DIR" -name "nextcloud_backup_*.tar.gz" -mtime +${BACKUP_RETENTION_DAYS:-30} -delete
|
||||
# 8. Générer le checksum SHA256
|
||||
log "INFO" "Génération du checksum SHA256..."
|
||||
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"
|
||||
du -h "$BACKUP_DIR/$BACKUP_NAME.tar.gz"
|
||||
# Supprimer le dossier temporaire après compression réussie
|
||||
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
283
scripts/check-health.sh
Executable 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
26
scripts/clean-old-logs.sh
Executable 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
33
scripts/common.sh
Normal 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
25
scripts/occ.sh
Normal file → Executable file
@@ -1,6 +1,27 @@
|
||||
#!/bin/bash
|
||||
# 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
97
scripts/recover.sh
Executable 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é"
|
||||
299
scripts/restore.sh
Normal file → Executable file
299
scripts/restore.sh
Normal file → Executable file
@@ -1,70 +1,277 @@
|
||||
#!/bin/bash
|
||||
# scripts/restore.sh - Restauration d'un backup
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <backup_file.tar.gz>"
|
||||
# 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
|
||||
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
|
||||
fi
|
||||
|
||||
BACKUP_FILE="$1"
|
||||
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
echo "❌ Fichier introuvable: $BACKUP_FILE"
|
||||
# Valider le chemin du fichier (éviter path traversal)
|
||||
if [[ "$BACKUP_FILE" =~ \.\. ]] || [[ "$BACKUP_FILE" == /* && ! "$BACKUP_FILE" =~ ^/home/ && ! "$BACKUP_FILE" =~ ^/tmp/ ]]; then
|
||||
log "ERROR" "Chemin de fichier invalide ou non autorisé"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "⚠️ ATTENTION: Cette opération va écraser les données actuelles !"
|
||||
read -p "Continuer? (yes/no): " confirm
|
||||
# Résoudre le chemin absolu
|
||||
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
|
||||
echo "Annulé."
|
||||
log "INFO" "Restauration annulée"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extraire le backup
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
echo "📂 Extraction vers $TEMP_DIR..."
|
||||
tar -xzf "$BACKUP_FILE" -C "$TEMP_DIR"
|
||||
# Fonction de nettoyage
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
|
||||
BACKUP_DIR=$(ls -1 "$TEMP_DIR" | head -n1)
|
||||
|
||||
# Arrêter les services
|
||||
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
|
||||
if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then
|
||||
log "INFO" "Nettoyage du répertoire temporaire..."
|
||||
rm -rf "${TEMP_DIR:?}"
|
||||
fi
|
||||
|
||||
# Redémarrer
|
||||
echo "▶️ Redémarrage des services..."
|
||||
docker-compose up -d
|
||||
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
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
log "INFO" "Extraction vers $TEMP_DIR..."
|
||||
|
||||
if ! tar -xzf "$BACKUP_FILE" -C "$TEMP_DIR" 2>>"$LOG_FILE"; then
|
||||
log "ERROR" "Erreur lors de l'extraction"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Trouver le répertoire de backup
|
||||
BACKUP_DIR=$(find "$TEMP_DIR" -mindepth 1 -maxdepth 1 -type d | head -n1)
|
||||
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
|
||||
echo "🔧 Réparation..."
|
||||
sleep 30
|
||||
docker-compose exec -u www-data nextcloud php occ maintenance:repair
|
||||
docker-compose exec -u www-data nextcloud php occ files:scan --all
|
||||
log "INFO" "Réparation de l'installation..."
|
||||
docker-compose exec -T -u www-data nextcloud php occ maintenance:repair 2>>"$LOG_FILE" || log "WARN" "Erreur lors de la réparation"
|
||||
|
||||
# Nettoyer
|
||||
rm -rf "$TEMP_DIR"
|
||||
log "INFO" "Scan des fichiers..."
|
||||
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
176
scripts/update.sh
Normal file → Executable file
@@ -1,47 +1,167 @@
|
||||
#!/bin/bash
|
||||
# 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
|
||||
echo "💾 Backup de sécurité..."
|
||||
bash scripts/backup.sh
|
||||
log "INFO" "Création du backup de sécurité..."
|
||||
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
|
||||
echo "⏸️ Mode maintenance activé"
|
||||
docker-compose exec -u www-data nextcloud php occ maintenance:mode --on
|
||||
# Sauvegarder le docker-compose.yml
|
||||
log "INFO" "Sauvegarde de docker-compose.yml..."
|
||||
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
|
||||
echo "📥 Téléchargement de la nouvelle version..."
|
||||
docker-compose pull nextcloud
|
||||
# Pull nouvelle image de base et rebuild image custom
|
||||
log "INFO" "Téléchargement de la nouvelle version de base..."
|
||||
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
|
||||
echo "🔄 Redémarrage..."
|
||||
docker-compose up -d --force-recreate nextcloud cron
|
||||
log "INFO" "Redémarrage des services..."
|
||||
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
|
||||
echo "⏳ Attente du démarrage..."
|
||||
sleep 30
|
||||
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" "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
|
||||
echo "⬆️ Lancement de l'upgrade..."
|
||||
docker-compose exec -u www-data nextcloud php occ upgrade
|
||||
log "INFO" "Lancement de l'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
|
||||
echo "🔍 Scan des fichiers..."
|
||||
docker-compose exec -u www-data nextcloud php occ files:scan --all
|
||||
# Afficher la nouvelle version
|
||||
log "INFO" "Nouvelle version:"
|
||||
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..."
|
||||
docker-compose exec -u www-data nextcloud php occ db:add-missing-indices
|
||||
# Opérations de maintenance post-upgrade (non bloquantes)
|
||||
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..."
|
||||
docker-compose exec -u www-data nextcloud php occ db:convert-filecache-bigint --no-interaction
|
||||
log "INFO" "Ajout des indices manquants..."
|
||||
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
|
||||
echo "▶️ Désactivation du mode maintenance"
|
||||
docker-compose exec -u www-data nextcloud php occ maintenance:mode --off
|
||||
log "INFO" "Conversion des colonnes BigInt..."
|
||||
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"
|
||||
|
||||
echo "✅ Mise à jour terminée !"
|
||||
docker-compose exec -u www-data nextcloud php occ status
|
||||
# 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
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user