# Installation sous RHEL / Oracle Linux — Apache + PHP-FPM

Guide de déploiement sur Red Hat Enterprise Linux (RHEL 8/9) ou Oracle
Linux avec Apache 2.4 et PHP-FPM 8.2.

---

## Table des matières

1. [Prérequis](#1-prérequis)
2. [Installation des paquets](#2-installation-des-paquets)
3. [Configuration de PHP-FPM](#3-configuration-de-php-fpm)
4. [Configuration d'Apache](#4-configuration-dapache)
5. [Oracle Instant Client et OCI8](#5-oracle-instant-client-et-oci8)
6. [Déploiement de l'application](#6-déploiement-de-lapplication)
7. [Permissions et SELinux](#7-permissions-et-selinux)
8. [Démarrage et activation des services](#8-démarrage-et-activation-des-services)
9. [Vérification](#9-vérification)
10. [Pare-feu](#10-pare-feu)
11. [HTTPS avec TLS](#11-https-avec-tls)
12. [Maintenance](#12-maintenance)

---

## 1. Prérequis

| Composant | Version | Notes |
|---|---|---|
| RHEL / Oracle Linux | 8.x ou 9.x | Rocky Linux, AlmaLinux compatibles |
| Apache HTTPD | 2.4.x | Paquet `httpd` |
| PHP | 8.2.x | Via le module stream `php:8.2` (RHEL 9) ou Remi |
| Oracle Instant Client | 19c+ | Requis pour le module Oracle |
| Git | 2.x | Optionnel — clonage du dépôt (non requis si déploiement par ZIP) |
| SELinux | enforcing | Configuration spécifique documentée |

---

## 2. Installation des paquets

### RHEL 9 / Oracle Linux 9 — serveur connecté

```bash
# Activer le module PHP 8.2
sudo dnf module reset php
sudo dnf module enable php:8.2

# Installer Apache, PHP-FPM et les extensions requises
sudo dnf install -y \
    httpd \
    php-fpm \
    php-cli \
    php-common \
    php-mbstring \
    php-gd \
    php-ldap \
    php-zip \
    php-sodium \
    php-process \
    php-xml
```

### RHEL 8 — serveur connecté (via le dépôt Remi)

```bash
# Installer le dépôt Remi
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm

# Activer PHP 8.2
sudo dnf module reset php
sudo dnf module enable php:remi-8.2

# Installer les paquets
sudo dnf install -y \
    httpd \
    php-fpm \
    php-cli \
    php-common \
    php-mbstring \
    php-gd \
    php-ldap \
    php-zip \
    php-sodium \
    php-process \
    php-xml
```

### Serveur hors ligne (sans accès Internet)

Si le serveur cible n'a pas accès à Internet, préparer les RPM sur une
machine connectée de même version RHEL/OL, puis les transférer.

**Sur la machine connectée** — télécharger les RPM et leurs dépendances :

```bash
# Créer un répertoire pour les paquets
mkdir -p /tmp/rpms-app && cd /tmp/rpms-app

# Télécharger tous les RPM (avec dépendances) sans les installer
sudo dnf download --resolve --destdir . \
    httpd \
    php-fpm php-cli php-common php-mbstring php-gd \
    php-ldap php-zip php-sodium php-process php-xml

# Télécharger Oracle Instant Client si nécessaire
sudo dnf download --resolve --destdir . \
    oracle-instantclient-basic oracle-instantclient-devel

# Archiver pour le transfert
tar czf rpms-app.tar.gz *.rpm
```

Pour l'extension OCI8 (PECL), télécharger le `.tgz` manuellement :

```bash
# Depuis https://pecl.php.net/package/oci8
wget https://pecl.php.net/get/oci8-3.3.0.tgz
```

**Sur le serveur cible** — installer depuis les RPM locaux :

```bash
# Transférer rpms-app.tar.gz et oci8-3.3.0.tgz sur le serveur
scp rpms-app.tar.gz oci8-3.3.0.tgz user@serveur:/tmp/

# Sur le serveur
cd /tmp && tar xzf rpms-app.tar.gz

# Installer les RPM locaux
sudo dnf install -y /tmp/*.rpm

# Installer OCI8 depuis le .tgz local (nécessite php-devel + gcc)
sudo pecl install /tmp/oci8-3.3.0.tgz
# Prompt: instantclient,/usr/lib/oracle/19.25/client64/lib

echo "extension=oci8.so" | sudo tee /etc/php.d/30-oci8.ini
```

> **Astuce** : si `php-devel` et `gcc` ne sont pas disponibles sur le
> serveur cible, compiler `oci8.so` sur la machine connectée et copier
> le `.so` résultant directement dans le répertoire d'extensions PHP
> (`php -i | grep extension_dir`).

### Vérification

```bash
php -v          # PHP 8.2.x
php -m          # Doit inclure : mbstring, gd, ldap, zip, sodium, sqlite3
httpd -v        # Apache/2.4.x
```

> **sqlite3** est inclus dans `php-common` sous RHEL. **Ne pas installer
> `php-pdo`** : l'application utilise l'extension native `SQLite3`, pas PDO.

---

## 3. Configuration de PHP-FPM

### Pool principal

Éditer `/etc/php-fpm.d/www.conf` :

```ini
[www]
; Exécuter sous le même utilisateur qu'Apache
user = apache
group = apache

; Socket Unix (plus performant que TCP)
listen = /run/php-fpm/www.sock
listen.owner = apache
listen.group = apache
listen.mode = 0660

; Gestion des processus
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

; Environnement Oracle (si Instant Client installé)
; Décommenter et ajuster le chemin après installation d'Instant Client
;env[LD_LIBRARY_PATH] = /usr/lib/oracle/19.25/client64/lib
;env[ORACLE_HOME]     = /usr/lib/oracle/19.25/client64
;env[TNS_ADMIN]       = /usr/lib/oracle/19.25/client64/network/admin
```

### php.ini

Éditer `/etc/php.ini` :

```ini
; Fuseau horaire
date.timezone = Europe/Paris

; Encodage
default_charset = "UTF-8"

; Taille des uploads (pour les mises à jour ZIP et les wallets)
upload_max_filesize = 64M
post_max_size = 72M

; Mémoire
memory_limit = 256M

; Sessions
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.use_strict_mode = 1

; Journalisation des erreurs (pas d'affichage)
display_errors = Off
log_errors = On
error_log = /var/log/php-fpm/error.log

; Désactiver les fonctions dangereuses (optionnel, renforcement)
; disable_functions = exec,passthru,shell_exec,system,proc_open,popen
```

---

## 4. Configuration d'Apache

### Activer le proxy FastCGI

```bash
# Vérifier que les modules proxy sont chargés (activés par défaut sous RHEL)
httpd -M | grep proxy_fcgi
```

Les modules `proxy_module` et `proxy_fcgi_module` sont chargés par défaut
via `/etc/httpd/conf.modules.d/00-proxy.conf`.

### VirtualHost

Créer `/etc/httpd/conf.d/app.conf` :

```apache
<VirtualHost *:80>
    ServerName mon-appli.example.com

    # Racine web = mon-appli/ dans le dépôt
    DocumentRoot /opt/app/mon-appli

    # Passage des .php à PHP-FPM via socket Unix
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
    </FilesMatch>

    <Directory /opt/app/mon-appli>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted

        # Page d'accueil
        DirectoryIndex index.php
    </Directory>

    # Interdire l'accès aux fichiers sensibles
    <DirectoryMatch "^/opt/app/(securite|log|lib|docs)">
        Require all denied
    </DirectoryMatch>

    # Journaux Apache
    ErrorLog  /var/log/httpd/app-error.log
    CustomLog /var/log/httpd/app-access.log combined
    LogLevel warn
</VirtualHost>
```

> **`AllowOverride All`** est nécessaire pour que le `.htaccess` de
> l'application (mod_rewrite pour le module Oracle) soit pris en compte.

### Activer mod_rewrite

```bash
# Vérifier (activé par défaut sous RHEL)
httpd -M | grep rewrite
```

Si absent, ajouter dans `/etc/httpd/conf.modules.d/` :

```apache
LoadModule rewrite_module modules/mod_rewrite.so
```

### Valider la configuration

```bash
sudo apachectl configtest
# Syntax OK
```

---

## 5. Oracle Instant Client et OCI8

### Installer Instant Client

```bash
# Télécharger les RPM depuis oracle.com ou utiliser le dépôt Oracle
# https://yum.oracle.com/repo/OracleLinux/OL9/oracle/instantclient/x86_64/

# Exemple avec les RPM Instant Client 19.25
sudo dnf install -y \
    oracle-instantclient19.25-basic-19.25.0.0.0-1.x86_64.rpm \
    oracle-instantclient19.25-devel-19.25.0.0.0-1.x86_64.rpm
```

Ou via le dépôt Oracle Linux :

```bash
sudo dnf install -y \
    oracle-instantclient-basic \
    oracle-instantclient-devel
```

### Configurer le linker

```bash
echo "/usr/lib/oracle/19.25/client64/lib" | \
    sudo tee /etc/ld.so.conf.d/oracle-instantclient.conf
sudo ldconfig
```

### Installer l'extension OCI8 via PECL

```bash
sudo dnf install -y php-devel php-pear gcc make

# Installer OCI8 (répondre avec le chemin Instant Client)
sudo pecl install oci8-3.3.0
# Prompt: instantclient,/usr/lib/oracle/19.25/client64/lib

# Activer l'extension
echo "extension=oci8.so" | sudo tee /etc/php.d/30-oci8.ini
```

### Variables d'environnement pour PHP-FPM

Décommenter les lignes `env[…]` dans `/etc/php-fpm.d/www.conf` :

```ini
env[LD_LIBRARY_PATH] = /usr/lib/oracle/19.25/client64/lib
env[ORACLE_HOME]     = /usr/lib/oracle/19.25/client64
env[TNS_ADMIN]       = /usr/lib/oracle/19.25/client64/network/admin
```

### Vérification

```bash
php -m | grep oci8
# oci8

php -r "echo oci_client_version();"
# 19.25.0.0.0
```

---

## 6. Déploiement de l'application

### Depuis Git (serveur connecté)

```bash
sudo mkdir -p /opt/app && cd /opt/app
sudo git clone https://git.yaodb-blog.fr/ojo/sw.git .
```

### Depuis une archive ZIP (serveur hors ligne)

```bash
# Transférer le ZIP sur le serveur
scp release-1.0.0.zip user@serveur:/tmp/

# Sur le serveur
sudo mkdir -p /opt/app
sudo unzip /tmp/release-1.0.0.zip -d /opt/app
```

### Structure résultante

```
/opt/app/
├── mon-appli/              ← DocumentRoot (racine web)
│   ├── .htaccess           ← mod_rewrite pour le module Oracle
│   ├── index.php
│   ├── bootstrap.php
│   ├── login.php
│   ├── about.php
│   ├── admin/
│   ├── oracle/
│   ├── modules/
│   ├── includes/
│   ├── assets/
│   └── i18n/
├── lib/                    ← bibliothèques PHP (hors DocumentRoot)
├── docs/                   ← documentation
├── securite/               ← données sensibles (créé au 1er démarrage)
│   ├── database.sqlite     ← base SQLite
│   ├── master.key          ← clé de chiffrement (auto-générée)
│   ├── wallets/            ← wallets Oracle Cloud
│   └── backups/            ← sauvegardes métadonnées
└── log/                    ← journaux applicatifs
    ├── app.log
    ├── debug.log
    └── trace.log
```

---

## 7. Permissions et SELinux

### Permissions fichiers

```bash
# Propriétaire : apache pour les répertoires inscriptibles
sudo chown -R apache:apache /opt/app/securite /opt/app/log

# Le reste appartient à root (lecture seule pour Apache)
sudo chown -R root:apache /opt/app/mon-appli /opt/app/lib
sudo chmod -R 750 /opt/app/mon-appli /opt/app/lib

# Permissions spécifiques
sudo chmod 700 /opt/app/securite
sudo chmod 600 /opt/app/securite/master.key 2>/dev/null || true
```

### SELinux

SELinux est activé par défaut sur RHEL. Il faut autoriser Apache/PHP-FPM
à accéder aux répertoires de l'application.

```bash
# Contexte pour le DocumentRoot
sudo semanage fcontext -a -t httpd_sys_content_t "/opt/app/mon-appli(/.*)?"
sudo restorecon -Rv /opt/app/mon-appli

# Contexte lecture/écriture pour securite/ et log/
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/opt/app/securite(/.*)?"
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/opt/app/log(/.*)?"
sudo restorecon -Rv /opt/app/securite /opt/app/log

# Contexte pour les assets uploadés (logo, fonts)
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/opt/app/mon-appli/assets/uploads(/.*)?"
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/opt/app/mon-appli/assets/fonts/uploads(/.*)?"
sudo restorecon -Rv /opt/app/mon-appli/assets

# Autoriser PHP-FPM à se connecter au réseau (LDAP, Oracle, OAuth)
sudo setsebool -P httpd_can_network_connect 1

# Autoriser les connexions vers les ports Oracle (1521 etc.)
sudo setsebool -P httpd_can_network_connect_db 1

# Autoriser l'envoi de mail (si notifications futures)
sudo setsebool -P httpd_can_sendmail 1
```

### Vérification SELinux

```bash
# Vérifier les contextes
ls -laZ /opt/app/securite/
ls -laZ /opt/app/mon-appli/

# Surveiller les refus AVC
sudo ausearch -m AVC -ts recent
```

---

## 8. Démarrage et activation des services

```bash
# Démarrer PHP-FPM
sudo systemctl start php-fpm
sudo systemctl enable php-fpm

# Démarrer Apache
sudo systemctl start httpd
sudo systemctl enable httpd

# Vérifier les statuts
sudo systemctl status php-fpm
sudo systemctl status httpd
```

---

## 9. Vérification

### PHP-FPM

```bash
# Processus actifs
ps aux | grep php-fpm

# Socket existant
ls -la /run/php-fpm/www.sock
```

### Extensions PHP

```bash
php -m | grep -E 'oci8|sqlite3|mbstring|ldap|sodium|zip|gd'
```

Toutes ces extensions doivent apparaître.

### Application

```bash
# Test via curl
curl -I http://localhost/

# Attendu : HTTP/1.1 302 (redirection vers login.php)
```

Accéder à `http://mon-appli.example.com/` dans un navigateur. La base
SQLite et la clé de chiffrement sont créées automatiquement au premier
accès. Le compte administrateur par défaut est créé par `seedInitialData()`.

---

## 10. Pare-feu

```bash
# Ouvrir le port HTTP
sudo firewall-cmd --permanent --add-service=http

# Ouvrir le port HTTPS (si configuré)
sudo firewall-cmd --permanent --add-service=https

# Appliquer
sudo firewall-cmd --reload
```

---

## 11. HTTPS avec TLS

### Installer mod_ssl

```bash
sudo dnf install -y mod_ssl
```

### Certificat (Let's Encrypt ou interne)

Pour un certificat auto-signé (environnement interne) :

```bash
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/pki/tls/private/app.key \
    -out /etc/pki/tls/certs/app.crt \
    -subj "/CN=mon-appli.example.com"
```

### VirtualHost HTTPS

Créer ou modifier `/etc/httpd/conf.d/app-ssl.conf` :

```apache
<VirtualHost *:443>
    ServerName mon-appli.example.com

    SSLEngine on
    SSLCertificateFile    /etc/pki/tls/certs/app.crt
    SSLCertificateKeyFile /etc/pki/tls/private/app.key

    # Même configuration que le VirtualHost :80
    DocumentRoot /opt/app/mon-appli

    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
    </FilesMatch>

    <Directory /opt/app/mon-appli>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
        DirectoryIndex index.php
    </Directory>

    <DirectoryMatch "^/opt/app/(securite|log|lib|docs)">
        Require all denied
    </DirectoryMatch>

    # Headers de sécurité
    Header always set Strict-Transport-Security "max-age=31536000"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"

    ErrorLog  /var/log/httpd/app-ssl-error.log
    CustomLog /var/log/httpd/app-ssl-access.log combined
</VirtualHost>

# Redirection HTTP → HTTPS
<VirtualHost *:80>
    ServerName mon-appli.example.com
    Redirect permanent / https://mon-appli.example.com/
</VirtualHost>
```

```bash
sudo apachectl configtest && sudo systemctl restart httpd
```

---

## 12. Maintenance

### Mise à jour de l'application

Deux méthodes :

**Via l'interface admin** (recommandé) :
Administration > Maintenance > Mise à jour — téléverser le ZIP de mise
à jour. La base de données et la clé de chiffrement ne sont jamais
écrasées.

**Via Git** :

```bash
cd /opt/app
sudo git pull --ff-only origin main
sudo chown -R apache:apache securite/ log/
sudo restorecon -Rv securite/ mon-appli/
```

### Sauvegarde des métadonnées

**Via l'interface admin** :
Administration > Maintenance > Sauvegarde — crée un ZIP de tout le
répertoire `securite/` (base, clé, wallets). Peut être stocké localement
ou téléchargé.

**Via cron** :

```bash
# Sauvegarde quotidienne à 2h du matin
echo '0 2 * * * root cd /opt/app && zip -r securite/backups/metadata_$(date +\%Y\%m\%d_\%H\%M\%S).zip securite/ -x "securite/backups/*"' \
    | sudo tee /etc/cron.d/app-backup
```

### Journaux

```bash
# Journaux applicatifs
tail -f /opt/app/log/app.log

# Journaux Apache
tail -f /var/log/httpd/app-error.log

# Journaux PHP-FPM
tail -f /var/log/php-fpm/error.log
```

### Rotation des journaux

Créer `/etc/logrotate.d/app` :

```
/opt/app/log/*.log {
    weekly
    rotate 12
    compress
    delaycompress
    missingok
    notifempty
    create 0640 apache apache
}
```
