我正在尝试设置一台 Windows 计算机,以便始终拥有两个到我的 Linux 服务器的 SSH 隧道。
目前,我正在使用 PuTTY 打开两个 SSH 隧道:我在 PuTTY 中登录服务器,将其最小化,并且从不碰它。这很有效,除非 SSH 连接断开:PuTTY 会显示错误消息,我需要手动关闭错误并重新连接到服务器。
我想要一个可以设置两个 SSH 隧道并自动重新连接的应用程序,而无需手动执行任何操作,包括输入密码。我通过这两个隧道发送的数据是 VNC 连接,因此我经常不会在机器旁清除错误并输入密码。这两个隧道是一个本地隧道和一个远程隧道。
(是的,我知道自动登录 SSH 的危险。我打算创建一个没有权限且不允许以交互方式登录的专用用户,然后使用它。)
我确实发现了这个问题:如何可靠地保持 SSH 隧道畅通?,但那是使用 Linux 作为 SSH 客户端,而我使用的是 Windows。
答案1
尝试Bitvise Tunnelier- 它对我来说很管用。我将其设置为建立 SSH 隧道,同时仅显示为托盘图标。它在启动时建立 SSH 连接,并在断线或系统进入睡眠状态后恢复连接后立即重新建立连接。我仍然更喜欢 Putty 控制台的外观,所以我继续使用它 - 但为了保持隧道畅通,我现在使用 Tunnelier。我发现的唯一主要缺点是缺乏 IPv6 支持,而 Putty 无需用户操作即可提供 IPv6 支持。
答案2
尝试我的EnTunnel. 连接失败时可重新连接。
答案3
我尝试过许多解决方案,例如 SSH 隧道管理器,但对我来说都很不方便:配置屏幕太多,有时有错误(有一次 SSH 隧道管理器清除了我所有的设置!所以我不得不恢复所有 30 个隧道的设置)。所以他们都失去了我的信任。这就是为什么我想出自定义 Powershell 脚本,易于配置、可更改、小巧但有效。已发布这里及以下:
要开始使用它,您需要如下配置:
# LocalPort TargetHost TargetPort SshHost SshUsername SshKeyPath
18080 google.com 80 bastion.example.com User D:\secure\path\to\private_key.ppk
将其保存为 config.csv。并使用 powershell 脚本来保存它:
<#
.SYNOPSIS
Powershell script for keeping ssh tunnel up and running
.DESCRIPTION
This script uses configuration of tunnels located in config.csv. For more information visit http://tsherlock.tech/2019/03/13/simple-ssh-tunnel-auto-reconnect-using-putty-and-powershell/
.NOTES
Version: 1.0
Author: Anton Shkuratov
Creation Date: 2019-03-13
Purpose/Change: Initial script development
#>
$currentDir = $PSScriptRoot
if (-not $env:PATH.Contains($currentDir)) {
$env:PATH="$env:PATH;$currentDir"
}
# Check plink is accessible
try {
Start-Process plink.exe -WindowStyle Hidden
} catch {
Write-Host Error running plink.exe Please make sure its path is in PATH environment variable
EXIT 1
}
# Parse config
$config = [System.IO.File]::ReadAllLines("$currentDir\config.csv");
$bindings = New-Object System.Collections.ArrayList
$regex = New-Object System.Text.RegularExpressions.Regex("(\d)+\s([^ ]+)\s(\d+)\s([^ ]+)\s([^ ]+)\s([^ ]+)", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase);
$keyPasswords = @{}
$procs = @{}
foreach($line in $config) {
$match = $regex.Match($line)
if ($match.Success) {
$sshKey = $match.Groups[6];
$bindings.Add(@{
LocalPort = $match.Groups[1];
TargetHost = $match.Groups[2];
TargetPort = $match.Groups.Groups[3];
SshHost = $match.Groups[4];
SshUser = $match.Groups[5];
SshKey = $match.Groups[6];
});
if (-not $keyPasswords.ContainsKey($sshKey)) {
$pass = Read-Host "Please enter password for key (if set): $sshKey" -AsSecureString
$keyPasswords.Add($sshKey, $pass);
}
}
}
# Starting Processes
function EnsureRunning($procs, $keyPasswords, $binding) {
if ($procs.ContainsKey($binding) -and $procs[$binding].HasExited) {
$proc = $procs[$binding]
$sshKey = $binding.sshKey
$out = $proc.StandardError.ReadToEnd()
if ($out.Contains("Wrong passphrase")) {
Write-Host "Wrong pass phrase for $sshKey, please re-enter"
$pass = Read-Host "Please enter password for key: $sshKey" -AsSecureString
$keyPasswords[$sshKey] = $pass;
} else {
$exitCode = $proc.ExitCode
$tHost = $binding.sshHost
Write-Host "Connection to $tHost is lost, exit code: $exitCode"
}
}
if (-not $procs.ContainsKey($binding) -or $procs[$binding].HasExited) {
$sshUser = $binding.SshUser
$sshHost = $binding.SshHost
$sshKey = $binding.SshKey
$lPort = $binding.LocalPort
$tPort = $binding.TargetPort
$tHost = $binding.TargetHost
$sshKeyPass = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($keyPasswords[$sshKey]))
$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.FileName = "plink.exe";
$psi.UseShellExecute = $false;
$psi.CreateNoWindow = $true;
$psi.RedirectStandardInput = $true;
$psi.RedirectStandardError = $true;
$psi.Arguments = "-ssh $sshUser@$sshHost -i `"$sshKey`" -batch -pw $sshKeyPass -L $lPort`:$tHost`:$tPort"
$proc = [System.Diagnostics.Process]::Start($psi);
Start-Sleep 1
if (-not $proc.HasExited) {
Write-Host Connected to $sshUser@$sshHost
}
$procs[$binding] = $proc;
}
}
function EnsureAllRunning($procs, $keyPasswords, $bindings) {
while($true) {
foreach($binding in $bindings) {
EnsureRunning $procs $keyPasswords $binding
}
Start-Sleep 1
}
}
try {
# Waiting for exit command
Write-Host Working... Press Ctrl+C to stop execution...
EnsureAllRunning $procs $keyPasswords $bindings
} finally {
# Clean up
Write-Host Clean up
foreach($proc in $procs.Values) {
if ($proc -ne $null -and -not $proc.HasExited) {
$proc.Kill();
}
}
}
配置完成后,只需像这样运行它:
powershell -File autossh.ps1
答案4
看一下外壳- 它比 PuTTY 更易于编写脚本,并且对于家庭使用是免费的(如果您需要使用它的话)。它声称具有自动重新连接功能,但我还没有尝试过,而且我已经使用基于 Linux 的笔记本电脑好几个月了,所以目前没有任何方法可以测试它。