Доступ к WSL2 с общедоступного IP-адреса
Я установил WSL2 с Ubuntu 20.04 в Windows 10.
У меня есть сервер Apache, работающий в WSL2, и он отлично работает, когда я использую браузер в Windows (Chrome) для доступа к нему через IP-адрес WSL.
Поскольку IP-адрес WSL2 может измениться, я создал следующий сценарий Powershell, который перезапускает WSL, получает новый IP-адрес WSL, перезапускает службы (Apache и MySQL для самого веб-сайта, а также Cron для запуска «certbot» для сертификата SSL). продление), затем я настраиваю переадресацию портов из Windows на IP-адрес WSL для портов 80 и 443, гарантирую, что брандмауэр Windows открыт для этих портов, а затем обновляю файл хостов для домена, указывая новый IP-адрес WSL.
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
Я протестировал скрипт, и он правильно выполняет все задачи. Файл «hosts» обновляется, добавляются правила брандмауэра (это правило можно запустить один раз, и оно не обязательно должно быть в сценарии «перезапуска сервера», но я объединил все шаги в этот сценарий).
Скрипт показывает все правила портпрокси и они настроены так, как положено (не обязательно есть причина прослушивать все адреса, а затем специально прослушивать IP-адрес локальной сети Windows - это просто паранония и тестирование разных вещей, когда этого не будет работа).
И сам сервер работает, потому что, если я перейду к IP-адресу WSL (или использую имя домена благодаря записи хостов - использование правильного имени домена соответствует сертификату SSL, чтобы не игнорировать предупреждения браузера) или «localhost», то веб-сайт работает нормально.
Но если я попытаюсь перейти к «127.0.0.1» или IP-адресу локальной сети Windows (192.168.1.165, как показано в сценарии), я получу сообщение «Отказано в соединении».
Обратите внимание, что я напрямую поместил команды portproxy в сценарий для IP 192.168.1.165 на IP-адрес WSL (который работает при прямом использовании), поэтому этот портпрокси явно отклоняется (брандмауэром? Но я добавил правила брандмауэра в откройте эти порты, верно?).
И если я попытаюсь использовать общедоступный IP-адрес (или настоящее доменное имя), браузер просто вращается, пока не сообщит «время ожидания истекло». Что интересно, так это то, что 127.0.0.1 и IP-адрес локальной сети «отказано в соединении» (немедленный возврат), но это тайм-аут из-за отсутствия ответа вообще.
Сам сервер находится в DMZ, а общедоступный IP-адрес привязан к IP-адресу локальной сети через NAT, поэтому я специально пытаюсь заставить его работать, поскольку он должен сделать его общедоступным.
Ранее этот сервер у меня был запущен и работал — с полным общедоступным доступом, и все было в порядке — но на сервере произошел сбой в подаче электроэнергии, и теперь я не могу заставить его снова работать.
Возможно, какая-то команда или настройка, которые я выполнил ранее, не сохранилась и потерялась из-за отключения электроэнергии, но я не могу придумать, что это могло быть.
Есть идеи, что может привести к сбою IP-адреса LAN/127.0.0.1 с сообщением «отказано в соединении», в то время как «localhost» и IP-адрес WSL2 работают нормально?
Хотя 127.0.0.1 менее важен, так как это IP-адрес локальной сети, который должен работать, чтобы сделать его общедоступным, потому что именно на него NAT отправляет пакеты.
Редактировать: О боже. Я прочитал сообщение кого-то другого, и, по-видимому, если вы используете переменную в команде «netsh Interface portproxy», то, хотя она отображается как правильная, когда вы ее указываете, на самом деле она не работает. А вот если вбить команду вручную, без переменной, а проставив напрямую IP-адрес WSL2, то всё заработало, включая публичный доступ.
Это неприятная ошибка в Powershell, не в последнюю очередь потому, что она означает, что я не могу ее автоматизировать и должен вручную вводить команды, поскольку переменные не будут работать, но также и потому, что нет никаких признаков того, что она сломана. Когда вы перечисляете правила, все они выглядят на 100% правильными с правильными IP-адресами, но это просто не работает.
Хорошо, теперь у меня все работает. Но я думаю, я изменю свой вопрос на вопрос, есть ли способ обойти эту проблему? Мне бы хотелось, чтобы мой небольшой скрипт автоматизации работал, потому что тогда я смогу запустить его при загрузке без необходимости ручного вмешательства. Ну что ж, я думаю, что серверам не следует слишком часто отключать электричество.
Это напомнило мне, почему я предпочитаю Linux Windows.