I have installed WSL2 with Ubuntu 20.04 on Windows 10.
I have an Apache server running in WSL2, and this works fine when I use a browser in Windows (Chrome) to access it via WSL IP address.
As the WSL2 IP address may change, I've created the following Powershell script which restarts WSL, grabs the new WSL IP address, restarts the services (Apache and MySQL for the website itself, and also Cron to run "certbot" for SSL certificate renewal), then I set up port forwarding from Windows to the WSL IP for ports 80 and 443, ensure that the Windows Firewall is open for those ports, then update the hosts file for the domain to the new WSL IP address.
Write-Host "Shutting down WSL"
wsl --shutdown
Write-Host "Starting services..."
wsl sudo service mysql restart
wsl sudo service apache2 restart
wsl sudo service cron restart
$wsl_ip = wsl hostname -I
Write-Host "Port forwarding to $wsl_ip"
netsh interface portproxy reset
netsh interface portproxy add v4tov4 listenport=80 connectport=80 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=443 connectport=443 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenaddress=192.168.1.165 listenport=80 connectport=80 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenaddress=192.168.1.165 listenport=443 connectport=443 connectaddress=$wsl_ip
netsh interface portproxy show all
Write-Host "Open Firewall"
Remove-NetFirewallRule -DisplayName "Apache2 Port 80 TCP"
Remove-NetFirewallRule -DisplayName "Apache2 Port 443 TCP"
New-NetFirewallRule -DisplayName "Apache2 Port 80 TCP" -Direction Inbound -Protocol TCP -LocalPort 80 -Action Allow -EdgeTraversalPolicy Allow
New-NetFirewallRule -DisplayName "Apache2 Port 80 TCP" -Direction Outbound -Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "Apache2 Port 443 TCP" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -EdgeTraversalPolicy Allow
New-NetFirewallRule -DisplayName "Apache2 Port 443 TCP" -Direction Outbound -Protocol TCP -LocalPort 443 -Action Allow
Write-Host "Updating hosts..."
$domain = "example.com"
$line = "$wsl_ip`t$domain"
$hostsPath = "$env:windir\System32\drivers\etc\hosts"
$items = Get-Content $hostsPath | Select-String $domain
if($items -eq $null)
{
Add-Content $hostsPath $line
}
else
{
foreach($item in $items)
{
(Get-Content $hostsPath) -replace $item, $line | Set-Content $hostsPath
}
}
pause
I've tested the script and it does complete all the tasks correctly. The "hosts" file is updated, the firewall rules are added (this one could just be run once and needn't be in this "restart server" script, but I've bundled all the steps together into this script).
The script shows all the portproxy rules and they are set up as expected (there's not necessarily a reason for listening on all addresses and then also specifically listening on the Windows LAN IP - this is just paranonia and testing different things, when it wouldn't work).
And the server itself is up and running, because if I browse to the WSL IP address (or use the domain name, thanks to the hosts entry - using the correct domain name matches the SSL certificate to not have to wave away browser warnings) or "localhost" then the website comes up just fine.
But If I try to browse to "127.0.0.1" or the Windows LAN IP address (192.168.1.165, as shown in the script) then I get "connection refused".
Note that I've directly placed portproxy commands in the script for IP 192.168.1.165 to the WSL IP address (which works when used directly), so this portproxy is being explicitly refused (by the firewall? But I've added Firewall rules to open those ports, right?).
And if I try to use the public IP address (or real domain name) then the browser just spins until it says "timed out". Which is interestingly different, as 127.0.0.1 and the LAN IP address are "connection refused" (returning immediately) but this is timing out from no response at all.
The server itself is in the DMZ and the public IP address is NAT'd to the LAN IP address, which is why I'm specifically trying to get that one working, as it should make it publicly accessible.
I did have this server up and running previously - with full public access and all was fine - but the server suffered a power outage, and now I can't get it to work again.
It's possible that there was some command or setting I did previously, that wasn't saved and got lost in the power outage, but I can't think what it could be.
Any ideas what could be making the LAN IP / 127.0.0.1 fail with "connection refused", while "localhost" and the WSL2 IP works just fine?
Though 127.0.0.1 is less important, as it's the LAN IP that needs to be working to get it publicly accessible, because that's what the NAT sends packets to.
Edit: Oh dear. I read a post by someone else and, apparently, if you use a variable in the "netsh interface portproxy" command then though it shows up as correct when you list it, it doesn't actually work. But if you manually type in the command, without a variable but placing the WSL2 IP address directly, then it all started working, including public access.
This is a nasty bug in Powershell, not least because it means that I can't automate it and must manually type the commands, as variables won't work, but also because there's no indication that it's broken. When you list the rules, they all look 100% correct with the right IP addresses but it just doesn't work.
Okay, so I've got it working now. But I guess I'll alter my question to asking whether there's any way around this problem? As I'd like my little automation script to work, because then I can run it on boot without need for manual intervention. Oh well, I guess servers shouldn't hit power outages too often.
This has reminded me why I prefer Linux to Windows.