Port Forwarding
Net::SSH provides a powerful and easy-to-use API for forwarding TCP/IP ports and Unix domain sockets through an SSH connection. This is often called "SSH tunneling."
The forwarding API is accessed via ssh.forward
.
Local Port Forwarding
Local port forwarding allows you to forward connections from a port on your local machine to a port on a remote server. This is useful for accessing services on a remote machine's network that are not exposed to the internet.
Signature: ssh.forward.local(local_port, remote_host, remote_port)
local_port
: The port to listen on your local machine.remote_host
: The destination host to connect to from the SSH server.remote_port
: The port on the destination host.
Important: After setting up a forwarded port, you must run the event loop (ssh.loop
) to keep the connection alive and process forwarding requests.
Example: Accessing a Remote Database
Imagine a database server db.internal.network
is only accessible from your SSH gateway ssh.example.com
.
Net::SSH.start('ssh.example.com', 'user') do |ssh|
# Forward local port 5432 to the remote database server's port 5432
ssh.forward.local(5432, 'db.internal.network', 5432)
puts "Forwarding local port 5432. Connect your DB client to localhost:5432."
puts "Press Ctrl-C to stop."
# Keep the script running to handle forwarded connections
ssh.loop { true }
end
Now, any connection to localhost:5432
on your machine will be securely tunneled through ssh.example.com
to db.internal.network:5432
.
To stop forwarding, use ssh.forward.cancel_local(port, bind_address)
.
Remote Port Forwarding
Remote port forwarding is the reverse of local forwarding. It forwards connections from a port on the SSH server to a port on your local machine (or another machine accessible from your local machine).
Signature: ssh.forward.remote(local_port, local_host, remote_port, remote_host = '127.0.0.1')
local_port
: The port on the destination host to connect to.local_host
: The destination host (from your client's perspective).remote_port
: The port to listen on the SSH server.remote_host
: The address to bind to on the SSH server (e.g.,'0.0.0.0'
for all interfaces).
Example: Exposing a Local Web Server
If you have a local web server running on port 3000, you can expose it to the world through a public SSH server.
Net::SSH.start('public_server.com', 'user') do |ssh|
# Forward port 8080 on the remote server to port 3000 on your local machine
ssh.forward.remote(3000, 'localhost', 8080, '0.0.0.0')
puts "Forwarding remote port 8080. Access it via http://public_server.com:8080"
puts "Press Ctrl-C to stop."
ssh.loop { true }
end
Anyone connecting to http://public_server.com:8080
will have their traffic tunneled to localhost:3000
on your machine.
To stop, use ssh.forward.cancel_remote(port, host)
.
Unix Domain Socket Forwarding
Net::SSH also supports forwarding through Unix domain sockets, which is useful for services like Docker or database connections that use sockets.
Signature: ssh.forward.local_socket(local_socket_path, remote_socket_path)
This forwards connections from a local Unix socket to a remote Unix socket.
Example: Connecting to a Remote Docker Daemon
Net::SSH.start('docker-host', 'user') do |ssh|
local_socket = '/tmp/docker.sock'
remote_socket = '/var/run/docker.sock'
ssh.forward.local_socket(local_socket, remote_socket)
puts "Forwarding remote Docker socket to #{local_socket}"
puts "Run: DOCKER_HOST=unix://#{local_socket} docker ps"
puts "Press Ctrl-C to stop."
ssh.loop { true }
end
To stop, use ssh.forward.cancel_local_socket(path)
.