Mise en production

Déployez votre site sur un hébergement Hostinger (ou tout serveur Apache avec accès SSH) et vérifiez que tout est prêt avant le lancement.

Déploiement (Hostinger / Apache)

Déployez votre site via rsync pour des mises à jour rapides et automatiques.

Prérequis

  • Serveur Apache avec mod_rewrite et mod_headers activés (ce sont des fonctionnalités d'Apache activées par défaut chez la plupart des hébergeurs — vous n'avez rien à faire)
  • PHP 7+ (pour api/baserow.php et api/consent.php)
  • Certificat SSL (Let's Encrypt ou autre)
  • Accès SSH activé sur l'hébergement (Hostinger : plan Premium ou supérieur)

1. Activer et configurer SSH

Sur Hostinger, allez dans hPanel (hpanel.hostinger.com) → Avancé → Accès SSH et notez :

  • IP du serveur
  • Port (généralement 65002 chez Hostinger)
  • Nom d'utilisateur (ex : u123456789)

2. Générer une clé SSH (si pas déjà fait)

# Générer une clé SSH ed25519
ssh-keygen -t ed25519 -C "votre@email.com"

# Appuyer sur Entrée pour accepter le chemin par défaut
# Choisir un mot de passe (ou Entrée pour aucun)

Appuyez sur Entrée à chaque question (emplacement du fichier, mot de passe) pour garder les valeurs par défaut. Deux fichiers sont créés : id_ed25519 (votre clé secrète, ne la partagez jamais) et id_ed25519.pub (votre clé publique, à coller sur Hostinger).

  1. Afficher la clé publique dans le terminal : cat ~/.ssh/id_ed25519.pub
  2. Copier tout le contenu affiché (de ssh-ed25519 jusqu'à la fin)
  3. Aller sur hpanel.hostinger.com
  4. Cliquer Hébergement (menu de gauche) → sélectionner votre domaine
  5. Cliquer AvancéAccès SSH
  6. Dans la section Clés SSH, coller la clé publique
  7. Cliquer Ajouter
  8. Tester la connexion : ssh -p 65002 uXXXXXX@xx.xxx.xx.xxx (remplacer par vos valeurs)

3. Première connexion SSH

Connectez-vous une première fois pour accepter l'empreinte du serveur :

# Remplacez USER, IP et PORT par vos valeurs
ssh -p PORT USER@IP

# Tapez "yes" pour accepter l'empreinte
# Entrez votre mot de passe SSH
# Une fois connecté, tapez "exit" pour revenir en local

4. Copier la clé publique sur le serveur

Pour ne plus avoir à taper le mot de passe à chaque déploiement :

# Copier la clé publique (demande le mot de passe une dernière fois)
ssh-copy-id -p PORT USER@IP

# Vérifier que la connexion fonctionne sans mot de passe
ssh -p PORT USER@IP "echo 'SSH OK'"

5. Identifier le dossier du domaine

Sur Hostinger, chaque domaine a son propre dossier. Connectez-vous en SSH pour le trouver :

ssh -p PORT USER@IP
ls ~/domains/
# Résultat : monsite.fr  autre-site.com  ...
exit

Le chemin de déploiement sera : /home/USER/domains/monsite.fr/public_html/

6. Créer le fichier d'exclusions

Créez un fichier .rsync-exclude à la racine du projet pour lister les fichiers à ne pas envoyer sur le serveur :

# Git + CI
.git/
.gitignore
.gitmodules
.github/

# Dev / documentation (inutile en prod)
CLAUDE.md
README.md
.claude/
.rsync-exclude

# Secrets et config locale (jamais déployés)
.deploy.env
.deploy.env.example
.env.example
.baserow-credentials

# Dev tools (pas utiles en prod)
node_modules/
.playwright-mcp/
.mcp.json

# Scripts locaux (pas utiles en prod)
setup.sh
deploy.sh
generate-sitemap.js

# Configurateur (local uniquement)
configurateur/

# Submodule (les symlinks sont suivis par rsync -L)
.framework/

# Données locales (registre pages, etc.)
data/

# Form builder state (dev only, pas utile en prod)
forms/.meta.json
forms/*.json

# Wireframes bundle (dev only)
wireframes/wireframes-data.json
wireframes/build-data.js

# IDE / OS
.vscode/
.DS_Store
Thumbs.db

Note : le fichier .env n'est pas exclu du déploiement : il est envoyé sur le serveur par rsync et protégé par le .htaccess. Seuls les fichiers de développement et de configuration SSH sont exclus.

Matrice de déploiement

Fichier / Dossier GitHub Serveur (prod) Template Notes
core/, assets/, api/, snippets/ ✅ (symlinks) Framework core — déployé via symlinks suivis par rsync -L
components/ Dossier projet (pas un symlink) — copié depuis snippets/components/ par setup.sh
configurateur/ ✅ (symlink) Outil local uniquement, exclu du déploiement
wireframes/ Dossier réel du projet — 375+ sections HTML prêtes à l'emploi
docs/ ✅* *Déployé uniquement sur framework.beely.studio (la prod de la doc)
config-site.js Configuration client — spécifique à chaque projet
.env Secrets API (Baserow, CORS) — nécessaire côté serveur
.env.example Template documenté, inutile en prod
.deploy.env Config SSH locale uniquement
.deploy.env.example Template documenté
.htaccess Config Apache serveur
setup.sh Script d'initialisation local
deploy.sh Script de déploiement local
CLAUDE.md, README.md Documentation dev, inutile en prod
.vscode/ Config IDE locale
sitemap.xml Généré par generate-sitemap.js avant chaque déploiement
pages/ Pages HTML du site
data/ Données locales (registre pages, métadonnées médias)
404.html Page d'erreur Apache

Rappel : .gitignore contrôle ce qui va sur GitHub. .rsync-exclude contrôle ce qui va sur le serveur. Ce sont deux périmètres indépendants.

7. Configurer le déploiement

Astuce : si vous avez utilisé init-project.sh, cette étape est déjà faite automatiquement. Passez à l’étape 8.

Le script deploy.sh lit les informations de connexion depuis un fichier .deploy.env (non committé dans git). Copiez le template et remplissez-le :

cp .deploy.env.example .deploy.env

Contenu de .deploy.env :

# Production
PROD_HOST=xx.xxx.xx.xxx
PROD_PORT=65002
PROD_USER=uXXXXXX
PROD_PATH=/home/uXXXXXX/domains/monsite.fr/public_html/
PROD_URL=https://monsite.fr

# Pré-production (optionnel)
PREPROD_HOST=
PREPROD_PORT=
PREPROD_USER=
PREPROD_PATH=
PREPROD_URL=

Rendez le script exécutable (une seule fois) :

chmod +x deploy.sh

8. Déployer

# Simuler le déploiement en production (dry-run)
./deploy.sh prod --dry-run

# Déployer en production
./deploy.sh prod

# Déployer en pré-production
./deploy.sh preprod

# Dry-run pré-production
./deploy.sh preprod --dry-run

Comment ça marche :

  • rsync ne transfère que les fichiers modifiés (très rapide après le premier déploiement)
  • --delete supprime sur le serveur les fichiers supprimés en local (synchronisation miroir)
  • --dry-run simule sans rien modifier, parfait pour vérifier avant de déployer
  • Préprod non indexée : chaque déploiement préprod ajoute un header X-Robots-Tag: noindex, nofollow dans le .htaccess du serveur — la préprod n’apparaîtra jamais dans Google

9. Configurer le fichier .env

Créez un fichier .env à la racine de votre projet dans VSCode. Ce fichier contient les variables utilisées par les API PHP côté serveur :

# .env (à la racine du projet)
SITE_ORIGIN=https://monsite.fr
BASEROW_TOKEN=votre_token_api_ici

Le fichier .env est inclus dans le déploiement rsync et sera envoyé automatiquement sur le serveur. Il est protégé par le .htaccess (inaccessible depuis le web) et exclu du versionning Git via .gitignore. C'est sûr car le fichier .htaccess contient une règle qui renvoie une erreur 403 (accès interdit) à quiconque tente d'accéder au .env depuis un navigateur. Le fichier est sur le serveur mais invisible depuis le web.

Aucun accès SSH à Hostinger n'est nécessaire pour la configuration : tout se fait en local dans VSCode.

VariableUtilisé parDescription
SITE_ORIGINTous les proxiesDomaine autorisé pour les requêtes CORS
BASEROW_TOKENapi/baserow.phpToken API Baserow (read-only)

10. Vérifier le .htaccess

Le fichier .htaccess fourni gère automatiquement :

  • HTTPS : redirection HTTP → HTTPS (301)
  • URLs propres : /blog au lieu de /blog.html
  • Page 404 : page d'erreur personnalisée
  • Sécurité : headers (HSTS, X-Frame-Options, X-Content-Type-Options, CSP — une règle de sécurité qui dit au navigateur « ce site n'a le droit de charger des scripts que depuis ces sources précises », ce qui empêche les pirates d'injecter du code malveillant), tous les dotfiles bloqués (.env, .deploy.env, etc.), dossier data/ protégé, rate limiting sur les endpoints PHP (protection anti-spam : si quelqu'un soumet plus de 5 formulaires par minute, il est automatiquement bloqué)
  • Anti-cache CDN : désactive le cache LiteSpeed/HCDN sur les fichiers CSS, JS et HTML pour que chaque déploiement soit immédiatement visible (headers no-cache, CDN-Cache-Control: no-store, CacheLookup off)

Testez que mod_rewrite fonctionne en accédant à https://votre-site.fr/blog (sans .html).

11. Protection HTTP — htpasswd (optionnel)

Protégez un site en développement ou pré-production par mot de passe (HTTP Basic Auth). Une popup d'authentification apparaîtra dans le navigateur avant de pouvoir accéder au site.

Via le configurateur (recommandé)

  1. Lancez le serveur Python : python3 configurateur/configurator-server.py
  2. Ouvrez le configurateur : http://localhost:XXXX/configurateur/
  3. Cliquez sur l'onglet Protection HTTP dans la sidebar
  4. Cochez Activer la protection HTTP
  5. Renseignez un identifiant et un mot de passe
  6. Cliquez sur Enregistrer

Le serveur génère automatiquement :

  • .htpasswd à la racine du projet (mot de passe hashé en APR1/MD5)
  • Le bloc AuthType Basic dans le .htaccess

Pour désactiver : décochez la case et cliquez sur Enregistrer. Le .htpasswd est supprimé et le bloc auth retiré du .htaccess.

Manuellement

1. Générer le fichier .htpasswd :

# 📂 Dossier : racine du projet
htpasswd -cm .htpasswd admin
# Entrez le mot de passe quand demandé

2. Ajouter ce bloc en haut du .htaccess (après ErrorDocument 404) :

# --- BEGIN Protection HTTP (htpasswd) ---
AuthType Basic
AuthName "Accès restreint"
AuthUserFile /chemin/absolu/vers/votre/projet/.htpasswd
Require valid-user
# --- END Protection HTTP (htpasswd) ---

Important : AuthUserFile doit être un chemin absolu (pas relatif). Un chemin absolu commence par / et part de la racine du serveur, comme /home/u123456789/domains/monsite.fr/public_html/.htpasswd. Ne mettez jamais un chemin relatif (comme ../.htpasswd), sinon ça ne fonctionnera pas.

3. Pour désactiver : supprimez le bloc du .htaccess et le fichier .htpasswd.

Rappel : pensez à désactiver la protection avant la mise en production du site final.

12. Sitemap

Le sitemap est généré automatiquement à chaque déploiement par deploy.sh. Il utilise l'URL du site configurée dans .deploy.env (PROD_URL ou PREPROD_URL).

Vous pouvez aussi le générer manuellement :

node generate-sitemap.js https://votre-site.fr

Cela crée sitemap.xml et robots.txt avec les URLs propres. Soumettez le sitemap dans Google Search Console :

  1. Allez sur search.google.com/search-console
  2. Cliquez Ajouter une propriété et entrez l'URL de votre site
  3. Vérifiez la propriété (méthode recommandée : enregistrement DNS ou fichier HTML)
  4. Dans le menu de gauche, cliquez Sitemaps
  5. Dans le champ « Ajouter un sitemap », entrez sitemap.xml
  6. Cliquez Envoyer

Récap : fichiers à personnaliser par projet

Chaque nouveau projet nécessite de remplir 3 fichiers :

FichierContenuCommitté ?
config-site.jsNom du site, favicon, analytics, informations légales, config blog (tableId)Oui
.envSecrets : token Baserow, CORS originNon
.deploy.envConnexion SSH : host, port, user, path pour prod et préprodNon

Les fichiers .env.example et .deploy.env.example servent de templates documentés (committés dans git).

Pour le dépôt Git, configurez le remote au démarrage du projet :

git remote add origin https://github.com/votre-user/votre-projet.git
git push -u origin main

Récap : workflow quotidien

Une fois tout configuré, le cycle de développement-déploiement est simple :

# 1. Modifier le code en local (Live Server pour prévisualiser)

# 2. Commiter les changements
git add -A
git commit -m "Update hero section design"

# 3. Pousser sur GitHub
git push

# 4. Déployer en production
./deploy.sh prod

Déploiement automatique (GitHub Actions)

Pour les projets avec un client qui modifie le contenu via GitHub, GitHub Actions déploie automatiquement à chaque commit.

Fonctionnement

  1. Le client modifie un fichier JSON sur GitHub et commit
  2. GitHub Actions valide le JSON, compile le contenu dans le HTML, et déploie via SSH/rsync
  3. Le site est mis à jour en ~15 secondes

Le déploiement SSH inclut un système de retry automatique (jusqu'à 3 tentatives avec 10s d'attente) pour gérer les connexions instables de certains hébergeurs.

Configuration

Dans GitHub → SettingsSecrets and variablesActions, créer ces secrets :

SecretValeurOù la trouver
SSH_PRIVATE_KEYClé SSH privéecat ~/.ssh/id_ed25519
PROD_HOSTIP du serveur.deploy.env → PROD_HOST
PROD_PORTPort SSH.deploy.env → PROD_PORT
PROD_USERUtilisateur SSH.deploy.env → PROD_USER
PROD_PATHChemin sur le serveur.deploy.env → PROD_PATH

Le workflow .github/workflows/deploy.yml est copié automatiquement par setup.sh.

Voir Contenu éditable pour le guide client complet.

Sécurité

  • La clé SSH est stockée dans les GitHub Secrets — jamais visible, même par les admins du repo
  • Chaque projet a ses propres secrets — un client ne peut déclencher que le déploiement de son site
  • La clé SSH est restreinte au rsync vers un seul répertoire — pas d'accès shell au serveur
  • Le client n'a accès qu'au repo de son site — pas aux autres projets

Voir la documentation Contenu éditable pour le workflow client complet.

Déploiement manuel (FTP / cPanel)

Si vous n'utilisez pas SSH/rsync, vous pouvez déployer manuellement via le gestionnaire de fichiers cPanel ou un client FTP (FileZilla, Cyberduck, etc.). Cette méthode fonctionne avec tous les hébergeurs (Hostinger, o2switch, Infomaniak, etc.).

1. Uploader les fichiers

Connectez-vous à votre espace d'hébergement et accédez au dossier de votre domaine (généralement public_html/).

  • cPanel : Gestionnaire de fichiers → naviguez dans public_html/ → glissez-déposez vos fichiers
  • FTP : connectez votre client avec les identifiants fournis par votre hébergeur et uploadez dans le dossier du domaine

2. Fichiers à ne pas envoyer

Excluez ces fichiers/dossiers du transfert (ils sont inutiles en production) :

.git/                  # Historique Git
.claude/               # Configuration Claude Code
CLAUDE.md              # Instructions Claude Code
.deploy.env            # Config SSH locale
.rsync-exclude         # Liste d'exclusion rsync
deploy.sh              # Script de déploiement
generate-sitemap.js    # Générateur de sitemap (Node.js)

3. Créer le .env sur le serveur

Le fichier .env n'est pas dans Git, il faut le créer manuellement sur le serveur. Dans le gestionnaire de fichiers cPanel, créez un nouveau fichier .env à la racine du site :

# .env (racine du site sur le serveur)
SITE_ORIGIN=https://votre-site.fr
BASEROW_TOKEN=votre-token-baserow

Le .htaccess fourni bloque automatiquement l'accès à ce fichier depuis le navigateur.

4. Vérifications après upload

  • PHP actif : la plupart des hébergeurs mutualisés l'activent par défaut
  • .htaccess lu : testez que les URLs propres fonctionnent (/blog au lieu de /blog.html)
  • HTTPS actif : activez le certificat SSL dans votre panneau d'hébergement si ce n'est pas fait. Sur Hostinger : hPanel → Sécurité → SSL. Sur o2switch : cPanel → SSL/TLS.
  • .env inaccessible : vérifiez que https://votre-site.fr/.env retourne une erreur 403
  • Dossier data/ : il sera créé automatiquement par consent.php au premier consentement cookies

Le projet étant zéro-dépendance, il n'y a aucun npm install ou build à lancer. Les fichiers fonctionnent tels quels.

Checklist de lancement

Vérifiez chaque point avant de considérer le site comme prêt à être lancé.

Charte graphique
  • tokens.css : couleurs principales (--color-primary, --color-secondary)
  • tokens.css : polices personnalisées (--font-heading, --font-body)
  • tokens.css : arrondis, ombres, conteneur max-width si besoin
  • ☐ Test dark mode : toutes les pages lisibles en mode sombre
Configuration (config-site.js)
  • SITE_CONFIG : nom du site (name) renseigné
  • SITE_CONFIG : favicon (favicon) renseigné
  • COOKIES_CONFIG : IDs analytics renseignés (ou vides si non utilisés)
  • COOKIES_CONFIG : textes du bandeau cookies adaptés
  • COOKIES_CONFIG : privacyUrl pointe vers /confidentialite.html
  • COOKIES_CONFIG : consentEndpoint configuré (/api/consent.php)
  • BLOG_CONFIG : connexion Baserow renseignée (si blog), tableId renseigné (le token est dans .env, pas dans config-site.js)
  • LEGAL_CONFIG : toutes les infos entreprise remplies (company, SIRET, adresse, etc.)
  • LEGAL_CONFIG : infos hébergeur remplies (nom, adresse, URL)
  • LEGAL_CONFIG : section développeur remplie ou laissée vide (masquée automatiquement)
Pages légales & RGPD
  • mentions-legales.html : ouvrir et vérifier que toutes les infos s'affichent (pas de [...])
  • confidentialite.html : vérifier le tableau cookies (doit lister les services configurés)
  • ☐ Bouton « Gérer mes préférences cookies » fonctionnel sur la page confidentialité
  • ☐ Bandeau cookies : lien vers la politique de confidentialité visible
  • ☐ Footer de chaque page : liens vers mentions légales et confidentialité
  • ☐ Textes légaux validés par un professionnel du droit
  • api/consent.php fonctionnel (tester un accept/refus et vérifier data/consents.csv)
Contenu & SEO
  • ☐ Header : logo, navigation finale, liens corrects
  • ☐ Footer : copyright à jour, liens légaux présents
  • ☐ Toutes les balises <title> uniques et descriptives
  • ☐ Toutes les balises <meta description> renseignées
  • 404.html : texte et lien personnalisés
  • generate-sitemap.js exécuté avec l'URL finale
  • robots.txt généré et correct
Serveur & Sécurité
  • .env : SITE_ORIGIN renseigné avec l'URL de production
  • .env : BASEROW_TOKEN renseigné (si blog)
  • ☐ HTTPS actif et fonctionnel
  • ☐ URLs propres fonctionnelles (/blog au lieu de /blog.html)
  • .htaccess : vérifier que .env et tous les dotfiles sont inaccessibles depuis le navigateur
  • data/ : vérifier que le dossier est inaccessible depuis le navigateur
  • ☐ HSTS actif (header Strict-Transport-Security)
  • ☐ Rate limiting actif sur les endpoints PHP (api/rate-limit.php)
  • ☐ Page 404 accessible (/page-inexistante)
Tests finaux
  • ☐ Test mobile : toutes les pages responsive
  • ☐ Test dark mode : lisibilité de toutes les pages
  • ☐ Test bandeau cookies : accepter, refuser, personnaliser
  • ☐ Test pages légales : infos dynamiques correctes
  • ☐ Test blog : listing, article, filtres (si blog actif)
  • ☐ Test 404 : page d'erreur personnalisée
  • ☐ Test formulaires : validation, envoi (si formulaires actifs)
  • ☐ Supprimer les fichiers inutiles du serveur (.git/, snippets/)

Problèmes courants

  • Le déploiement échoue : vérifiez que .deploy.env est bien rempli et que la clé SSH est configurée (ssh-keygen -t ed25519).
  • Le .env n'est pas envoyé : vérifiez qu'il n'est pas listé dans .rsync-exclude (il ne devrait pas y être).
  • Les URLs propres ne fonctionnent pas : vérifiez que mod_rewrite est activé sur le serveur Apache et que le .htaccess est bien déployé.
  • Le CSS/JS n'est pas à jour après déploiement : le .htaccess désactive déjà le cache CDN. Videz le cache navigateur (Ctrl+Shift+R).

Voir aussi