我在 Windows 10 上使用 WSL2。
我的发行版是 Debian。
我想为我的发行版设置一个静态 IP,但我发现无法为 WSL 做到这一点回答。
然而我发现可能还存在其他的可能性。
是否可以使用 Powershell 脚本来更新 Windows 10 上的 etc 主机,并使用新的 WSL IP 指向自定义域名(如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 脚本一无所知,非常感谢您的帮助。
答案1
感谢这个的帮助,我得到了我想要的东西回答,但我确实做了一些修改。
基本上,我创建了一个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
桌面上以管理员权限添加了该文件的另一个快捷方式,并手动运行该快捷方式,因为由于某种原因,前一个快捷方式并不总是在启动时运行。
更新
在我的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
然后我在 10 号对我的档案进行了下列输入Windows
。
127.65.43.21 localwslnginx.com
127.65.43.22 localwslapache.com
我相信这方面有很大的潜力,我可能能够用我的apache
或在不同的端口上运行多个应用程序nginx
。
我会随时更新。
更新 2 (2021 年 12 月 28 日)
我已经能够运行多个应用程序,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
它们必须分别与 或localwslapache.com
承担相同的静态 IP 。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
我想通过这种方式,我就能以某种方式创建一个黑客程序,为我的所有apache
和nginx
应用程序提供一个静态 IP WSL
。
我接下来想要做的是让它在启动时自动WSL
Debian
启动。apache
mariadb
windows
答案2
我也遇到了同样的问题,并找到了自己的解决方案。这就是解决方案。它缺少添加静态 IP 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
) - 获取正在运行的 WSL 发行版的 IP 地址
hosts
将中的每个域名的IP 替换为新 IPMYWSLDISTRONAME-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
文件添加了漂亮且独特的图标,以便轻松识别每个发行版 :)。
它们可以在没有管理员权限的情况下启动,脚本会在必要时请求它们。
编辑:更改(?<ip>172\.[\d\.]*)\/
为,(?<ip>(172|192\.168)\.[\d\.]*)\/
因为看起来 WSL2 也已经开始从该范围发出 IP (?)。[2022 年 2 月 17 日编辑]
答案3
使用 Windows 11 和当前的 wsl2,我发现移动DNS似乎运行良好,您无需编写 hosts 文件脚本。我的 WSL2 发行版是 ubuntu 22.04。
您可以使用 mDNS 来通告您的 wsl 主机的主机名(带后缀).local
。如果您在 中为您的 wsl2 环境分配主机名/etc/wsl.conf
,如下所示:
[network]
hostname=projects
您的Windows主机应该能够解析该名称projects.local
。
从 WSL 终端,你可以使用以下命令检查 wsl 是否正在公布其 IP 地址:
$ avahi-resolve -n "$(hostname).local"
projects.local 172.17.0.1
PS:我发现只要我在Windows中启用数据包转发(如图所示这里), 我甚至可以使用名称从连接到默认 vSwitch 的 HyperV VM 访问我的 wsl 主机<wsl hostname>.local
。