# Déploiement sur le serveur WHM/cPanel — app.amabuffet.com

Compte cPanel : **amabuffet** · Domaine : **app.amabuffet.com**

## Le point de départ : Docker ne tourne pas dans un compte cPanel

Un compte cPanel n'exécute pas de conteneurs. La pile tourne donc **au niveau
du serveur**, sous `root`, dans `/opt/ama-buffet`, et n'écoute que sur
`127.0.0.1`. Apache — celui de cPanel, qui détient déjà les ports 80 et 443 —
relaie `app.amabuffet.com` vers elle.

```
Internet ──► Apache (cPanel, TLS AutoSSL) ──► 127.0.0.5:8099 ──► nginx ──► API ──► PostgreSQL
```

L'adresse `127.0.0.5` est une adresse de boucle locale comme `127.0.0.1` : sur
Linux, toute la plage `127.0.0.0/8` répond, sans configuration réseau. Elle est
utilisée ici pour que cette pile ne se confonde pas avec les autres
applications du serveur lors d'un diagnostic. Ce qui empêche réellement deux
applications de se marcher dessus reste le **port**, pas l'adresse.

Trois conséquences utiles :

- **rien de la pile n'est exposé** : pas de port ouvert dans le pare-feu ;
- **une seule origine** pour le site et l'API, donc pas de CORS et des cookies
  `SameSite=Strict` qui fonctionnent ;
- **AutoSSL gère le certificat**, renouvellement compris.

Si l'hébergeur refuse Docker sur la machine, voir « Plan B » en fin de document.

## 1. Adresse IP

Le serveur a déjà une ou plusieurs IP. Il n'y a rien à inventer :

- **WHM → Basic WebHost Manager Setup** affiche l'IP principale ;
- **WHM → IP Functions → Show/Edit Reserved IPs** liste les IP disponibles ;
- **WHM → Change Site's IP Address** attribue une IP dédiée au compte
  `amabuffet` si vous en avez acheté une.

Une IP dédiée n'est pas nécessaire au fonctionnement : AutoSSL et le SNI gèrent
le HTTPS sur IP partagée. Elle sert surtout à la réputation d'envoi d'e-mails.

Notez l'IP retenue, elle sert au DNS : `___.___.___.___`

## 2. DNS

Chez le gestionnaire du domaine `amabuffet.com` :

| Type | Nom | Valeur | TTL |
| --- | --- | --- | --- |
| A | `app` | l'IP notée ci-dessus | 3600 |

Vérification, une fois propagé :

```bash
dig +short app.amabuffet.com
```

Ne pas activer de proxy (type Cloudflare orange) avant d'avoir validé le
certificat : AutoSSL a besoin de joindre le domaine directement.

## 3. Sous-domaine dans cPanel

cPanel du compte `amabuffet` → **Domains → Create A Domain** :

- Domaine : `app.amabuffet.com`
- Document root : `public_html/app` (il restera vide, c'est normal)

Ce dossier vide ne sert à rien d'autre qu'à faire exister le vhost : c'est lui
qui recevra notre configuration de proxy.

## 4. Préparation du serveur (en root, par SSH)

```bash
mkdir -p /opt/ama-buffet
cd /opt/ama-buffet
# déposer le code ici (scp, git clone, ou tar)

bash deploy/install-serveur.sh
```

Le script lit `BIND_ADDR` et `WEB_PORT` s'ils sont déjà exportés, sinon il
utilise `127.0.0.5:8099`. Pour d'autres valeurs :

```bash
BIND_ADDR=127.0.0.7 WEB_PORT=8110 bash deploy/install-serveur.sh
```

Le script installe Docker, vérifie les modules Apache `mod_proxy`, dépose la
configuration de proxy dans les fichiers *userdata* de cPanel, installe le
service systemd et programme la sauvegarde quotidienne.

Les fichiers *userdata* sont le point important : une modification directe du
`httpd.conf` serait écrasée à la première reconstruction de vhost par cPanel.

## 5. Configuration

```bash
cp deploy/.env.production.example .env
chmod 600 .env
nano .env
```

À remplir :

```bash
openssl rand -base64 36   # POSTGRES_PASSWORD
openssl rand -base64 48   # AMA_JWT_SECRET
```

Pour les notifications push :

```bash
docker compose run --rm api python -c \
  "from py_vapid import Vapid01 as V; v=V(); v.generate_keys(); \
   print('public:', v.public_key); print('private:', v.private_key)"
```

E-mails : créer `no-reply@amabuffet.com` dans cPanel → **Email Accounts**, puis
reporter le mot de passe dans `AMA_SMTP_PASSWORD`.

## 6. Démarrage

```bash
systemctl enable --now ama-buffet
docker compose -f docker-compose.yml -f docker-compose.cpanel.yml logs -f api
```

Attendre `Application des migrations` puis `Uvicorn running`. Test local :

```bash
curl -s http://127.0.0.1:8099/api/health
```

Puis dans le navigateur : `https://app.amabuffet.com`

## 7. Certificat

WHM → **SSL/TLS → Manage AutoSSL** → onglet *Manage Users* → lancer
**Check “amabuffet”**. Le certificat couvre le sous-domaine automatiquement.

Une fois le HTTPS actif, forcer la redirection : cPanel → **Domains** →
activer *Force HTTPS Redirect* sur `app.amabuffet.com`.

## 8. Premier accès et paramétrage

```bash
cd /opt/ama-buffet
docker compose -f docker-compose.yml -f docker-compose.cpanel.yml \
  exec api python -m app.cli owner patron@amabuffet.com
```

Le lien affiché permet de choisir le mot de passe. Ensuite, dans
`https://app.amabuffet.com/admin.html` :

1. **Paramètres** : position du restaurant, moyens de paiement, livraison ;
2. **Horaires** : les horaires réels du restaurant ;
3. **Carte** : allergènes et temps de préparation de chaque plat ;
4. **TVA** : taux par catégorie, avec le comptable ;
5. **Équipe** : inviter la cuisine et les gérants.

## 9. Stripe

Une fois le compte du restaurant ouvert :

1. `.env` → `AMA_PAYMENT_PROVIDER=stripe` + les trois clés ;
2. Stripe → Developers → Webhooks → endpoint
   `https://app.amabuffet.com/api/payments/webhook`, événements
   `payment_intent.succeeded` et `payment_intent.payment_failed` ;
3. reporter le secret de signature dans `AMA_STRIPE_WEBHOOK_SECRET` ;
4. `systemctl reload ama-buffet` ;
5. vérifier dans le journal Stripe que le webhook répond `200`.

## 10. Sauvegardes

```bash
age-keygen -o ~/ama-backup-key.txt     # sur VOTRE poste, pas sur le serveur
```

Copier la ligne `public key:` dans `BACKUP_AGE_RECIPIENT`. La clé privée reste
chez vous : le serveur peut alors sauvegarder sans pouvoir relire ses propres
sauvegardes. Le cron est déjà en place (3h15).

**Tester une restauration** sur un environnement de test avant l'ouverture, puis
une fois par trimestre. Une sauvegarde jamais restaurée n'est pas une sauvegarde.

## 11. Mise à jour du code

```bash
cd /opt/ama-buffet
# déposer la nouvelle version
systemctl reload ama-buffet      # reconstruit les images et applique les migrations
docker compose -f docker-compose.yml -f docker-compose.cpanel.yml logs -f api
```

## Vérifications après mise en ligne

- [ ] `https://app.amabuffet.com` s'ouvre, cadenas valide
- [ ] `http://` redirige vers `https://`
- [ ] Création de compte, réception de l'e-mail de confirmation
- [ ] Connexion par e-mail **et** par téléphone
- [ ] Commande de test en « paiement sur place » visible dans l'espace gestion
- [ ] Ajout à l'écran d'accueil sur iPhone et sur Android
- [ ] `curl -sI https://app.amabuffet.com | grep -i strict-transport` (HSTS)
- [ ] Sauvegarde : lancer `bash scripts/backup.sh /opt/ama-buffet-backups`
- [ ] Textes légaux publiés, allergènes renseignés

## Dépannage

| Symptôme | Cause habituelle |
| --- | --- |
| 503 depuis Apache | La pile n'est pas démarrée : `systemctl status ama-buffet` |
| 404 sur tout le domaine | Les inclusions userdata ne sont pas prises : `/scripts/ensure_vhost_includes --user=amabuffet` puis `/scripts/restartsrv_httpd` |
| Page blanche, erreurs CORS | `AMA_ALLOWED_ORIGINS` ne correspond pas exactement à l'URL du navigateur |
| Déconnexion immédiate | `X-Forwarded-Proto` absent : vérifier le `proxy.conf` |
| Port déjà pris | `ss -ltnp \| grep 8099` puis changer `WEB_PORT` (et relancer `install-serveur.sh`, le proxy Apache doit suivre) |
| `bind: address already in use` sur `0.0.0.0` | Une autre pile occupe le port : `docker compose ls` liste tous les projets et leur dossier, y compris ceux lancés depuis une copie oubliée |
| Apache renvoie 502 | L'adresse du `proxy.conf` ne correspond pas à `BIND_ADDR` : comparer avec `ss -ltnp` |
| E-mails non reçus | Tester `AMA_SMTP_*`, vérifier SPF/DKIM du domaine dans WHM |

## Plan B : sans Docker

Si l'hébergeur interdit Docker sur la machine :

1. **PostgreSQL** installé sur le serveur (WHM → *Service Configuration*), ou
   base managée externe ;
2. **API** via cPanel → *Setup Python App* (Passenger) pointant sur
   `app.main:app`, avec les variables d'environnement de `.env` ;
3. **Front** : le contenu de `frontend/public` copié dans
   `public_html/app`, servi directement par Apache ;
4. le proxy Apache ne garde alors que la règle `/api/` vers le port de
   Passenger.

C'est faisable, mais on perd l'isolation et la reproductibilité du déploiement :
les migrations et les dépendances redeviennent manuelles. À réserver au cas où
Docker est réellement impossible.
