Docker - Configurer votre localhost pour utiliser SSL
Configurez votre localhost Docker pour utiliser SSL (HTTPS) sans avertissements du navigateur. Ce guide pas à pas utilise mkcert pour générer des certificats de confiance pour vos containers Apache, Nginx et PHP.
Traduction automatique
Journal des modifications
openssl with mkcert for trusted local certificates covering both localhost and 127.0.0.1; removed the obsolete Chrome flags workaround; added Windows/WSL2 CA import instructions.
Ce guide ajoute SSL à un site Apache dockerisé pour que https://localhost fonctionne sans avertissement du navigateur. Au lieu d'un certificat auto-signé OpenSSL, il utilise mkcert pour générer un certificat localement approuvé couvrant à la fois localhost et 127.0.0.1. Des sections bonus couvrent la même configuration pour nginx et PHP, ainsi que la façon d'importer la CA racine de mkcert dans Windows quand votre navigateur tourne en dehors de WSL2.
Dans un article précédent, j'ai expliqué comment lancer un site HTML statique en quelques secondes.
Le résultat était un site tournant sur votre ordinateur, en http. Allons un pas plus loin et voyons comment configurer Docker pour utiliser https, c'est-à-dire SSL et le chiffrement.
Dans cet article, vous apprendrez à utiliser Apache, nginx et PHP sur votre machine et à pouvoir démarrer https://localhost.
Une fois HTTPS opérationnel en local, l'article Le fichier .htaccess d'Apache contient les directives pour le forcer en production (avec le préchargement HSTS). Et pour chiffrer des fichiers plutôt que du trafic, voyez Chiffrer des données sensibles avec SSL et Docker.
Notre objectif principal est d'utiliser une image Docker Apache pour permettre l'accès à localhost en http ou en https. Pour cela, nous avons besoin d'un certificat SSL.
Nous allons utiliser mkcert, un outil qui crée une autorité de certification (CA) locale et émet des certificats signés par celle-ci. Une fois la CA installée dans le magasin de confiance de votre navigateur, https://localhost fonctionne sans aucun avertissement de sécurité — et curl fonctionne sans --insecure.
Ensuite, dans la section Bonus, nous ferons la même chose pour nginx et pour PHP.
Commençons avec juste http
Première chose : créons notre bac à sable, c'est-à-dire un petit site que nous utiliserons pour cet article.
Après une rapide recherche sur github.com, j'ai trouvé un joli template html5/css3 gratuit d'une seule page : https://github.com/peterfinlan/Sedna.
Créer un dossier temporaire et télécharger un site statique d'exemple
Téléchargeons le site de démo Sedna dans un dossier temporaire sur notre disque dur, décompressons le fichier, renommons le dossier par défaut Sedna-master en src et lançons le site avec Docker :
Une fois ces commandes lancées, rendez-vous sur http://localhost:80 et vous obtiendrez ceci :

Terriblement simple, non ?
Le site tourne avec le protocole http mais https n'est pas encore possible. Alors, continuons...
Pour l'instant, supprimez le container en cours d'exécution ; nous le recréerons plus tard :
Création de quelques fichiers dont nous aurons besoin
Comme nous l'avons vu, nous pouvons lancer docker run -d --name static-site -p 80:80 -v ./src:/usr/local/apache2/htdocs httpd:2.4 et bingo, le site tourne en http.
Nous ne pouvons pas utiliser cette seule ligne pour https car, entre autres, nous avons besoin d'un certificat SSL et nous devons configurer Apache pour l'utiliser.
Pour rester propre et maintenable, créons quelques fichiers.
Assurez-vous d'être dans le dossier /tmp/https_localhost et créez les fichiers suivants.
FROM httpd:2.4
COPY httpd/my-site.conf /etc/apache2/sites-available/my-site.confCe Dockerfile crée une image Docker basée sur Apache httpd version 2.4, puis copie un fichier de configuration de site personnalisé dans le répertoire de configuration Apache. Il configure essentiellement un serveur web Apache avec une configuration spécifique pour un site.
Le deuxième fichier dont nous aurons besoin s'appelle compose.yaml avec le contenu suivant :
services: apache: build: context: . ports: - "80:80" volumes: - ./src:/usr/local/apache2/htdocsCe fichier Docker Compose définit un service Apache qui construit une image à partir du répertoire courant, expose le port 80 sur la machine hôte, et monte le dossier src local dans le répertoire de documents web du conteneur Apache.
compose.yaml est strictement équivalent à docker-compose.yml
Le troisième fichier dont nous aurons besoin doit être créé dans un dossier httpd et doit s'appeler my-site.conf avec le contenu suivant :
<VirtualHost *:80> DocumentRoot /usr/local/apache2/htdocs ServerName localhost
<Directory /usr/local/apache2/htdocs> AllowOverride All RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.html [QSA,L] </Directory>
ErrorLog /usr/local/apache2/logs/error.log CustomLog /usr/local/apache2/logs/access.log combined
</VirtualHost>Ce fichier configure un hôte virtuel Apache qui écoute sur le port 80 et sert des fichiers depuis /usr/local/apache2/htdocs. Il active la réécriture d'URL pour rediriger toutes les requêtes vers index.html, sauf celles correspondant à des fichiers existants, ce qui est typique pour les applications single-page. Les logs d'erreur et d'accès sont dirigés vers des fichiers spécifiques.
Pour un container basé sur Apache, le site doit être copié dans le dossier /usr/local/apache2/htdocs et non /var/www/html ; ce dernier est pour une image PHP.
Tout est maintenant en place pour activer l'accès http. Toujours dans le dossier /tmp/https_localhost, lancez simplement docker compose up -d --build pour construire notre image Docker personnalisée et démarrer un container, c'est-à-dire lancer le site.
Vous obtiendrez quelque chose comme ceci dans la console :

Si nous regardons Docker Desktop, liste des containers, nous verrons notre projet (appelé https_localhost puisque c'est le nom de notre dossier dans cet article) et nous verrons notre service apache tourner sur le port 80.

En accédant à http://localhost:80 avec le navigateur, nous obtenons notre site, opérationnel :

Bien, nous avons donc la confirmation que les trois fichiers créés ci-dessus fonctionnent et nous donnent un accès http. Allons plus loin avec https.
Commençons le voyage vers https
Nous avons trois actions principales à mener :
- Créer notre certificat SSL,
- Apprendre à Apache comment gérer notre certificat et
- Mettre à jour quelques-uns de nos fichiers Docker.
Créer le certificat SSL
Toujours dans notre dossier /tmp/https_localhost, créez un dossier appelé ssl ; c'est là que nous créerons notre certificat.
D'abord, installez mkcert si ce n'est pas déjà fait :
Prérequis : mkcert
Vérifier :
Générez ensuite la CA locale et le certificat :
mkcert -install crée une CA locale et l'enregistre dans le magasin de confiance de votre système. mkcert émet ensuite server.crt et server.key — les deux fichiers arrivent directement dans le dossier ssl/.
Le certificat couvre à la fois localhost (DNS) et 127.0.0.1 (IP), donc accéder au site par l'une ou l'autre adresse fonctionne sans avertissement du navigateur.
Valable deux ans
Les certificats générés par mkcert sont valables deux ans. Pour les renouveler, relancez simplement la commande mkcert.
Pour une image Apache, les fichiers doivent être nommés ainsi, server.crt et server.key
Comme expliqué sur https://hub.docker.com/_/httpd, les deux fichiers doivent être nommés ainsi : server.crt et server.key.
Mise à jour de notre fichier de configuration Apache
Nous devons mettre à jour notre fichier de configuration Apache et ajouter un Virtual host pour le port 443, le port standard pour SSL.
Éditez le fichier httpd/my-site.conf existant et ajoutez le contenu ci-dessous.
<VirtualHost *:80> DocumentRoot /usr/local/apache2/htdocs ServerName localhost
<Directory /usr/local/apache2/htdocs> AllowOverride All RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.html [QSA,L] </Directory>
ErrorLog /usr/local/apache2/logs/error.log CustomLog /usr/local/apache2/logs/access.log combined
</VirtualHost>
// highlight-next-line<VirtualHost *:443> // highlight-next-line DocumentRoot /usr/local/apache2/htdocs // highlight-next-line ServerName localhost // highlight-next-line
// highlight-next-line SSLEngine on // highlight-next-line SSLCertificateFile "/usr/local/apache2/conf/server.crt" // highlight-next-line SSLCertificateKeyFile "/usr/local/apache2/conf/server.key" // highlight-next-line
// highlight-next-line <Directory /usr/local/apache2/htdocs> // highlight-next-line AllowOverride All // highlight-next-line RewriteEngine On // highlight-next-line RewriteCond %{REQUEST_FILENAME} !-f // highlight-next-line RewriteRule ^(.*)$ index.html [QSA,L] // highlight-next-line </Directory> // highlight-next-line
// highlight-next-line ErrorLog /usr/local/apache2/logs/error.log // highlight-next-line CustomLog /usr/local/apache2/logs/access.log combined // highlight-next-line
// highlight-next-line</VirtualHost>Ce fichier configure deux hôtes virtuels Apache : l'un écoute sur le port 80 (HTTP) et l'autre sur le port 443 (HTTPS). Chacun redirige les requêtes vers des fichiers non-existants vers index.html, ce qui est typique pour les applications single-page. Le second hôte active le SSL/TLS avec les certificats appropriés.
Les chemins sont cruciaux !
Les noms de dossiers et de fichiers ont une importance majeure. Les deux fichiers de certificat doivent être enregistrés dans le dossier /usr/local/apache2/conf/ et être nommés server.crt et server.key. Ceci parce que nous utilisons une image Docker Apache ; ce n'est pas la même chose si vous utilisez, par exemple, une image PHP+Apache.
Mise à jour de notre fichier compose.yaml
Éditez le fichier compose.yaml existant et ajoutez la nouvelle ligne surlignée ci-dessous
services: apache: build: context: . ports: - "80:80" # highlight-next-line - "443:443" volumes: - ./src:/usr/local/apache2/htdocsCe fichier Docker Compose définit un service Apache avec une image construite à partir du répertoire courant. Le service expose les ports HTTP et HTTPS vers l'hôte et monte un répertoire local pour servir les fichiers web.
Nous devons donc simplement exposer le port 443 du container vers notre host. Ce port est le port standard du protocole https.
Et, enfin, mise à jour de notre fichier Dockerfile
Le dernier fichier à mettre à jour est notre Dockerfile existant, avec les nouvelles lignes ci-dessous :
# cspell:disableFROM httpd:2.4# highlight-next-line
# highlight-next-lineRUN apt-get update \ # highlight-next-line && apt-get install -y --no-install-recommends apache2-utils libapache2-mod-php openssl \ # highlight-next-line && rm -rf /var/lib/apt/lists/*# highlight-next-line
# highlight-next-lineCOPY ssl/server.crt /usr/local/apache2/conf/server.crt# highlight-next-lineCOPY ssl/server.key /usr/local/apache2/conf/server.key# highlight-next-line
COPY httpd/my-site.conf /etc/apache2/sites-available/my-site.conf# highlight-next-line
# highlight-next-lineRUN sed -i \ # highlight-next-line -e 's/^#\(Include .*httpd-ssl.conf\)/\1/' \ # highlight-next-line -e 's/^#\(LoadModule .*mod_ssl.so\)/\1/' \ # highlight-next-line -e 's/^#\(LoadModule .*mod_socache_shmcb.so\)/\1/' \ # highlight-next-line /usr/local/apache2/conf/httpd.conf# highlight-next-line
# highlight-next-lineRUN a2enmod ssl \ # highlight-next-line && a2enmod rewrite \ # highlight-next-line && a2dissite 000-default default-ssl \ # highlight-next-line && a2ensite my-siteCe Dockerfile construit une image Apache HTTP Server avec support SSL/TLS et PHP. Il installe les dépendances nécessaires, copie les certificats SSL et la configuration personnalisée du site, active les modules SSL et de réécriture, puis désactive les sites par défaut pour activer uniquement le site personnalisé.
Ici, il y a pas mal de choses à faire. Nous devons installer (apt-get install) quelques binaires Linux pour permettre plus tard l'utilisation de a2enmod et du protocole SSL.
Nous devons copier notre certificat SSL et notre clé privée (fichiers server.crt et server.key) au bon endroit.
Nous devons aussi mettre à jour le fichier httpd.conf par défaut d'Apache pour inclure certains fichiers et certains modules.
Enfin, nous devons activer SSL et le mod rewrite d'Apache, désactiver les sites standards (000-default et default-ssl) et activer le nôtre (appelé my-site).
Prêt à lancer le site en http et en https
À ce stade, vous devriez avoir une structure de dossiers comme celle-ci :
- Un dossier appelé
httpdcontenant un fichier appelémy-site.conf, le fichier de configuration d'Apache, - Un dossier appelé
srcavec les fichiers du site statique HTML (beaucoup de fichiers, venant de Github), - Un dossier appelé
sslavec le certificat SSL que nous avons créé (un certificat public appeléserver.crtet une clé privée appeléeserver.key), - Un fichier appelé
compose.yamlet - Un fichier appelé
Dockerfile
Lancer le site
Nous devons mettre à jour notre image Docker puisque nous avons modifié le Dockerfile, donc lançons docker compose up -d --build.
Si nous retournons dans Docker Desktop, nous devrions voir ceci :

Nous avons permis à notre site de tourner sur le port 80 (http) et 443 (https).
Maintenant que tout est en place, rendez-vous sur https://localhost/ et vous obtiendrez le site :

Parce que nous avons utilisé mkcert -install plus tôt, le navigateur fait déjà confiance à la CA locale qui a signé notre certificat — le cadenas est donc vert et il n'y a aucun avertissement de sécurité.
Vous utilisez Windows ou WSL2 ?
mkcert -install enregistre la CA dans le magasin système Linux. Si votre navigateur tourne sur Windows, vous devez aussi importer la CA racine dans Windows. Voyez la section Bonus ci-dessous pour les instructions.
Attention aux noms de fichiers et de dossiers
J'ai passé de nombreuses heures — trop — à écrire cet article. Ça semblait simple ; plusieurs articles ici et là donnent l'impression que ce serait facile, mais ça ne l'était pas.
C'est parce que la majorité des exemples que j'ai trouvés utilisaient une image PHP ou Nginx et pas Apache. Les noms de fichiers et de dossiers ne sont pas les mêmes, et il faut utiliser soigneusement ceux qu'Apache exige. Ce n'était pas explicite du tout.
Utiliser curl
Parce que mkcert -install a enregistré la CA locale dans le magasin de confiance du système, curl fonctionne sans aucun flag supplémentaire :
Si vous êtes sur une machine où la CA n'est pas installée (ou si vous avez sauté mkcert -install), vous obtiendrez :
Dans ce cas, vous pouvez soit passer la CA explicitement, soit utiliser --insecure comme contournement rapide :
Bonus - Configurer nginx pour utiliser SSL
Si vous ne voulez pas Apache mais nginx, utilisez plutôt les fichiers ci-dessous.
C'est globalement la même chose mais vous remarquerez quelques différences, comme dans les chemins et le fait que nous n'avons pas besoin d'installer de dépendances supplémentaires pour PHP.
FROM nginx:latest
RUN apt-get update \ && apt-get install -y --no-install-recommends openssl \ && rm -rf /var/lib/apt/lists/*
COPY ssl/server.crt /etc/nginx/ssl/server.crtCOPY ssl/server.key /etc/nginx/ssl/server.key
COPY httpd/my-site.conf /etc/nginx/conf.d/my-site.confCe Dockerfile construit une image nginx en installant openssl pour la gestion SSL, puis copie les certificats SSL et le fichier de configuration nginx dans l'image. Le nettoyage du cache apt à la fin réduit la taille de l'image finale.
Le deuxième fichier dont nous aurons besoin s'appelle compose.yaml avec le contenu suivant :
services: nginx: build: context: . ports: - "80:80" - "443:443" volumes: - ./src:/usr/share/nginx/htmlCe fichier Docker Compose définit un service nginx qui construit une image à partir du répertoire courant, expose les ports HTTP et HTTPS, et monte le dossier src local dans le répertoire de contenu web du conteneur.
compose.yaml est strictement équivalent à docker-compose.yml
Le troisième fichier dont nous aurons besoin doit être créé dans un dossier httpd et doit s'appeler my-site.conf avec le contenu suivant :
server { listen 80;
server_name localhost;
root /usr/share/nginx/html;}
server { listen 443 ssl; listen [::]:443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key;
root /usr/share/nginx/html; }Ce fichier de configuration nginx définit deux serveurs : le premier écoute sur le port 80 (HTTP non chiffré) et le second sur le port 443 (HTTPS avec SSL/TLS). Les deux servent des fichiers depuis le même répertoire racine et répondent aux requêtes dirigées vers localhost.
Bonus - Configurer PHP pour utiliser SSL
Si vous ne voulez pas Apache mais PHP (parce que vous devez exécuter du code PHP), utilisez plutôt les fichiers ci-dessous.
C'est globalement la même chose mais vous remarquerez quelques différences, comme dans les chemins et le fait que nous n'avons pas besoin d'installer de dépendances supplémentaires pour PHP.
Créez un fichier appelé Dockerfile avec le contenu suivant :
# cspell:disable
FROM php:8.3-apache
COPY ssl/server.crt /etc/ssl/certs/server.crtCOPY ssl/server.key /etc/ssl/private/server.key
COPY httpd/my-site.conf /etc/apache2/sites-available/my-ssl.conf
RUN a2enmod ssl && \ a2enmod rewrite && \ a2dissite 000-default default-ssl && \ a2ensite my-sslCe Dockerfile crée une image Docker basée sur PHP 8.3 avec Apache, configure SSL en copiant les certificats et clés, puis active les modules Apache nécessaires et désactive les sites par défaut au profit d'une configuration personnalisée.
Le deuxième fichier dont nous aurons besoin s'appelle compose.yaml avec le contenu suivant :
services: php: build: context: . ports: - "80:80" - "443:443" volumes: - ./src:/var/www/html/Ce fichier Docker Compose définit un service PHP qui construit une image Docker à partir du répertoire courant, expose les ports HTTP et HTTPS, et monte le dossier src local dans le conteneur pour que le code PHP soit accessible.
compose.yaml est strictement équivalent à docker-compose.yml
Le troisième fichier dont nous aurons besoin doit être créé dans un dossier httpd et doit s'appeler my-site.conf avec le contenu suivant :
<VirtualHost *:80> DocumentRoot /var/www/html ServerName localhost
<Directory /var/www/html> AllowOverride All RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.html [QSA,L] </Directory>
ErrorLog /var/log/apache2/error.log CustomLog /var/log/apache2/access.log combined
</VirtualHost>
<VirtualHost *:443> DocumentRoot /var/www/html ServerName localhost
SSLEngine on SSLCertificateFile "/etc/ssl/certs/server.crt" SSLCertificateKeyFile "/etc/ssl/private/server.key"
<Directory /var/www/html> AllowOverride All RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.html [QSA,L] </Directory>
ErrorLog /var/log/apache2/error.log CustomLog /var/log/apache2/access.log combined
</VirtualHost>Ce fichier configure deux hôtes virtuels Apache pour servir la même application web sur HTTP (port 80) et HTTPS (port 443). Les deux hôtes redirigent toutes les requêtes vers index.html, ce qui est typique pour les applications single-page qui gèrent leur propre routage côté client. Le second hôte active SSL/TLS avec les certificats appropriés.
Bonus - Installer la CA racine mkcert dans votre navigateur
Quand vous lancez mkcert -install, la CA locale est ajoutée au magasin de confiance de votre OS actuel. C'est suffisant pour les navigateurs natifs Linux (par exemple Firefox ou Chrome tournant directement dans Ubuntu).
Si votre navigateur tourne sur Windows — y compris quand vous travaillez dans WSL2 ou un devcontainer Docker — vous devez aussi importer la CA racine dans le magasin de certificats Windows. Ça ne se fait qu'une fois par machine.
Trouver le fichier de la CA racine
rootCA.pem est le certificat public de votre CA locale. Gardez rootCA-key.pem privé — quiconque le possède peut signer des certificats auxquels votre système fera confiance.
Importer dans Windows (depuis WSL2 ou PowerShell)
Depuis WSL2, vous pouvez utiliser directement le certutil.exe de Windows (WSL2 a accès aux exécutables Windows) :
Depuis un terminal PowerShell lancé en tant qu'Administrateur :
Ou manuellement : double-cliquez sur rootCA.pem → Installer le certificat → Ordinateur local → Placer tous les certificats dans le magasin suivant → Autorités de certification racines de confiance.
Après l'import, redémarrez Chrome ou Edge et https://localhost (ou https://127.0.0.1) affichera un cadenas vert sans avertissement.
Magasin de confiance système Linux uniquement
Si vous avez seulement besoin que curl ou d'autres outils en ligne de commande fassent confiance à la CA (sans l'installer dans Windows), copiez la CA racine dans le magasin système :
Le fichier doit avoir l'extension .crt quand il est placé dans /usr/local/share/ca-certificates
Après cela, curl https://localhost fonctionne sans aucun flag supplémentaire.

