Я использую WSL2 в Windows 10.
Мой дистрибутив - Debian.
Я хотел установить статический IP для моего дистрибутива, но я узнал, что это невозможно сделать для WSL из этого ответа.
Однако я понял, что могут быть и другие возможности.
Возможно ли создать сценарий Powershell, который при запуске обновляет hosts etc на Windows 10 с новым IP WSL, указывающим на пользовательское доменное имя, например 172.18.225.26 dev.local
? При этом не оставляя никаких предыдущих конфигураций WSL в файле хоста.
В настоящее время мой файл хоста выглядит следующим образом:
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
# Added by Docker Desktop
192.168.8.101 host.docker.internal
192.168.8.101 gateway.docker.internal
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section
# Added by Custom Script For WSL Distro
172.18.225.26 dev.local
#End of section
У меня нет знаний о Powershell сценариях, я буду очень признателен за помощь.
Я смог получить то, что хотел, благодаря помощи из этого ответа, но я сделал некоторые изменения.
В основном, я создал файл update_wsl_ip_to_domain.ps1
и сохранил в этом PATH C:\Scripts\update_wsl_ip_to_domain.ps1
, затем я добавил следующие скрипты
#
# Powershell script for adding/removing/showing entries to the hosts file.
#
# Known limitations:
# - does not handle entries with comments afterwards ("<ip> <host> # comment")
#
$file = "C:\Windows\System32\drivers\etc\hosts"
$wsl_ip = (wsl -d debian hostname -I).trim()
$data = @('add','localwsl.com',$wsl_ip)
function add-host([string]$filename, [string]$hostname, [string]$ip) {
remove-host $filename $hostname
$ip + "`t`t" + $hostname | Out-File -encoding ASCII -append $filename
}
function remove-host([string]$filename, [string]$hostname) {
$c = Get-Content $filename
$newLines = @()
foreach ($line in $c) {
$bits = [regex]::Split($line, "\t+")
if ($bits.count -eq 2) {
if ($bits[1] -ne $hostname) {
$newLines += $line
}
} else {
$newLines += $line
}
}
# Write file
Clear-Content $filename
foreach ($line in $newLines) {
$line | Out-File -encoding ASCII -append $filename
}
}
function print-hosts([string]$filename) {
$c = Get-Content $filename
foreach ($line in $c) {
$bits = [regex]::Split($line, "\t+")
if ($bits.count -eq 2) {
Write-Host $bits[0] `t`t $bits[1]
}
}
}
try {
if ($data[0] -eq "add") {
if ($data.count -lt 3) {
throw "Not enough arguments for add."
} else {
add-host $file $data[1] $data[2]
}
} elseif ($data[0] -eq "remove") {
if ($data.count -lt 2) {
throw "Not enough arguments for remove."
} else {
remove-host $file $data[1]
}
} elseif ($data[0] -eq "show") {
print-hosts $file
} else {
throw "Invalid operation '" + $data[0] + "' - must be one of 'add', 'remove', 'show'."
}
} catch {
Write-Host $error[0]
Write-Host "`nUsage: hosts add <ip> <hostname>`n hosts remove <hostname>`n hosts show"
}
Затем я создал отдельный update_wsl_ip_to_domain.cmd
файл в той же директории, что и ps1
файл, и добавил следующие команды.
PowerShell Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Powershell -File C:\Scripts\update_wsl_ip_to_domain.ps1
PowerShell Set-ExecutionPolicy Restricted
Чтобы файл update_wsl_ip_to_domain.cmd
запускался при запуске, я создал ярлык этого каталога C:\Users\<user_name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
и дал ему права администратора.
Наконец, я также добавил еще один ярлык update_wsl_ip_to_domain.cmd
файла на рабочем столе с правами администратора, который я запускаю вручную, потому что по какой-то причине предыдущий не всегда запускается при запуске.
UPDATES
На моем Debian
WSL
дистрибутиве я решил запустить apache
на 80 порту и nginx
на 81 порту.
Чтобы дать им статический IP и доменное имя, я отредактировал свой update_wsl_ip_to_domain.ps1
файл и добавил следующий код внизу.
#GIVING WSL NGINX A STATIC IP. IT RUNS AT PORT 81 ON MY DEBIAN
netsh interface portproxy add v4tov4 listenport=80 listenaddress=127.65.43.21 connectport=81 connectaddress=$wsl_ip
#GIVING WSL APACHE A STATIC IP. IT RUNS AT PORT 80 ON MY DEBIAN
netsh interface portproxy add v4tov4 listenport=80 listenaddress=127.65.43.22 connectport=80 connectaddress=$wsl_ip
Затем я сделал следующие записи в моем hosts
файле на Windows
10.
127.65.43.21 localwslnginx.com
127.65.43.22 localwslapache.com
Я считаю, что в этом есть большой потенциал, я просто смогу запускать несколько приложений на разных портах с помощью моего apache
или nginx
.
Я буду делать обновления по мере продвижения.
UPDATES 2 (28 декабря 2021 года)
Я смог запустить несколько приложений через wsl
, при этом каждое из них имеет свои уникальные доменные имена. Вот как выглядит мой файл hosts
на windows:
127.65.43.21 localwslnginx.com
127.65.43.22 localwslapache.com
# Laravel Apps
127.65.43.22 evangrest.test
127.65.43.22 firstbarcodes.test
Они должны иметь один и тот же статический IP с localwslapache.com
или localwslnginx.com
для apache
и nginx
соответственно.
Для apache
я использовал следующий конфиг, чтобы запустить мое laravel
приложение:
<VirtualHost *:80>
DocumentRoot "/data/www/firstbarcodes/public"
DirectoryIndex "index.php"
ServerName firstbarcodes.test
ServerAlias firstbarcodes.test
<Directory "/data/www/firstbarcodes">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory "/data/www/firstbarcodes/public">
Options Indexes FollowSymLinks MultiViews ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
</Directory>
#Alias /js /data/www/firstbarcodes/public/js
#<Directory /data/www/firstbarcodes/public/js>
# Options Indexes FollowSymLinks MultiViews ExecCGI
# AllowOverride All
# Order allow,deny
# Allow from all
# Require all granted
#</Directory>
</VirtualHost>
Вам также может понадобиться выполнить эту команду sudo a2enmod rewrite
для apache
.
Думаю, таким образом, я смог как-то создать хак для получения статического IP для всех моих apache
и nginx
приложений через WSL
.
Что я хотел бы сделать дальше, так это заставить мои WSL
Debian
apache
автоматически запускать мои mariadb
и windows
при update_wsl_ip_to_domain.ps1
запуске.
netsh
, но есть некоторые другие возможности :)
У меня есть несколько дистрибутивов WSL.
Для каждого из них я создаю файл с именем MYWSLDISTRONAME-hostnames.txt
в каталоге scripts
.
Этот файл содержит только доменные имена:
app.ds.local
pma.ds.local
sandbox.ds.local
test.ds.local
В начале, я добавляю эти доменные имена в конец файла hosts
, только один раз, как например
127.0.0.1 app.ds.local
127.0.0.1 pma.ds.local
127.0.0.1 sandbox.ds.local
127.0.0.1 test.ds.local
Если мне нужно добавить другое доменное имя для моего дистрибутива, я останавливаю WSL, а затем просто добавляю
строку
another.ds.local
кMYWSLDISTRONAME-hostnames.txt
и
127.0.0.1 another.ds.local
кhosts
Каждый раз, когда мне нужно запустить мой WSL-дистрибутив, я запускаю следующий скрипт MYWSLDISTRONAME-start.ps1
. Что он делает:
/root/start_services.sh
внутри дистрибутива, который запускает необходимые службы и т.д. (тем самым решая проблему с отсутствием systemd
)hosts
для каждого доменного имени из MYWSLDISTRONAME-hostnames.txt
. Все это делается с временным hosts
файлом.hosts
файл каких-либо изменений. Если да, то запускается отдельный pwsh
файл, который запрашивает права администратора. Если нет, скрипт просто выводит сообщение.$runningDirectory = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
$hostsFile = "c:\windows\system32\drivers\etc\hosts"
$wslHostnamesFile = "$runningDirectory\MYWSLDISTRONAME-hostnames.txt"
$tmpFile = "$runningDirectory\.new-hostnames.txt"
$distroName = "MYWSLDISTRONAME"
# Start services inside the WSL
wsl -d $distroName -e /root/start_services.sh
# Get IP address of WSL distro
$wslIpAddr = wsl -d $distroName -- ip addr
$match = [System.Text.RegularExpressions.Regex]::Match($wslIpAddr, "(?<ip>(172|192\.168)\.[\d\.]*)/")
$ip = $match.Groups["ip"]
Write-Host "$distroName is available at $ip"
# read hosts file and change the IPs
$host_file_contents = Get-Content $hostsFile -Encoding UTF8 -Raw
$hostnames = Get-Content $wslHostnamesFile -Encoding UTF8
foreach ($hostname in $hostnames) {
$host_file_contents = [System.Text.RegularExpressions.Regex]::Replace($host_file_contents, "(\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\b)\s+$hostname", "$ip`t$hostname")
}
# Save hosts file
$host_file_contents | Set-Content -Path $tmpFile -Encoding UTF8
# Compare two files to avoid unncecessary popups
$result = Compare-Object -ReferenceObject ((Get-Content $hostsFile).trim() -ne '') -DifferenceObject ((Get-Content $tmpFile).trim() -ne '')
if ($result)
{
# Prepare and execute encoded command (note that we use 'pwsh' instead of 'powershell')
$command = "Get-Content -Path ""$tmpFile"" | Set-Content -Path ""$hostsFile"""
Write-Host "Updating hosts file with: $command"
$encodedCmd = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($command))
Start-Process -FilePath pwsh.exe -Verb RunAs -ArgumentList "-encodedcommand $encodedCmd"
}
else
{
Write-Host "Hosts file is the same, modification is unnecessary"
}
Start-Sleep -Seconds 5
# Remove temporary file
Remove-Item $tmpFile
ПРИМЕЧАНИЕ: Мне очень нравится ваша идея с netsh
и, вероятно, я добавлю ее в свои скрипты.
И, для полноты картины, у меня также есть MYWSLDISTRONAME-stop.ps1
:
wsl.exe --shutdown -d MYWSLDISTRONAME
У меня также есть .lnk
'ы для обоих .ps1
файлов с красивыми и отличительными иконками, чтобы легко идентифицировать каждый дистрибутив :).
Они могут быть запущены без прав администратора, скрипты запросят их при необходимости.
EDIT: изменил (?<ip>172\.[\d\.]*)/
на (?<ip>(172|192\.168)\.[\d\.]*)/
, потому что кажется, что WSL2 тоже начал выдавать IP из этого диапазона (?). [отредактировано 17 февраля 2022 г.]