Aller au contenu principal

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.

· 13 minutes de lecture
Voir la source
Christophe
Amoureux de Markdown, WSL et Docker ~ Curieux insatiable.
Cet article existe aussi en anglais — lire la version originale.

Traduction automatique

Cette traduction a été produite par une IA. Elle peut contenir des contresens ou des maladresses, en particulier sur les termes techniques. En cas de doute, consultez l'article de référence en anglais — c'est lui qui fait foi.

Journal des modifications

Dernière
Replaced raw 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.

Docker - Configurer votre localhost pour utiliser SSL

⚡
TL;DR

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 :

Vos valeurs pour cette page
défaut
défaut
S'applique aux commandes de cette pageEnregistré uniquement sur cet appareil
>user@machine: ~/yourproject

Une fois ces commandes lancées, rendez-vous sur http://localhost:80 et vous obtiendrez ceci :

http://localhost:80

Site tournant en http

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 :

>user@machine: ~/yourproject

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.conf

Ce 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/htdocs

Ce 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 :

Docker run http

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.

Docker Desktop - Tourne sur le port 80

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

http://localhost:80

Site tournant en http

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 :

  1. Créer notre certificat SSL,
  2. Apprendre à Apache comment gérer notre certificat et
  3. 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

>user@machine: ~/yourproject

Vérifier :

>user@machine: ~/yourproject

Générez ensuite la CA locale et le certificat :

>user@machine: ~/yourproject

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/htdocs

Ce 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:disable
FROM httpd:2.4
# highlight-next-line
# highlight-next-line
RUN 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-line
COPY ssl/server.crt /usr/local/apache2/conf/server.crt
# highlight-next-line
COPY 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-line
RUN 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-line
RUN a2enmod ssl \
# highlight-next-line
&& a2enmod rewrite \
# highlight-next-line
&& a2dissite 000-default default-ssl \
# highlight-next-line
&& a2ensite my-site

Ce 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 :

La structure des dossiers

  1. Un dossier appelé httpd contenant un fichier appelé my-site.conf, le fichier de configuration d'Apache,
  2. Un dossier appelé src avec les fichiers du site statique HTML (beaucoup de fichiers, venant de Github),
  3. Un dossier appelé ssl avec le certificat SSL que nous avons créé (un certificat public appelé server.crt et une clé privée appelée server.key),
  4. Un fichier appelé compose.yaml et
  5. 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 :

Docker Desktop - Tourne sur les ports 80 et 443

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 :

https://localhost/

Site tournant en https

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 :

>user@machine: ~/yourproject

Si vous êtes sur une machine où la CA n'est pas installée (ou si vous avez sauté mkcert -install), vous obtiendrez :

>user@machine: ~/yourproject

Dans ce cas, vous pouvez soit passer la CA explicitement, soit utiliser --insecure comme contournement rapide :

>user@machine: ~/yourproject

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.crt
COPY ssl/server.key /etc/nginx/ssl/server.key
COPY httpd/my-site.conf /etc/nginx/conf.d/my-site.conf

Ce 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/html

Ce 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.crt
COPY 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-ssl

Ce 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​

>user@machine: ~/yourproject

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) :

>user@machine: ~/yourproject

Depuis un terminal PowerShell lancé en tant qu'Administrateur :

>user@machine: ~/yourproject

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 :

>user@machine: ~/yourproject

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.


Cet article vous a-t-il été utile ?
Avez-vous suivi les étapes de cet article ?