Skip to main content

Bookstack déploiement

# Déploiement de BookStack avec Podman Compose

## Contexte
Déploiement d'un wiki BookStack sur VPS AlmaLinux 10 avec Podman (au lieu de Docker), Nginx comme reverse proxy, et nftables comme firewall.

---

## Architecture finale
```
Internet → Nginx (443) → Podman (localhost:30080) → BookStack → MariaDB
                ↓
           Let's Encrypt SSL
```

- **BookStack** : Wiki de documentation
- **MariaDB** : Base de données
- **Nginx** : Reverse proxy avec SSL
- **Podman** : Alternative à Docker (rootless, sans daemon)

---

## Prérequis
```bash
# Installer Podman et podman-compose
sudo dnf install podman podman-compose -y

# Vérifier l'installation
podman --version
podman-compose --version
```

---

## Problèmes rencontrés et solutions

### 1. ❌ Tentative initiale : Kubernetes (K3s)

**Problème** : Communication réseau entre pods impossible
- **Erreur** : `SQLSTATE[HY000] [2002] No such file or directory`
- **Cause** : Module kernel `nf_conntrack` manquant
- **Erreur K3s** : `Extension conntrack is not supported, missing kernel module?`

**Tentative de solution** :
```bash
sudo modprobe nf_conntrack
sudo modprobe br_netfilter  # Module non disponible sur AlmaLinux 10
```

**Décision** : Abandon de K3s au profit de Podman Compose (plus simple, moins de ressources)

---

### 2. ❌ Problème : Communication réseau entre containers Podman

**Erreur** : `nc: getaddrinfo for host "bookstack-mariadb" port 3306: Try again`

**Cause** : nftables bloque le trafic entre containers

**Solution** : Ajouter des règles nftables pour autoriser le subnet Podman
```bash
# Trouver le subnet Podman
podman network inspect bookstack_default | grep -i subnet
# Exemple de résultat : 10.89.0.0/24

# Ajouter les règles nftables
sudo nft add rule inet filter input ip saddr 10.89.0.0/24 accept
sudo nft add rule inet filter forward ip saddr 10.89.0.0/24 accept
sudo nft add rule inet filter forward ip daddr 10.89.0.0/24 accept

# Sauvegarder
sudo nft list ruleset | sudo tee /etc/nftables/ruleset.nft
```

**Note importante** : Docker et nftables ont des conflits connus. Podman gère mieux nftables mais nécessite quand même des règles explicites.

---

### 3. ❌ Problème : Erreurs d'authentification MariaDB

**Erreur** : `ERROR 1045 (28000): Access denied for user 'bookstack'@'10.89.0.5' (using password: YES)`

**Causes multiples** :
1. Volumes persistants gardant les anciens mots de passe
2. Incohérence entre `MYSQL_USER` et `DB_USERNAME`
3. Caractères spéciaux (`!`) mal échappés dans les mots de passe

**Solution finale** :
```bash
# 1. Arrêter et supprimer complètement les volumes
cd ~/bookstack
podman-compose down
podman volume rm -f bookstack_bookstack-db-data bookstack_bookstack-config

# 2. Vérifier que les volumes sont supprimés
podman volume ls | grep bookstack

# 3. Utiliser des mots de passe simples (sans caractères spéciaux)
# Voir docker-compose.yml ci-dessous
```

---

### 4. ❌ Problème : APP_KEY manquant

**Erreur** : `The application key is missing, halting init!`

**Solution** : Générer et ajouter l'APP_KEY
```bash
# Générer la clé
APP_KEY=$(podman run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey | tr -d '\r')

# Afficher pour vérification
echo "APP_KEY: $APP_KEY"

# L'ajouter dans docker-compose.yml sous environment de bookstack
```

---

### 5. ❌ Problème : Certificat SSL ne couvre pas wiki.sanjyasz.pro

**Erreur** : `SSL: no alternative certificate subject name matches target hostname`

**Solution** : Étendre le certificat existant
```bash
sudo certbot certonly --nginx \
  -d sanjyasz.pro \
  -d www.sanjyasz.pro \
  -d jenkins.sanjyasz.pro \
  -d wiki.sanjyasz.pro \
  --expand
```

**Alternative** : Certificat wildcard (recommandé pour plusieurs sous-domaines)
```bash
sudo certbot certonly --manual --preferred-challenges dns \
  -d "*.sanjyasz.pro" -d "sanjyasz.pro"
```

---

## Configuration finale qui fonctionne

### Structure des dossiers
```
~/bookstack/
├── docker-compose.yml
```

### docker-compose.yml
```yaml
version: '3.8'

services:
  bookstack-db:
    image: mariadb:10.11
    container_name: bookstack-db
    environment:
      MYSQL_ROOT_PASSWORD: RootPassword123
      MYSQL_DATABASE: bookstack
      MYSQL_USER: bookstack
      MYSQL_PASSWORD: BookStackPass123
    volumes:
      - bookstack-db-data:/var/lib/mysql
    restart: unless-stopped

  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
      PUID: 1000
      PGID: 1000
      TZ: Europe/Paris
      APP_URL: https://wiki.sanjyasz.pro
      DB_HOST: bookstack-db
      DB_PORT: 3306
      DB_DATABASE: bookstack
      DB_USERNAME: bookstack
      DB_PASSWORD: BookStackPass123
      APP_KEY: base64:VOTRE_CLE_GENEREE_ICI
    volumes:
      - bookstack-config:/config
    ports:
      - "30080:80"
    depends_on:
      - bookstack-db
    restart: unless-stopped

volumes:
  bookstack-db-data:
  bookstack-config:
```

**Points importants** :
- Pas de guillemets autour des variables (évite les problèmes d'échappement)
- Mots de passe simples sans caractères spéciaux
- `depends_on` assure que MariaDB démarre avant BookStack
- Port 30080 choisi pour éviter les conflits

---

### Configuration Nginx

**Fichier** : `/etc/nginx/conf.d/wiki.conf`
```nginx
server {
    listen 80;
    listen [::]:80;
    server_name wiki.sanjyasz.pro;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name wiki.sanjyasz.pro;

    ssl_certificate /etc/letsencrypt/live/sanjyasz.pro/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sanjyasz.pro/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    add_header Strict-Transport-Security "max-age=31536000" always;

    location / {
        proxy_pass http://localhost:30080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Important pour les uploads de fichiers
        client_max_body_size 100M;
    }
}
```

**Appliquer la configuration** :
```bash
sudo nginx -t
sudo systemctl reload nginx
```

**SELinux** : Autoriser Nginx à se connecter au réseau
```bash
sudo setsebool -P httpd_can_network_connect 1
```

---

## Déploiement complet - Procédure pas à pas

### 1. Préparation
```bash
# Créer le dossier
mkdir -p ~/bookstack
cd ~/bookstack

# Créer le docker-compose.yml (voir ci-dessus)
nano docker-compose.yml
```

### 2. Générer l'APP_KEY
```bash
APP_KEY=$(podman run --rm --entrypoint /bin/bash lscr.io/linuxserver/bookstack:latest appkey | tr -d '\r')
echo "APP_KEY généré: $APP_KEY"

# Éditer docker-compose.yml et remplacer APP_KEY
nano docker-compose.yml
```

### 3. Configuration DNS (OVH)

Ajouter un enregistrement A :
```
Type: A
Sous-domaine: wiki
Cible: [IP du VPS]
TTL: 3600
```

### 4. Règles firewall nftables
```bash
# Trouver le subnet après le premier lancement
podman-compose up -d
SUBNET=$(podman network inspect bookstack_default | grep -i subnet | awk '{print $2}' | tr -d '",')

# Ajouter les règles
sudo nft add rule inet filter input ip saddr $SUBNET accept
sudo nft add rule inet filter forward ip saddr $SUBNET accept
sudo nft add rule inet filter forward ip daddr $SUBNET accept

# Sauvegarder
sudo nft list ruleset | sudo tee /etc/nftables/ruleset.nft
```

### 5. Lancer BookStack
```bash
cd ~/bookstack
podman-compose up -d

# Vérifier les logs
podman-compose logs -f
```

Attendre 30 secondes que MariaDB s'initialise complètement.

### 6. Vérifier le bon fonctionnement
```bash
# Vérifier les containers
podman-compose ps

# Tester la connexion réseau
podman exec -it bookstack nc -zv bookstack-db 3306

# Tester l'accès web
curl http://localhost:30080
```

### 7. Configuration Nginx et SSL
```bash
# Créer la config Nginx
sudo nano /etc/nginx/conf.d/wiki.conf
# (Voir configuration ci-dessus)

# Étendre le certificat SSL
sudo certbot certonly --nginx \
  -d sanjyasz.pro \
  -d www.sanjyasz.pro \
  -d jenkins.sanjyasz.pro \
  -d wiki.sanjyasz.pro \
  --expand

# Recharger Nginx
sudo nginx -t
sudo systemctl reload nginx
```

### 8. Première connexion

1. Accéder à `https://wiki.sanjyasz.pro`
2. Se connecter avec :
   - Email: `admin@admin.com`
   - Password: `password`
3. **Changer immédiatement le mot de passe !**

---

## Commandes de gestion quotidienne
```bash
# Démarrer
cd ~/bookstack
podman-compose up -d

# Arrêter
podman-compose down

# Redémarrer
podman-compose restart

# Voir les logs
podman-compose logs -f bookstack
podman-compose logs -f bookstack-db

# Voir le statut
podman-compose ps

# Mettre à jour les images
podman-compose pull
podman-compose up -d --force-recreate
```

---

## Backup et restauration

### Backup de la base de données
```bash
# Backup automatique
podman exec bookstack-db mysqldump -u bookstack -pBookStackPass123 bookstack > backup-$(date +%Y%m%d).sql

# Ou avec root
podman exec bookstack-db mysqldump -u root -pRootPassword123 --all-databases > backup-full-$(date +%Y%m%d).sql
```

### Backup des fichiers BookStack
```bash
# Les fichiers sont dans le volume bookstack-config
podman volume inspect bookstack_bookstack-config

# Backup du volume
sudo tar -czf bookstack-config-backup-$(date +%Y%m%d).tar.gz \
  $(podman volume inspect bookstack_bookstack-config -f '{{.Mountpoint}}')
```

### Restauration
```bash
# Restaurer la base de données
cat backup-20241122.sql | podman exec -i bookstack-db mysql -u root -pRootPassword123 bookstack

# Restaurer les fichiers
sudo tar -xzf bookstack-config-backup-20241122.tar.gz -C /
```

---

## Troubleshooting

### Les containers ne démarrent pas
```bash
# Vérifier les logs
podman-compose logs

# Vérifier les volumes
podman volume ls

# Supprimer et recréer
podman-compose down
podman volume rm bookstack_bookstack-db-data bookstack_bookstack-config
podman-compose up -d
```

### Erreur d'authentification MariaDB

**Solution** : Supprimer complètement les volumes et recréer
```bash
podman-compose down
podman volume rm -f bookstack_bookstack-db-data bookstack_bookstack-config
podman-compose up -d
```

### Erreur 502 Bad Gateway sur Nginx
```bash
# Vérifier que BookStack tourne
podman-compose ps

# Vérifier SELinux
sudo setsebool -P httpd_can_network_connect 1

# Vérifier les logs Nginx
sudo tail -f /var/log/nginx/error.log
```

### Problème de réseau entre containers
```bash
# Vérifier les règles nftables
sudo nft list ruleset | grep 10.89

# Tester la connexion
podman exec -it bookstack ping bookstack-db
podman exec -it bookstack nc -zv bookstack-db 3306
```

---

## Améliorations possibles

### 1. Service systemd pour auto-start
```bash
cd ~/bookstack
podman generate systemd --new --files --name bookstack
mkdir -p ~/.config/systemd/user/
mv *.service ~/.config/systemd/user/
systemctl --user enable container-bookstack.service
loginctl enable-linger $USER
```

### 2. Backups automatiques avec cron
```bash
# Éditer crontab
crontab -e

# Ajouter backup quotidien à 2h du matin
0 2 * * * cd ~/bookstack && podman exec bookstack-db mysqldump -u root -pRootPassword123 bookstack > ~/backups/bookstack-$(date +\%Y\%m\%d).sql
```

### 3. Monitoring

Intégrer BookStack dans Prometheus/Grafana pour surveiller :
- Uptime des containers
- Utilisation CPU/RAM
- Taille de la base de données

---

## Leçons apprises

1. **Kubernetes (K3s) est overkill pour un seul service** : Podman Compose est plus simple et consomme moins de ressources

2. **nftables et containers nécessitent des règles explicites** : Contrairement à iptables, nftables ne crée pas automatiquement les règles pour les containers

3. **Les volumes Podman persistent même après `podman-compose down`** : Toujours supprimer explicitement les volumes pour repartir à zéro

4. **Les caractères spéciaux dans les variables d'environnement causent des problèmes** : Utiliser des mots de passe alphanumériques simples dans docker-compose.yml

5. **SELinux doit être configuré pour Nginx → Containers** : `httpd_can_network_connect` est essentiel

6. **Let's Encrypt ne renouvelle que les domaines dans le certificat** : Utiliser `--expand` pour ajouter de nouveaux sous-domaines

---

## Ressources

- [BookStack Documentation](https://www.bookstackapp.com/docs/)
- [Podman Documentation](https://docs.podman.io/)
- [LinuxServer.io BookStack Image](https://docs.linuxserver.io/images/docker-bookstack)
- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)

---

## Changelog

- **2024-11-22** : Déploiement initial avec Podman Compose
  - Abandon de K3s pour Podman
  - Configuration nftables pour communication inter-containers
  - Résolution problèmes authentification MariaDB
  - Configuration SSL avec Let's Encrypt

---

**Déployé sur** : VPS OVH - AlmaLinux 10  
**URL** : https://wiki.sanjyasz.pro  
**Auteur** : Sanjy Andriamiseza