WSL - Web Development mit SSL
Das Windows Subsystem für Linux (WSL) bietet eine leistungsstarke Umgebung für Webentwicklung unter Windows 11. Die Integration von SSL in lokale Entwicklungsprojekte ist dabei ein wichtiger Aspekt, um produktionsnahe Bedingungen zu simulieren. Diese Anleitung führt durch den Prozess der WSL-Installation und -Konfiguration für Webentwicklung mit funktionierender SSL-Verschlüsselung. Mit den richtigen Tools und Einstellungen lässt sich eine effiziente Linux-basierte Entwicklungsumgebung direkt unter Windows nutzen, ohne Kompromisse bei Sicherheitsfeatures eingehen zu müssen.
Inhaltsverzeichnis
Voraussetzungen
Damit dieser Artikel Sinn ergibt und auch hilfreich ist, sollten ein paar Annahmen erläutert bzw. ein paar Voraussetzungen erfüllt werden.
Ich nehmen in diesem Artikel an, dass folgende Punkte gegeben sind.
Windows 11:
Das Betriebssystem ist Windows 11WSL 2:
WSL in Version 2 ist bereits aktiviert und Ubuntu ist installiert
Die Version von WSL könnt ihr wie folgt prüfen.
wsl --list --verbose
Hierbei solltet ihr ungefähr folgendes Ergebnis erhalten. Eine Auflistung von vorhandenen WSL-Installationen mit der Version in der rechten Spalte.
wsl --status
Bei dieser Möglichkeit erhaltet ihr die Standardversion für WLS, die verwendet wird. Und auch die Standard-Distribution.
Installation - Apache
Wir beginnen mit der Installation von Apache. Apache ist ein verbreiteter Web-Server. Wir werden ihn verwenden, um unsere lokale Web-Projekte auszuliefern und für unsere lokale Entwicklung einsetzen.
Das Paket installieren.
sudo apt install apache2
Nach der Installation sollte beim Aufruf von http://localhost
der Apache-Server mit einer Standard-Website antworten. Das ist ein Zeichen dafür, dass dieser Aktiv ist.
Den Status von Apache kann wie folgt prüfen.
sudo systemctl status apache2
Hier noch ein paar wichtige Befehle, die immer wieder während der Arbeit mit Apache und eigenen lokalen Projekten benötigt werden.
# Apache stoppen
sudo systemctl stop apache2
# Apache starten
sudo systemctl start apache2
# Apache neustarten
sudo systemctl restart apache2
Installation - PHP
Im nächsten Schritt installieren wir PHP. Sehr viele Websites werden mit PHP betrieben und daher ist es nahezu unerlässlich. In diesem Beispiel (Artikel) setze ich Ubuntu 24.04 ein und diese Distribution hatte PHP in Version 8.3 als Paket.
PHP ohne Module wird wie folgt installiert.
sudo apt install php
PHP mit den meisten Modulen wird wie folgt installiert.
sudo apt install php php-mysql php-curl php-xml php-mbstring php-intl php-gd php-zip php-bcmath php-imagick
Nach der Installation kann die aktive Version folgendermaßen geprüft werden.
php --version
PHP-INI Versionen
Für spätere Anpassungen wird man ab und zu auch die INI-Konfiguration bearbeiten müssen. Hier sollte man wissen, welche die korrekte ist und wo sie sich befindet.
Bei PHP unter einem Ubuntu-Server in Kombination mit Apache gibt es generell 2 php.ini
Dateien. Je nach PHP-Version und Linux-Version kann sich der Pfad unterscheiden.
Standardmäßig befinden sich die unterschiedlichen INI-Dateien im folgenden übergreifenden Ordner: /etc/php/8.3
.
Und in diesen Ordnern liegt jeweils eine php.ini
, die bestimmte Konfiguration beinhaltet. Für Web-Development wird man in der Regel mit der Apache-Version arbeiten müssen.
PHP-INI Pfad herausfinden
Um den Pfad zu der jeweiligen PHP-INI zu finden, falls dieser von der Standard-Konfiguration abweicht, gibt es mehrere Möglichkeiten und eine Sache zu beachten.
Wie weiter oben erwähnt, gibt es unterschiedliche Versionen von PHP-INI. Und je nach Ausführungskontext wie entweder die eine oder die andere Konfiguration geladen.
Wenn wir also innerhalb von WSL-Terminal folgenden Befehl ausführen php --ini
, erhalten wir den Pfad zu der CLI-Version, also der Terminal-Version.
Um die Ausgabe nur auf die eine Datei zu begrenzen, verwende ich grep
.
php --ini | grep php.ini
Als Ergebnis erhalten wir folgendes.
Hier haben die den Pfad zu der php.ini
im Ordner CLI erhalten. Warum? Weil wir den Befehl in der Shell ausgeführt. Der Apache-Kontext war hier nicht gegeben, dafür aber der CLI-Kontext.
Um den Pfad der Apache-Version zu erhalten, müssen wir einen anderen Weg nehmen. Dafür benötigen wir irgendeine PHP-Datei, die wir unter dem Localhost-Root platzieren und über eine URL ansprechen/ausführen. In diesem Fall würde Apache die Auslieferung übernehmen und der Apache-Kontext wäre gegeben.
Wir erstellen im Standard-Root /var/www/html
eine Datei info.php
. In dieser Datei platzieren wir folgenden Inhalt.
<?php phpinfo(); ?>
Diese Datei können wir dann (immer noch im Terminal) folgendermaßen aufrufen. Wir verwenden hier wieder grep
, um die Ausgabe auf den notwendigen Eintrag zu beschränken.
curl http://localhost/info.php | grep "Loaded Configuration File"
Installation - MariaDB
Sehr verbreit sind die MySQL und MariaDB Datenbank in der Web Entwicklung. Nahezu jedes Framework oder jedes CMS setzt irgendeine Art von SQL-Datenbank ein. Meistens entweder MySQL oder MariaDB. Ich verwende in diesem Beispiel und auch für meine lokale Entwicklungen MariaDB.
MariaDB wird mit folgendem Befehl installiert.
sudo apt install mariadb-server
MariaDB - Root Passwort
Nach der Installation empfehle ich ein Root-Passwort zu setzen. Man kann direkt nach der Installation MariaDB auch über sudo mariadb
verwenden. Da viele CMS oder Frameworks neben einer SQL-Datenbank auch einen SQL-Benutzer mit einem SQL-Passwort angegeben haben möchten, müssen wir dafür sorgen, dass es diesen gibt. Da es sich hierbei um lokale Entwicklung handelt, bei der keine Notwendigkeit besteht pro CMS oder Projekt einen eigenen Benutzer mit einer eigenen Datenbank zu erstellen, verwende ich für die meisten Fälle einfach den root
Benutzer.
Direkt nach der Installation rufe ich folgendes Programm auf.
sudo mariadb-secure-installation
Hier startet ein Wizard, bei dem ein paar Fragen gestellt werden, die man beantworten muss.
An diesem Punkt wird man noch kein Root-Passwort haben. Also klicken wir hier einfach auf “Enter” und gehen zum nächsten Punkt bzw. zur nächsten Frage.
Hier geben wir “Y” ein.
Im nächsten Step wird uns die Frage gestellt, ob das Root-Passwort geändert werden soll. Selbstverständlich geben wir hier auch “Y” ein, um das Passwort zu setzen (oder zu ändern).
Nun werden wir aufgefordert das neue Root-Passwort zwei Mal nacheinander einzugeben.
Die restlichen Fragen sind für lokale Entwicklung in der Regel weniger wichtig. Ich beantworte sie immer mit “Y”. Hierbei geht es um das Entfernen der anonymen Benutzer, entfernten Zugriff und das Entfernen der Test-Datenbank. Alles Fragen, die lokal nicht von großer Bedeutung sind.
Anmeldung mit Passwort
Hat man nun alles korrekt eingerichtet, sollte der MariaDB-Server neugestartet werden.
sudo systemctl restart mariadb
Um den Status von MariaDB-Server zu prüfen, kann folgende Anweisung verwendet werden.
sudo systemctl status mariadb
Da jetzt alles läuft, können wir mit dem Root-Benutzer und dem gesetzten Passwort uns am MariaDB-Server anmelden.
mariadb -u root -p
Bei erfolgreicher Eingabe des korrekten Passworts, landen wir in der MariaDB-Shell.
Installation - mkcert (Windows 11)
Wir möchten SSL auch für unsere lokale Projekte einsetzen. Dafür verwende ich mkcert. Dieses Tool muss auf beiden Seiten installiert wird. Einmal unter Windows und einmal direkt in WSL.
Für die Installation von mkcert unter Windows werden wir choco
Paketverwaltung (Chocolatey) brauchen. Diese können wir mit folgendem Befehl installieren.
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
Nachdem choco
auf dem System verfügbar ist, können wir nun mkcert
installieren.
choco install mkcert
Root-Zertifikat installieren
Nach der Installation von mkcert
muss das Root-Zertifikat installiert werden. Das erfolgt mit dem folgenden Befehl von mkcert
.
mkcert -install
Hinweis: -install
mit einem Bindestrich.
Um sich den Pfad des Root-Zertifikats anzuzeigen, können wir folgende Anweisung verwenden.
mkcert -CAROOT
Installation - mkcert (WSL Ubuntu)
Im zweiten Schritt installieren wir mkcert
unter Ubuntu in WSL. Für die Installation verwende ich Homebrew. Man kann allerdings mkcert
auch bequem manuell installieren. In diesem Fall mache ich es mit Homebrew.
Homebrew installieren
Bevor man Homebrew unter Ubuntu installiert, empfiehlt es sich, folgende Pakete zu installieren, wenn sie noch nicht installiert sind.
sudo apt install build-essential libnss3-tools curl file git
Im Anschluss kann dann Homebrew über das offizielle Installationsskript installiert werden.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Am Ende des Installationsvorgangs erhält man einen Hinweis, dass bestimmte Einträge in der .bashrc
vorhanden müssen, damit Homebrew der Shell bekannt ist.
In der Regel sollte folgende Zeile in der .bashrc
vorhanden sein.
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
Um zu prüfen, ob Homebrew korrekt installiert ist, kann man den Befehl doctor
verwenden. Bekommt man die Ausgabe wie Your system is ready to brew.
, ist alles in Ordnung und man kann Homebrew verwenden.
brew doctor
mkcert installieren
Nun können wir mkcert
mit Homebrew installieren.
brew install mkcert
Wenn alles korrekt installiert wurde, können wir prüfen, ob mkcert
unserer Shell bereits bekannt ist.
which mkcert
Oder, alternativ, kann man auch die Version prüfen.
mkcert --version
Root-Zertifikat installieren
Nun muss auch unter WSL ein Root-Zertifikat installiert werden. Der Befehl ist identisch.
mkcert -install
Auch in WSL kann man sich den Pfad zum Root-Zertifikat anzeigen. Diesen werden wir bald brauchen.
mkcert -CAROOT
Zertifikate tauschen
WICHTIG: Dieser Schritt muss ausgeführt werden, bevor das erste Projekt-Zertifikat erstellt wird!
Bei Verwendung von Windows mit WSL besteht die Situation, dass wir unterschiedliche Umgebungen haben. Wir werden die Websites mit einem Browser in Windows (Client) verwenden. Windows hat ein anderes Root-Zertifikat, als WSL. Mit dieser Tatsache würden unsere Zertifikate nicht funktionieren.
Daher ist es sehr wichtig, die Zertifikate zu vereinheitlichen.. Das können wir tun, indem wir auf beiden Seiten das gleiche Root-Zertifikat haben.
Wie kriegen wir das erreicht? Indem wir das Zertifikat unter WSL mit dem Zertifikat von Windows überschreiben. Dazu sollte man beide CAROOT
Pfade öffnen. Dann löschen wir die Zertifikate unter WSL und kopieren (nicht verschieben) die Zertifikatsdateien von Windows nach WSL.
Hier nochmals die Abfolge zusammengefasst.
- Ordner mit Root-Zertifikatsdateien von Windows öffnen
- Ordner mit Root-Zertifikatsdateien von WSL öffnen
- Die Linux (WSL) Root-Zertifikatsdateien entfernen
- Die Root-Zertifikatsdateien von Windows in den Ordner (
CAROOT
) von Linux (WSL) kopieren
VirtualHost erstellen
Wir brauchen nun ein Beispiel-Projekt, das wir versuchen mit SSL-Zertifikat zum Laufen zu bringen. Hier gehen wir schrittweise vor und richten erstmal ein VirtualHost ein, damit unser lokaler Web-Server unter WSL beim Aufrufen einer Domain im Browser darauf reagiert und uns irgendwas ausliefert.
In meinem Beispiel möchte ich die (für den Moment) neue Version des JTL-Shops installieren. Dafür verwende ich die lokale Domain jtl-550.work
.
Hosts Eintrag
Wir starten mit einem Hosts Eintrag. In der Datei /etc/hosts
fügen wir eine Domain hinzu, die von unserem Loopback (127.0.0.1) verarbeitet werden soll. Da wir aber WSL verwenden, müssen wir beachten, dass die /etc/hosts
Datei durch die Windows eigene Hosts-Datei überschrieben wird. Dieser Hinweis ist ebenfalls in der /etc/hosts
direkt am Anfang der Datei enthalten.
Somit öffnen wir die Hosts-Datei in Windows direkt, um unsere Domain einzutragen, die von 127.0.0.1 verarbeitet werden soll. Diese Datei befindet sich unter dem folgenden Pfad.
C:\Windows\System32\drivers\etc\hosts
Diese Datei sollte mit Administrator-Rechten geöffnet werden und folgende Einträge füge ich in meinem Fall ein.
In eurem Fall müsst ihr natürlich eure, beliebige lokale Domain eintragen.
Wenn es getan und die Datei gespeichert hat, sollte es ausreichen, um die Domain “anpingen” zu können. Ich empfehle jedoch einen Neustart von WSL durchzuführen. Dies kann man mit dem folgenden Befehl tun. Danach WSL einfach wieder öffnen.
wsl --shutdown
VirtualHost Eintrag
An diesem Schritt registrieren wir unsere lokale Domain für Apache. Dafür erstellen wir einen neuen VirtualHost Eintrag in der Apache Sites-Konfiguration.
Bei Apache gibt es zwei Ordner die in diesem Zusammenhang relevant sind.
/etc/apache2/sites-available/
/etc/apache2/sites-enabled/
Im Ordner sites-available/
befinden sich die tatsächlichen Konfigurationsdateien, die Konfigurationen für die jeweilige Domain beinhalten.
Im Ordner sites-enabled/
befinden sich symbolische Links auf die Konfigurationsdateien im Ordner sites-available/
. Nur die Konfigurationen, welche nach sites-enabled/
verlinkt worden sind, gelten für Apache als aktiv.
Man kann alle Konfigurationen aller lokaler Projekte in einer Datei führen. Ich empfehle den Ansatz die Konfigurationen auf die einzelnen Dateien aufzuteilen.
Wir erstellen für unser Beispiel eine Datei jtl-550.conf
. In dieser Datei machen wir einen neuen VirtualHost
Eintrag, welcher auf den Port 80 hört.
<VirtualHost *:80>
ServerName jtl-550.work
DocumentRoot /var/www/html/jtl_550
<Directory /var/www/html/jtl_550>
AllowOverride all
Require all granted
</Directory>
</VirtualHost>
Anschließend verlinken wir diese Datei im Ordner sites-enabled/
.
cd /etc/apache2/sites-enabled/
sudo ln -s ../sites-available/jtl-550.conf .
Und starten Apache neu.
sudo systemctl restart apache2
Webspace
Nun müssen wir in unserem Web-Root (/var/www/html
) einen neuen Ordner erstellen, in welchem sich unser Web-Projekt befinden wird und welcher von Apache angesteuert wird, wenn man die lokale Domain aufruft. In meinem Fall wird es der Ordner mit dem Namen jtl_550
sein und in euren Fall eben ein anderer.
In meinem Fall platziere ich dort folgenden Inhalt.
<?php
echo "Hier kommt der Web-Shop";
?>
Wenn wir jetzt also die Domain http://jtl-550.work
im Browser aufrufen, werden wir feststellen, dass unsere Mini-Website funktioniert. Die Verbindung ist momentan noch nicht gesichert und arbeitet nur mit dem HTTP-Protokoll.
Projekt Zertifikat
SSL-Zertifikate werden in der Regel pro Domain ausgestellt. Eine Domain ist in der Regel auch ein Projekt (manchmal gibt es etwas abweichende Konfigurationen). Somit werden wir auch für die lokale Entwicklung so verfahren, dass pro lokale Domain ein SSL-Zertifikat ausgestellt (generiert) wird. Dafür verwenden mkcert
.
Wenn man mkcert
für die Erstellung des lokalen Zertifikats verwendet, sollte beachtet werden, in welchem Benutzer-Kontext es ausgeführt wird. Wenn wir mit unserem normalen WSL-Benutzer mkcert
einsetzen, dann sollten wir darauf achten, dass wir uns in einem Ordner befinden, in welchem wir Schreibrechte haben. Dort werden nämlich die Zertifikate abgelegt.
Ich mache es auf meinem System immer im ~/temp/
Verzeichnis.
Das Zertifikat wird mit folgendem Befehl erzeugt.
mkcert jtl-550.work
Dabei erhalten wir folgende Ausgabe, wenn alles korrekt funktionierte.
Es besteht auch die Möglichkeit ein Zertifikat für mehrere Domains auszustellen.
mkcert domain-1.work domain-2.work domain-3.work
In diesem Fall würde das erstellte Zertifikat alle drei Domains abdecken. Allerdings ist es aus meiner Sicht nicht der beste Weg, da man irgendwann nicht mehr weiß, welches Zertifikat welche Domains abdeckt, außer man bezeichnet die Zertifikatsdatei entsprechend so, dass der Name alle Domains beinhaltet. Auch das ist weniger schöne Lösung. Daher erstelle ich pro Domain ein eigenes Zertifikat. Diese Lösung ist klar, verständlich und sauber.
Apache - SSL
Was haben wir aktuell? Wir haben einen funktionierenden VirtualHost mit unserer eigenen lokalen Domain, wir haben auf beiden Stellen (WSL und Windows) die Zertifikate installiert und wir haben das Zertifikat für unser Beispiel-Projekt erstellt. Die Zertifikatsdateien liegen aktuell im Home-Verzeichnis, im temp
Ordner.
temp/
├── jtl-550.work-key.pem
└── jtl-550.work.pem
In diesem Schritt müssen wir SSL unter Apache aktivieren, die SSL-Zertifikate verschieben und die Konfiguration von unserem VirtualHost für die Verwendung von SSL erweitern.
SSL-Zertifikate Speicherort
Hier gibt es nicht wirklich eine absolut falsche oder eine absolut richtige Lösung. Jede Lösung die funktioniert, ist eigentlich richtig. Der Rest ist Geschmack- und Organisationssache. In meinem Fall möchte ich allerdings hier auch Ordnung haben.
Die SSL-Zertifikate werden von Apache für unsere lokale Domains verwendet, die über das HTTPS-Protokoll und dem 443er Port ausgeliefert werden. Entsprechend möchte ich alle Projekt-Zertifikate irgendwo unter Apache speichern.
Dafür erstelle ich einen Ordner unter /etc/apache2/ssl
und verschiebe, nach der Erstellung, die Zertifikate in diesen Ordner.
sudo mkdir /etc/apache2/ssl
Anschließend verschiebe ich beiden Zertifikatsdateien aus dem ~/temp/
Ordner in den ssl
Ordner unter Apache.
cd ~/temp/
sudo mv jtl-550.work* /etc/apache2/ssl/
Somit wären jetzt die Zertifikate in diesem Ordner.
/etc/apache2/ssl/
├── jtl-550.work-key.pem
└── jtl-550.work.pem
SSL aktivieren
Unter Apache soll nun SSL aktiviert werden. Das kann man mit dem folgenden Befehl tun. Anschließend sollte unbedingt Apache neugestartet werden.
sudo a2enmod ssl
sudo systemctl restart apache2
Das Tool a2enmod
steht für Apache2 Enable Module und ist ein eigenständiges Programm, das mit Apache-Installation installiert wird. Wo es liegt kann man wie folgt herausfinden.
which mkcert
Man kann das Tool auch eigenständig aufrufen. Es ist dafür zuständig, vorhandene Apache-Module zu aktivieren, indem es symbolische Links von /etc/apache2/mods-available/
nach /etc/apache2/mods-enabled/
setzt.
Wenn man könnte also auch händisch die Apache-Module zuschalten.
VirtualHost erweitern
Nun haben wir unsere Zertifikatsdateien am richtigen Ort, das SSL-Module ist aktiviert und wir müssen noch unsere VirtualHost-Konfiguration entsprechend erweitern. Dabei besteht das Ziel Apache mitzuteilen, dass es auch den Port 443 für die entsprechende lokale Domain bedienen soll.
Wir öffnen die Datei /etc/apache2/sites-available/jtl-550.conf
. Und fügen folgenden Block für den 443 Port hinzu.
<VirtualHost *:443>
ServerName jtl-550.work
DocumentRoot /var/www/html/jtl_550
<Directory /var/www/html/jtl_550>
AllowOverride all
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/jtl-550.work.pem
SSLCertificateKeyFile /etc/apache2/ssl/jtl-550.work-key.pem
</VirtualHost>
Somit sieht unsere gesamte Konfiguration danach wie folgt aus.
Nach diesen Änderungen sollte Apache erneut neugestartet werden.
sudo systemctl restart apache2
Wenn wir den Cache des Browsers löschen oder unsere lokale Domain in einem Inkognito-Fenster öffnen, erhalten wir eine funktionierende SSL-Version unserer Website.