解决Windows10下WSL2中openclaw的保活和网络映射问题

2026-04-11 15:071阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

WSL2其实非常方便 维护迁移都不错,唯一的问题就是网络太恼人,每次重启后WSL的IP就变,很麻烦。很多人因为各种各样的原因没法开TUN模式。于是我让AI安排了这3个脚本,集合了自启动+保活+自动识别IP并映射 用了一段时间非常方便 也没问题 这里分享下

以V2rayn默认代理端口10808 龙虾端口18789为例

image594×126 12.5 KB

image599×409 34.2 KB

注意:Customer需要改成你Windows的当前用户名 这三个脚本也放到你对应的用户名目录下

运行下面命令就可以加入开机自动运行
& 'C:\Users\你的用户名\wsl-openclaw-autostart.ps1' -Action install

运行下面命令可以重启/恢复服务
& 'C:\Users\Customer\wsl-openclaw-recover.ps1'

wsl-openclaw-recover.ps1

param( [string]$Distro = 'Debian', [int]$Port = 18789, [int]$StaticPort = 18080, [string]$GatewayUnit = 'openclaw-gateway.service', [string]$StaticUnit = 'openclaw-static-http.service', [int]$WaitTimeoutSeconds = 240 ) $ErrorActionPreference = 'Stop' $Root = Split-Path -Parent $PSCommandPath $KeepAliveScript = Join-Path $Root 'wsl-keepalive.ps1' $PortProxyScript = Join-Path $Root 'wsl-openclaw-portproxy.ps1' $ServiceTemplate = Join-Path $Root 'openclaw-gateway.system.service' $StaticServiceTemplate = Join-Path $Root 'openclaw-static-http.system.service' function Wait-ForPort { param( [int]$TargetPort ) $deadline = (Get-Date).AddSeconds($WaitTimeoutSeconds) while ((Get-Date) -lt $deadline) { & wsl.exe -d $Distro -- sh -lc "ss -ltn | grep -q ':$TargetPort '" | Out-Null if ($LASTEXITCODE -eq 0) { return $true } Start-Sleep -Seconds 3 } return $false } try { & $KeepAliveScript -Action stop | Out-Null } catch { } & wsl.exe --shutdown Start-Sleep -Seconds 3 & $KeepAliveScript -Action start $installCommand = @" if [ -f /mnt/c/Users/Customer/openclaw-gateway.system.service ]; then install -m 0644 /mnt/c/Users/Customer/openclaw-gateway.system.service /etc/systemd/system/openclaw-gateway.service fi if [ -f /mnt/c/Users/Customer/openclaw-static-http.system.service ]; then install -m 0644 /mnt/c/Users/Customer/openclaw-static-http.system.service /etc/systemd/system/openclaw-static-http.service fi systemctl daemon-reload systemctl enable $GatewayUnit >/dev/null 2>&1 || true systemctl restart $GatewayUnit if [ -f /mnt/c/Users/Customer/openclaw-static-http.system.service ]; then systemctl enable $StaticUnit >/dev/null 2>&1 || true systemctl restart $StaticUnit fi "@ & wsl.exe -u root -d $Distro -- sh -lc $installCommand | Out-Null $ready = Wait-ForPort -TargetPort $Port if (-not $ready) { throw "OpenClaw gateway did not start listening on port $Port within $WaitTimeoutSeconds seconds." } if (Test-Path $StaticServiceTemplate) { $staticReady = Wait-ForPort -TargetPort $StaticPort if (-not $staticReady) { throw "OpenClaw static HTTP did not start listening on port $StaticPort within $WaitTimeoutSeconds seconds." } } & $PortProxyScript -Distro $Distro -Port $Port if (Test-Path $StaticServiceTemplate) { & $PortProxyScript -Distro $Distro -Port $StaticPort } $wslIp = (& wsl.exe -d $Distro -- sh -lc "hostname -I | cut -d' ' -f1").Trim() $keepAliveStatus = & $KeepAliveScript -Action status $serviceStatus = & wsl.exe -u root -d $Distro -- systemctl is-active $GatewayUnit $staticServiceStatus = if (Test-Path $StaticServiceTemplate) { & wsl.exe -u root -d $Distro -- systemctl is-active $StaticUnit } else { 'not-installed' } Write-Output "RECOVER_OK Distro=$Distro WSL_IP=$wslIp PORT=$Port Service=$serviceStatus" Write-Output "STATIC_OK Distro=$Distro WSL_IP=$wslIp PORT=$StaticPort Service=$staticServiceStatus" Write-Output $keepAliveStatus Write-Output "URLs: http://127.0.0.1:$Port/ http://${wslIp}:$Port/" if (Test-Path $StaticServiceTemplate) { Write-Output "Static URLs: http://127.0.0.1:$StaticPort/ http://${wslIp}:$StaticPort/" }

wsl-openclaw-autostart.ps1

param( [ValidateSet('install', 'remove', 'status', 'run-now')] [string]$Action = 'status', [string]$Distro = 'Debian' ) $ErrorActionPreference = 'Stop' $TaskName = 'WSL OpenClaw Recover' $RunnerPath = (Get-Process -Id $PID).Path $RecoverScript = Join-Path (Split-Path -Parent $PSCommandPath) 'wsl-openclaw-recover.ps1' $RecoverWaitTimeoutSeconds = 240 $UserId = "$env:USERDOMAIN\$env:USERNAME" function Test-IsAdmin { $currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal]::new($currentIdentity) $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Get-Task { Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue } if ($Action -in @('install', 'remove', 'run-now') -and -not (Test-IsAdmin)) { $arguments = @( '-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $PSCommandPath, '-Action', $Action, '-Distro', $Distro ) $process = Start-Process -FilePath $RunnerPath -Verb RunAs -ArgumentList $arguments -PassThru -Wait exit $process.ExitCode } switch ($Action) { 'install' { $taskAction = New-ScheduledTaskAction -Execute $RunnerPath -Argument "-NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$RecoverScript`" -Distro `"$Distro`" -WaitTimeoutSeconds $RecoverWaitTimeoutSeconds" $trigger = New-ScheduledTaskTrigger -AtLogOn -User $UserId $principal = New-ScheduledTaskPrincipal -UserId $UserId -LogonType Interactive -RunLevel Highest $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Days 3650) Register-ScheduledTask -TaskName $TaskName -Action $taskAction -Trigger $trigger -Principal $principal -Settings $settings -Description 'Auto-run WSL/OpenClaw recovery after Windows login.' -Force | Out-Null $task = Get-Task Write-Output "AUTOSTART_INSTALLED TASK_STATE=$($task.State)" break } 'remove' { $task = Get-Task if (-not $task) { Write-Output 'AUTOSTART_NOT_FOUND' break } Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false Write-Output 'AUTOSTART_REMOVED' break } 'status' { $task = Get-Task if (-not $task) { Write-Output 'AUTOSTART_NOT_FOUND' break } $info = Get-ScheduledTaskInfo -TaskName $TaskName Write-Output "AUTOSTART_STATUS TASK_STATE=$($task.State) LAST_RESULT=$($info.LastTaskResult)" break } 'run-now' { $task = Get-Task if (-not $task) { throw 'Autostart task is not installed.' } Start-ScheduledTask -TaskName $TaskName Start-Sleep -Seconds 3 $task = Get-Task Write-Output "AUTOSTART_STARTED TASK_STATE=$($task.State)" break } }

wsl-keepalive.ps1

param( [ValidateSet('start', 'stop', 'status', 'hold')] [string]$Action = 'status', [string]$Distro = 'Debian' ) $ErrorActionPreference = 'Stop' $TaskName = "WSL KeepAlive $Distro" $RunnerPath = (Get-Process -Id $PID).Path $HoldCommand = 'while true; do sleep 2147483647; done' function Get-Task { Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue } function Get-WslIp { $ip = (& wsl.exe -d $Distro -- sh -lc "hostname -I | cut -d' ' -f1").Trim() if (-not $ip) { throw "Failed to resolve WSL IP for $Distro." } return $ip } function Ensure-Task { $action = New-ScheduledTaskAction -Execute $RunnerPath -Argument "-NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Action hold -Distro `"$Distro`"" $trigger = New-ScheduledTaskTrigger -AtLogOn -User "$env:USERDOMAIN\$env:USERNAME" $principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Days 3650) Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Keep WSL distro $Distro active from Windows." -Force | Out-Null Get-Task } switch ($Action) { 'start' { & wsl.exe -d $Distro -- true | Out-Null Ensure-Task | Out-Null $task = Get-Task if ($task.State -ne 'Running') { Start-ScheduledTask -TaskName $TaskName Start-Sleep -Seconds 3 $task = Get-Task } $wslIp = Get-WslIp Write-Output "KEEPALIVE_STARTED TASK_STATE=$($task.State) WSL_IP=$wslIp" break } 'stop' { $task = Get-Task if (-not $task) { Write-Output 'KEEPALIVE_NOT_FOUND' break } Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false Write-Output 'KEEPALIVE_STOPPED' break } 'status' { $task = Get-Task if (-not $task) { Write-Output 'KEEPALIVE_NOT_FOUND' break } $info = Get-ScheduledTaskInfo -TaskName $TaskName $wslIp = 'UNKNOWN' try { $wslIp = Get-WslIp } catch { } Write-Output "KEEPALIVE_STATUS TASK_STATE=$($task.State) LAST_RESULT=$($info.LastTaskResult) WSL_IP=$wslIp" break } 'hold' { & wsl.exe -d $Distro -- sh -lc $HoldCommand break } }

image1062×245 43.1 KB

image1089×274 52.6 KB

网友解答:
--【壹】--:

你这个需求hyperv走起,安全且方便


--【贰】--:

感谢大佬


--【叁】--:

wsl2就是基于hyperv的,更轻量是你的错觉,尤其是常驻任务应该和hyperv完全没差别


--【肆】--:

那确实难受


--【伍】--:

镜像模式下代理软件开全局模式,wsl2就是全走代理了


--【陆】--:

哈哈感觉wsl2更轻量呢…… 我那电脑跑的服务太多了


--【柒】--:

牛的飞佬


--【捌】--:

win10开不了镜像 …… win11就没这些问题……

标签:人工智能
问题描述:

WSL2其实非常方便 维护迁移都不错,唯一的问题就是网络太恼人,每次重启后WSL的IP就变,很麻烦。很多人因为各种各样的原因没法开TUN模式。于是我让AI安排了这3个脚本,集合了自启动+保活+自动识别IP并映射 用了一段时间非常方便 也没问题 这里分享下

以V2rayn默认代理端口10808 龙虾端口18789为例

image594×126 12.5 KB

image599×409 34.2 KB

注意:Customer需要改成你Windows的当前用户名 这三个脚本也放到你对应的用户名目录下

运行下面命令就可以加入开机自动运行
& 'C:\Users\你的用户名\wsl-openclaw-autostart.ps1' -Action install

运行下面命令可以重启/恢复服务
& 'C:\Users\Customer\wsl-openclaw-recover.ps1'

wsl-openclaw-recover.ps1

param( [string]$Distro = 'Debian', [int]$Port = 18789, [int]$StaticPort = 18080, [string]$GatewayUnit = 'openclaw-gateway.service', [string]$StaticUnit = 'openclaw-static-http.service', [int]$WaitTimeoutSeconds = 240 ) $ErrorActionPreference = 'Stop' $Root = Split-Path -Parent $PSCommandPath $KeepAliveScript = Join-Path $Root 'wsl-keepalive.ps1' $PortProxyScript = Join-Path $Root 'wsl-openclaw-portproxy.ps1' $ServiceTemplate = Join-Path $Root 'openclaw-gateway.system.service' $StaticServiceTemplate = Join-Path $Root 'openclaw-static-http.system.service' function Wait-ForPort { param( [int]$TargetPort ) $deadline = (Get-Date).AddSeconds($WaitTimeoutSeconds) while ((Get-Date) -lt $deadline) { & wsl.exe -d $Distro -- sh -lc "ss -ltn | grep -q ':$TargetPort '" | Out-Null if ($LASTEXITCODE -eq 0) { return $true } Start-Sleep -Seconds 3 } return $false } try { & $KeepAliveScript -Action stop | Out-Null } catch { } & wsl.exe --shutdown Start-Sleep -Seconds 3 & $KeepAliveScript -Action start $installCommand = @" if [ -f /mnt/c/Users/Customer/openclaw-gateway.system.service ]; then install -m 0644 /mnt/c/Users/Customer/openclaw-gateway.system.service /etc/systemd/system/openclaw-gateway.service fi if [ -f /mnt/c/Users/Customer/openclaw-static-http.system.service ]; then install -m 0644 /mnt/c/Users/Customer/openclaw-static-http.system.service /etc/systemd/system/openclaw-static-http.service fi systemctl daemon-reload systemctl enable $GatewayUnit >/dev/null 2>&1 || true systemctl restart $GatewayUnit if [ -f /mnt/c/Users/Customer/openclaw-static-http.system.service ]; then systemctl enable $StaticUnit >/dev/null 2>&1 || true systemctl restart $StaticUnit fi "@ & wsl.exe -u root -d $Distro -- sh -lc $installCommand | Out-Null $ready = Wait-ForPort -TargetPort $Port if (-not $ready) { throw "OpenClaw gateway did not start listening on port $Port within $WaitTimeoutSeconds seconds." } if (Test-Path $StaticServiceTemplate) { $staticReady = Wait-ForPort -TargetPort $StaticPort if (-not $staticReady) { throw "OpenClaw static HTTP did not start listening on port $StaticPort within $WaitTimeoutSeconds seconds." } } & $PortProxyScript -Distro $Distro -Port $Port if (Test-Path $StaticServiceTemplate) { & $PortProxyScript -Distro $Distro -Port $StaticPort } $wslIp = (& wsl.exe -d $Distro -- sh -lc "hostname -I | cut -d' ' -f1").Trim() $keepAliveStatus = & $KeepAliveScript -Action status $serviceStatus = & wsl.exe -u root -d $Distro -- systemctl is-active $GatewayUnit $staticServiceStatus = if (Test-Path $StaticServiceTemplate) { & wsl.exe -u root -d $Distro -- systemctl is-active $StaticUnit } else { 'not-installed' } Write-Output "RECOVER_OK Distro=$Distro WSL_IP=$wslIp PORT=$Port Service=$serviceStatus" Write-Output "STATIC_OK Distro=$Distro WSL_IP=$wslIp PORT=$StaticPort Service=$staticServiceStatus" Write-Output $keepAliveStatus Write-Output "URLs: http://127.0.0.1:$Port/ http://${wslIp}:$Port/" if (Test-Path $StaticServiceTemplate) { Write-Output "Static URLs: http://127.0.0.1:$StaticPort/ http://${wslIp}:$StaticPort/" }

wsl-openclaw-autostart.ps1

param( [ValidateSet('install', 'remove', 'status', 'run-now')] [string]$Action = 'status', [string]$Distro = 'Debian' ) $ErrorActionPreference = 'Stop' $TaskName = 'WSL OpenClaw Recover' $RunnerPath = (Get-Process -Id $PID).Path $RecoverScript = Join-Path (Split-Path -Parent $PSCommandPath) 'wsl-openclaw-recover.ps1' $RecoverWaitTimeoutSeconds = 240 $UserId = "$env:USERDOMAIN\$env:USERNAME" function Test-IsAdmin { $currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal]::new($currentIdentity) $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Get-Task { Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue } if ($Action -in @('install', 'remove', 'run-now') -and -not (Test-IsAdmin)) { $arguments = @( '-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $PSCommandPath, '-Action', $Action, '-Distro', $Distro ) $process = Start-Process -FilePath $RunnerPath -Verb RunAs -ArgumentList $arguments -PassThru -Wait exit $process.ExitCode } switch ($Action) { 'install' { $taskAction = New-ScheduledTaskAction -Execute $RunnerPath -Argument "-NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$RecoverScript`" -Distro `"$Distro`" -WaitTimeoutSeconds $RecoverWaitTimeoutSeconds" $trigger = New-ScheduledTaskTrigger -AtLogOn -User $UserId $principal = New-ScheduledTaskPrincipal -UserId $UserId -LogonType Interactive -RunLevel Highest $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Days 3650) Register-ScheduledTask -TaskName $TaskName -Action $taskAction -Trigger $trigger -Principal $principal -Settings $settings -Description 'Auto-run WSL/OpenClaw recovery after Windows login.' -Force | Out-Null $task = Get-Task Write-Output "AUTOSTART_INSTALLED TASK_STATE=$($task.State)" break } 'remove' { $task = Get-Task if (-not $task) { Write-Output 'AUTOSTART_NOT_FOUND' break } Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false Write-Output 'AUTOSTART_REMOVED' break } 'status' { $task = Get-Task if (-not $task) { Write-Output 'AUTOSTART_NOT_FOUND' break } $info = Get-ScheduledTaskInfo -TaskName $TaskName Write-Output "AUTOSTART_STATUS TASK_STATE=$($task.State) LAST_RESULT=$($info.LastTaskResult)" break } 'run-now' { $task = Get-Task if (-not $task) { throw 'Autostart task is not installed.' } Start-ScheduledTask -TaskName $TaskName Start-Sleep -Seconds 3 $task = Get-Task Write-Output "AUTOSTART_STARTED TASK_STATE=$($task.State)" break } }

wsl-keepalive.ps1

param( [ValidateSet('start', 'stop', 'status', 'hold')] [string]$Action = 'status', [string]$Distro = 'Debian' ) $ErrorActionPreference = 'Stop' $TaskName = "WSL KeepAlive $Distro" $RunnerPath = (Get-Process -Id $PID).Path $HoldCommand = 'while true; do sleep 2147483647; done' function Get-Task { Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue } function Get-WslIp { $ip = (& wsl.exe -d $Distro -- sh -lc "hostname -I | cut -d' ' -f1").Trim() if (-not $ip) { throw "Failed to resolve WSL IP for $Distro." } return $ip } function Ensure-Task { $action = New-ScheduledTaskAction -Execute $RunnerPath -Argument "-NoLogo -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$PSCommandPath`" -Action hold -Distro `"$Distro`"" $trigger = New-ScheduledTaskTrigger -AtLogOn -User "$env:USERDOMAIN\$env:USERNAME" $principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" -LogonType Interactive -RunLevel Limited $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Days 3650) Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Keep WSL distro $Distro active from Windows." -Force | Out-Null Get-Task } switch ($Action) { 'start' { & wsl.exe -d $Distro -- true | Out-Null Ensure-Task | Out-Null $task = Get-Task if ($task.State -ne 'Running') { Start-ScheduledTask -TaskName $TaskName Start-Sleep -Seconds 3 $task = Get-Task } $wslIp = Get-WslIp Write-Output "KEEPALIVE_STARTED TASK_STATE=$($task.State) WSL_IP=$wslIp" break } 'stop' { $task = Get-Task if (-not $task) { Write-Output 'KEEPALIVE_NOT_FOUND' break } Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false Write-Output 'KEEPALIVE_STOPPED' break } 'status' { $task = Get-Task if (-not $task) { Write-Output 'KEEPALIVE_NOT_FOUND' break } $info = Get-ScheduledTaskInfo -TaskName $TaskName $wslIp = 'UNKNOWN' try { $wslIp = Get-WslIp } catch { } Write-Output "KEEPALIVE_STATUS TASK_STATE=$($task.State) LAST_RESULT=$($info.LastTaskResult) WSL_IP=$wslIp" break } 'hold' { & wsl.exe -d $Distro -- sh -lc $HoldCommand break } }

image1062×245 43.1 KB

image1089×274 52.6 KB

网友解答:
--【壹】--:

你这个需求hyperv走起,安全且方便


--【贰】--:

感谢大佬


--【叁】--:

wsl2就是基于hyperv的,更轻量是你的错觉,尤其是常驻任务应该和hyperv完全没差别


--【肆】--:

那确实难受


--【伍】--:

镜像模式下代理软件开全局模式,wsl2就是全走代理了


--【陆】--:

哈哈感觉wsl2更轻量呢…… 我那电脑跑的服务太多了


--【柒】--:

牛的飞佬


--【捌】--:

win10开不了镜像 …… win11就没这些问题……

标签:人工智能