Skip to content

Instantly share code, notes, and snippets.

@Viiprogrammer
Last active March 2, 2025 23:29
Show Gist options
  • Save Viiprogrammer/c3bb2e852e338882f5fcc1dc18b3cd04 to your computer and use it in GitHub Desktop.
Save Viiprogrammer/c3bb2e852e338882f5fcc1dc18b3cd04 to your computer and use it in GitHub Desktop.
Infinite SSH tunnel
const { spawn } = require('node:child_process');
const user = 'user'
const password = 'password'
const ip = '1.1.1.1'
const port = 5173
let sshCommand = `-p ${password} ssh `
sshCommand += '-o ServerAliveInterval=5 '
sshCommand += `${user}@${ip} `
let forwardError = false
async function main () {
const forwardCommand = sshCommand
+ `-R ${port}:localhost:${port} `
+ '-C -N -g -c [email protected] '
+ '-o ExitOnForwardFailure=yes '
const tunnel = spawn('sshpass', forwardCommand.split(' '))
tunnel.stdout.on('data', (data) => console.log(data.toString()))
tunnel.stderr.on('data', data => {
const err = data.toString()
console.error('Error while connect:', err)
// If port used, connect and kill process
if (!forwardError && err.includes('remote port forwarding failed for listen port')) {
forwardError = true
console.log('Looks port used, connect and kill')
const fuser = spawn('sshpass', [...sshCommand.split(' '), 'fuser', `-k ${port}/tcp`])
fuser.stdout.on('data', (data) => console.log(data.toString()))
fuser.stderr.on('data', data => console.error(data.toString()))
fuser.on('exit', async code => {
console.log(`Child exited with code ${code}`)
if (code === 0) {
console.log('Successfuly killed, wait 3000 ms and restart')
await new Promise(r => setTimeout(r, 3000))
main ()
}
})
}
})
tunnel.on('exit', code => console.log(`Child exited with code ${code}`))
}
main ()
@Viiprogrammer
Copy link
Author

Viiprogrammer commented Sep 22, 2024

Requires sshpass, ssh, node16, also can be started with pm2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment