How to Create Persistent SSH Tunnels as Windows Services Using CLI Tools


5 views

When setting up SSH tunnels on Windows servers, we need persistent connections that survive reboots and can be managed like other system services. The challenge lies in finding a CLI-compatible solution that doesn't require GUI tools or complex configuration.

Here are the most reliable CLI-capable tools for this purpose:

1. Plink (PuTTY Link) - Lightweight SSH client from PuTTY suite
2. Windows' native SSH client (since Windows 10 1809)
3. NSSM (Non-Sucking Service Manager) - For service wrapping
4. WinSW (Windows Service Wrapper) - Alternative to NSSM

This method uses Plink with NSSM for robust service creation:

# First, install NSSM:
choco install nssm -y

# Then create the service:
nssm install SSHTunnel "C:\path\to\plink.exe" -ssh -N -L 3306:localhost:3306 user@remotehost -i "C:\path\to\private_key.ppk" -P 22

# Configure service properties:
nssm set SSHTunnel AppDirectory "C:\path\to"
nssm set SSHTunnel DisplayName "MySQL SSH Tunnel"
nssm set SSHTunnel Start SERVICE_AUTO_START

For newer Windows versions (1809+):

# First generate SSH keys:
ssh-keygen -t rsa -b 4096 -f C:\ssh\tunnel_key

# Create batch script (tunnel.bat):
@echo off
ssh -N -L 3306:localhost:3306 -i C:\ssh\tunnel_key user@remotehost

# Then use WinSW to create the service:
<service>
  <id>SSHTunnel</id>
  <name>SSH Tunnel Service</name>
  <description>Persistent SSH tunnel to remote host</description>
  <executable>cmd.exe</executable>
  <arguments>/C C:\path\to\tunnel.bat</arguments>
  <log mode="roll"></log>
</service>
  • Always use key-based authentication (passwordless SSH)
  • Set up proper retry logic for connection drops
  • Configure firewall rules to allow the tunnel ports
  • Monitor tunnel health with logging or external tools

If the service fails to start:

# Check service logs:
nssm start SSHTunnel
nssm status SSHTunnel

# Test the SSH command manually first
# Verify network connectivity to the remote host
# Check permissions on private key files

When implementing SSH tunnels as Windows services, we have several robust command-line options:

# Plink (PuTTY command-line)
plink.exe -N -L 3306:localhost:3306 user@remote-server -pw password -batch

# OpenSSH for Windows (built-in)
ssh -N -L 8989:localhost:8989 user@example.com -f

The most reliable approach combines OpenSSH with NSSM (Non-Sucking Service Manager):

# Install NSSM
choco install nssm -y

# Create the service
nssm install SSH-Tunnel "C:\Windows\System32\OpenSSH\ssh.exe" -N -L 8080:localhost:80 user@server -i C:\keys\private.ppk

For production environments, implement a monitoring script:

@echo off
:loop
plink.exe -N -L 5432:localhost:5432 dbuser@dbserver -i C:\ssh\keyfile.ppk -batch
timeout /t 30
goto loop
  • Always use key-based authentication
  • Restrict service account privileges
  • Implement connection logging
  • Use non-standard ports when possible

For enterprise environments, Bitvise offers command-line configuration:

# Bitvise command-line configuration
bsshd.exe -install -svcName SSHTunnel -cmdFile "C:\tunnel_config.tbc"

Key problems and solutions:

# Check service status
sc query SSHTunnel

# View service logs
Get-EventLog -LogName Application -Source "OpenSSH" -Newest 20