J’ai utilisé MAMP, puis MAMP Pro, pendant des années. Fin mars 2026, lassé de diagnostiquer mes pannes à l’aveugle, j’ai demandé à Claude Code de reconstruire la même chose en natif : Apache, PHP-FPM et MySQL installés avec Homebrew, 98 vhosts migrés, HTTPS local et une commande unique pour tout piloter. Voici le tutoriel complet, écrit pour mes étudiants qui développent en PHP sur Mac.
Pourquoi j’ai fini par quitter MAMP Pro
MAMP a un vrai mérite : il démarre. On installe une application, on clique sur un bouton, et un serveur Apache avec PHP et MySQL répond sur le port 8888. Pour un premier cours de PHP, c’est parfait. J’ai fonctionné comme ça pendant des années, en passant à MAMP Pro pour débloquer les hôtes virtuels.
Puis les problèmes se sont accumulés. Pas un bug spectaculaire : une friction permanente.
- Des versions figées - mon installation MAMP Pro 6.8.1 plafonnait à PHP 8.2.0, sorti en décembre 2022. Pour suivre les versions récentes, il faut acheter la mise à jour majeure de l’application.
- Une configuration opaque - MAMP Pro régénère les fichiers de configuration d’Apache et de PHP depuis ses propres gabarits à chaque démarrage des serveurs. Toute modification manuelle finit écrasée : la configuration ne vous appartient pas.
- Un diagnostic impossible - quand un site ne répond plus, l’interface n’offre qu’une réponse : tout redémarrer et espérer. Aucun moyen simple de savoir quelle brique est en cause.
- Rien n’est scriptable - impossible d’automatiser, de versionner ou de documenter proprement une configuration enfermée dans une application graphique. Pour transmettre un environnement à des étudiants, c’est rédhibitoire.
Fin mars 2026, j’ai arrêté de me battre. J’ai ouvert Claude Code et je lui ai demandé de reconstruire mon environnement en natif, brique par brique, avec Homebrew. MAMP est toujours installé sur ma machine, par prudence. Je ne l’ai plus jamais ouvert.
Homebrew, le gestionnaire de paquets qui manque Ă macOS
Homebrew est un gestionnaire de paquets : un outil en ligne de commande qui installe, met à jour et désinstalle des logiciels libres sur macOS. Là où Linux a apt ou dnf, macOS n’a rien en standard. Homebrew comble ce vide depuis 2009 et s’est imposé comme l’outil par défaut de tout développeur sur Mac.
Trois notions suffisent pour suivre ce tutoriel :
- La formule - la recette d’installation d’un logiciel.
brew install phptélécharge et installe PHP avec toutes ses dépendances. - Le Cellar - le dossier où tout s’installe :
/opt/homebrewsur les Mac Apple Silicon. Rien ne se disperse dans le système, tout se désinstalle proprement. - Les services -
brew services start mysqlenregistre MySQL comme service qui démarre avec votre session, via le launchd de macOS.
/usr/local, pas dans /opt/homebrew. Remplacez ce préfixe dans tous les chemins de l’article, ou mieux : demandez-le à Homebrew lui-même avec brew --prefix. Les derniers portables Mac Intel ont été vendus en 2021, il peut donc encore y en avoir dans une classe.
L’installation tient en une commande, à coller dans le Terminal :
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Le script demande votre mot de passe et installe au passage les Command Line Tools d’Apple si nécessaire. Vérifiez ensuite que tout est en ordre :
brew --version
brew doctor
Pour mes étudiants, l’argument décisif n’est pas technique : une installation Homebrew se documente. Chaque étape de ce tutoriel est une commande qu’on peut lire, rejouer et corriger. Un clic dans une interface, non.
La stack cible
Voici ce qu’on va monter. Chaque brique est un paquet Homebrew indépendant, avec son fichier de configuration et son log :
Navigateur
|
v
Apache 2.4 ................. :80 / :443
| fichiers statiques servis en direct
| *.php transmis a PHP-FPM (proxy fcgi)
v
PHP-FPM 8.4 ................ 127.0.0.1:9000
|
v
MySQL 9.6 .................. 127.0.0.1:3306
(socket /tmp/mysql.sock)
mail() PHP -> msmtp -> MailHog :1025 (SMTP)
:8025 (interface web)
Deux choix de conception comptent. Apache tourne sous votre utilisateur macOS (directives User et Group) : fini les conflits de permissions entre le serveur et vos fichiers. Et PHP ne vit pas dans Apache : il tourne en service séparé, PHP-FPM, auquel Apache transmet les fichiers .php par le protocole FastCGI. C’est l’architecture des serveurs de production modernes.
Les versions au moment où j’écris : Apache 2.4.66, PHP 8.4.12, MySQL 9.6.0, mkcert 1.4.4, MailHog 1.0.1. Les vôtres seront peut-être plus récentes, les commandes ne changent pas.
L’installation, brique par brique
Tout ce qui suit vient de ma machine réelle, pas d’un tutoriel théorique : les chemins, les ports et les blocs de configuration sont ceux qui tournent chez moi aujourd’hui. Comptez une petite heure la première fois.
Installer Apache
brew install httpd
Homebrew livre Apache configuré sur le port 8080, pour éviter de réclamer des privilèges. On veut les vrais ports. Ouvrez /opt/homebrew/etc/httpd/httpd.conf et ajustez ces directives :
Listen 80
User votrenom # votre nom d'utilisateur macOS
Group staff
DirectoryIndex index.php index.html
Dans le même fichier, décommentez les modules dont la stack a besoin :
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_fcgi_module lib/httpd/modules/mod_proxy_fcgi.so
LoadModule ssl_module lib/httpd/modules/mod_ssl.so
LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so
Le port 80 étant privilégié, Apache se lance avec sudo /opt/homebrew/bin/httpd -k start. C’est le seul service de la stack qui exige sudo ; tous les autres tournent en simple utilisateur.
Créez ensuite le dossier qui contiendra tous vos projets, avec cette commande dans le Terminal :
mkdir -p ~/htdocs
Puis rouvrez httpd.conf et collez le bloc suivant tel quel, à la fin du fichier, en remplaçant votrenom. Attention : il se place bien dans httpd.conf, pas dans un fichier .htaccess. C’est même l’inverse : sa ligne AllowOverride All autorise vos futurs projets à utiliser leurs propres fichiers .htaccess, indispensables à WordPress. Vous n’avez aucun .htaccess à créer ici.
<Directory "/Users/votrenom/htdocs">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Installer PHP et PHP-FPM
brew install php
brew services start php
La formule installe PHP 8.4 avec PHP-FPM, son gestionnaire de processus. Il écoute sur le port 9000, comme le confirme /opt/homebrew/etc/php/8.4/php-fpm.d/www.conf :
listen = 127.0.0.1:9000
Côté Apache, un bloc suffit pour transmettre chaque fichier .php à PHP-FPM. C’est le pont entre les deux briques, à ajouter en fin de httpd.conf :
# === PHP-FPM Handler ===
Timeout 30
ProxyTimeout 30
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
Les deux directives Timeout fixent la patience d’Apache à 30 secondes. Retenez ce chiffre : il expliquera plus loin un piège classique.
Installer MySQL
brew install mysql
brew services start mysql
MySQL écoute en TCP sur 127.0.0.1:3306 et sur un socket UNIX, /tmp/mysql.sock. À l’installation, root n’a pas de mot de passe : donnez-lui-en un.
mysql -u root
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
Oui, root/root. Un mot de passe fort n’a aucun intérêt sur une base locale qui n’écoute que votre machine ; la simplicité, si. Toutes les commandes du quotidien deviennent mysql -u root -proot.
Créer un vhost par projet
Un hôte virtuel associe un nom de domaine local à un dossier. Chaque projet reçoit son domaine en .test, un TLD réservé qui n’existera jamais sur Internet. Trois fichiers à toucher.
D’abord, déclarer le domaine dans /etc/hosts :
127.0.0.1 nomduprojet.test
Ensuite, le vhost HTTP dans /opt/homebrew/etc/httpd/extra/httpd-vhosts.conf :
<VirtualHost *:80>
ServerName nomduprojet.test
DocumentRoot "/Users/votrenom/htdocs/nomduprojet"
</VirtualHost>
Enfin son jumeau HTTPS dans httpd-ssl.conf, qui pointe vers le certificat commun (on le génère juste après) :
<VirtualHost *:443>
ServerName nomduprojet.test
DocumentRoot "/Users/votrenom/htdocs/nomduprojet"
SSLEngine on
SSLCertificateFile "/opt/homebrew/etc/httpd/ssl/local-dev.pem"
SSLCertificateKeyFile "/opt/homebrew/etc/httpd/ssl/local-dev-key.pem"
</VirtualHost>
Redémarrez Apache (sudo /opt/homebrew/bin/httpd -k restart) et testez avec une page de diagnostic :
echo '<?php phpinfo();' > ~/htdocs/nomduprojet/index.php
Ma configuration compte aujourd’hui 98 vhosts construits sur ce modèle. Je n’en ai écrit aucun à la main : Claude Code a lu la configuration de MAMP Pro et généré les deux fichiers d’un coup. L’en-tête « Auto-generated from MAMP Pro configuration » est encore visible en haut du fichier.
Passer en HTTPS avec mkcert
mkcert crée une autorité de certification locale, l’installe dans le trousseau macOS, puis émet des certificats que votre navigateur accepte sans avertissement.
brew install mkcert
mkcert -install
Je génère un certificat unique pour tous mes domaines locaux, stocké à côté de la configuration Apache :
mkdir -p /opt/homebrew/etc/httpd/ssl
cd /opt/homebrew/etc/httpd/ssl
mkcert -cert-file local-dev.pem -key-file local-dev-key.pem \
localhost nomduprojet.test autreprojet.test
Tous les vhosts SSL pointent vers cette même paire de fichiers. Quand un projet arrive, on ajoute son domaine à la liste et on régénère : le mien couvre aujourd’hui 104 domaines. Un wildcard *.test ferait aussi l’affaire si vous préférez ne plus jamais y retoucher.
Capturer les emails avec MailHog
Dernier angle mort du dev local : les emails. Un site cloné qui envoie de vrais messages à de vrais utilisateurs pendant vos tests, c’est l’accident bête par excellence. MailHog intercepte tout : il écoute en SMTP sur le port 1025 et affiche les messages capturés dans une interface web sur le port 8025.
brew install mailhog msmtp
brew services start mailhog
Le pont avec PHP se fait par msmtp, un client SMTP minimal. Une ligne dans /opt/homebrew/etc/php/8.4/php.ini redirige la fonction mail() :
sendmail_path = "/opt/homebrew/bin/msmtp --host=127.0.0.1 --port=1025 --from=dev@localhost -t"
Chaque mail() de vos projets atterrit désormais sur http://localhost:8025. Aucun email ne quitte jamais la machine.
devstack : toute la stack en une commande
Quatre services, quatre façons de démarrer : c’est exactement le genre de friction qui ramène vers MAMP. Claude Code a donc écrit devstack, un script bash de 440 lignes posé dans /usr/local/bin, qui pilote l’ensemble :
devstack start # demarre MySQL, PHP-FPM, MailHog, Apache
devstack stop # arrete tout
devstack restart # redemarrage dur (tue les workers PHP-FPM satures)
devstack status # teste la connectivite reelle de chaque brique
devstack doctor site # diagnostique un projet precis
devstack fix # debloque les workers PHP-FPM coinces
La subtilité est dans status : il ne vérifie pas que les processus existent, il teste que chaque service répond vraiment. Un curl sur le port 80, un SELECT 1 sur MySQL, un lsof sur le port 9000. Un processus zombie est détecté, pas masqué.
=== Ports ===
:80 -> httpd (Apache)
:443 -> httpd (Apache)
:3306 -> mysqld (MySQL)
:9000 -> php-fpm (pool www)
:1025 -> MailHog (SMTP)
:8025 -> MailHog (interface web)
devstack doctor nomduprojet.test va plus loin : il détecte un WordPress, lit les identifiants dans wp-config.php, teste la connexion à la base, vérifie siteurl et home, compte les feuilles de style chargées et remonte les dernières erreurs PHP du log Apache. Le genre de vérifications qu’on fait à la main, dans le désordre, un soir de panne : le script les fait dans l’ordre, à chaque fois.
Les pièges à connaître
localhost n’est pas 127.0.0.1
Le piège le plus vicieux de la migration. Pour MySQL, localhost signifie « passe par le socket UNIX » et 127.0.0.1 « passe par TCP ». Un site configuré sous un autre environnement, MAMP par exemple, cherchera le socket au mauvais endroit et échouera avec un « can’t connect » incompréhensible, alors que MySQL tourne parfaitement. Sur cette stack, la règle est simple : 127.0.0.1 partout.
define('DB_HOST', '127.0.0.1'); // jamais 'localhost' en local
Le Gateway Timeout des WordPress clonés
Vous clonez un WordPress depuis la production, et tout répond 504 au bout de 30 secondes, même wp-login. Souvenez-vous des directives Timeout : Apache attend PHP-FPM 30 secondes, pas plus. Le coupable habituel est un plugin de sécurité comme Wordfence, qui tente des appels sortants vers son API au chargement de chaque page. En local, l’appel traîne, le worker PHP-FPM reste occupé, Apache abandonne.
Le remède : désactiver le plugin directement, sans passer par l’admin, qui est elle-même en timeout :
wp plugin deactivate wordfence --path=/Users/votrenom/htdocs/nomduprojet
brew services affiche httpd en erreur
Normal. Apache est le seul service lancé hors de brew services, en sudo, à cause du port 80. La colonne d’état de brew services list ne fait pas foi pour lui ; devstack status, si.
Le prompt Ă donner Ă Claude Code
Mes étudiants utilisent tous Claude Code. La tentation est donc grande de lui déléguer ce tutoriel entier, et elle est légitime : c’est exactement ce que j’ai fait. Voici le prompt que je leur donne, à coller tel quel dans une session :
Installe-moi un environnement LAMP complet sur ce Mac avec Homebrew,
sans MAMP ni application graphique :
1. Apache (formule httpd) sur les ports 80 et 443, tournant sous mon
utilisateur macOS, avec les modules proxy_fcgi, ssl et rewrite.
2. PHP, dernière version stable, en PHP-FPM sur 127.0.0.1:9000,
relié à Apache par un bloc FilesMatch.
3. MySQL en service brew, avec root/root en local.
4. Un dossier ~/htdocs pour tous mes projets (AllowOverride All).
5. Un vhost HTTP et un vhost HTTPS par projet, en .test,
déclarés dans /etc/hosts.
6. HTTPS local avec mkcert (autorité installée dans le trousseau).
7. MailHog et msmtp pour capturer la fonction mail() de PHP.
8. Un script devstack start|stop|restart|status dans /usr/local/bin.
Règles : explique-moi chaque étape avant de l’exécuter, demande ma
validation avant toute commande sudo, et termine par un test complet :
une page phpinfo() servie en HTTPS sur monprojet.test, et un mail()
visible dans MailHog sur localhost:8025.
Les règles de la fin ne sont pas décoratives. L’IA installera tout, mais l’environnement reste le vôtre : chaque étape validée est une étape comprise. Je recommanderais de suivre ce tutoriel à la main une première fois, puis de laisser Claude Code le rejouer sur les machines suivantes. Dans cet ordre-là .
Ce que ça change au quotidien
- La transparence bat le confort. Un fichier de configuration qu’on lit vaut mieux qu’une interface qui le cache. Mes pannes n’ont pas disparu : elles sont devenues diagnosticables.
- Scriptable veut dire transmissible. Ce tutoriel existe parce que la stack est du texte : des commandes, des fichiers de conf, un script bash. Une configuration MAMP ne s’enseigne pas, elle se montre.
- Le coût est nul. Toutes les briques sont libres et gratuites. La licence MAMP Pro finançait surtout le confort de ne pas apprendre.
- L’IA a changé le calcul. Monter cette stack à la main demandait une journée de documentation éparse ; c’est ce qui rendait MAMP attractif. Claude Code me l’a montée fin mars 2026, migration des 98 vhosts comprise, pendant que je faisais autre chose.
Qui fait quoi ? Le rappel
Six briques, six rôles. À garder sous la main :
- Homebrew - le gestionnaire de paquets : il installe, met à jour et désinstalle toutes les briques ci-dessous. brew.sh
- Apache - le serveur web : il reçoit les requêtes du navigateur et sert vos sites, un vhost par projet. httpd.apache.org
- PHP et PHP-FPM - le langage qui exécute votre code ; FPM, son gestionnaire de processus, répond à Apache sur le port 9000. php.net
- MySQL - la base de données : elle stocke les contenus de vos applications, en TCP sur le port 3306. mysql.com
- mkcert - la fabrique de certificats : elle rend le HTTPS local accepté par votre navigateur. GitHub
- MailHog - le filet à emails : il intercepte tout ce que PHP envoie et l’affiche sur le port 8025. GitHub