Skip to content

Use random local ports when doing automatic port forwarding or reuse existing tunnels #3561

Closed as not planned
@andreyorst

Description

@andreyorst

I often have to connect to a remote REPL running behind an SSH. CIDER has this custom option nrepl-use-ssh-fallback-for-remote-hosts which I relied on for quite a long time until recently.

The problem is when I use cider-connect-clj, and give it a remote host and port it will open an SSH tunnel to that host and port, which by itself is fine unless you want to connect to the same port from multiple projects, which I often have to do. It is problematic because CIDER creates a port forwarding from the given port to the same port, e.g. from localhost:1234 to user@remote:1234. Thus, when I go into the next project and try to do the same thing, CIDER tries to set up port forwarding from 1234 again, but it is already taken.

There are two possible solutions, I think:

  1. Use a random local port, e.g. when a user says M-x cider-connect-clj RET user@host RET 1234 RET, bind localhost:46573 to user@host:1234 instead of localhost:1234. It is similar to how CIDER currently works when using cider-jack-in-clj.
  2. Reuse existing tunnels - check if CIDER already set up a port forwarding for this particular port, and don't try to bind it again.

As an alternative, I've been using a custom ssh-tunnel function I've made for myself:

(defvar-local ssh-tunnel-port nil)
(put 'ssh-tunnel-port 'safe-local-variable #'numberp)

(defun ssh-tunnel (host port &optional local-port)
  "Start an SSH tunnel from localhost to HOST:PORT.
If LOCAL-PORT is nil, PORT is used as local port."
  (interactive (list (read-string "host: " nil 'ssh-host-history)
                     (read-number "port: " ssh-tunnel-port 'ssh-port-history)
                     (when current-prefix-arg
                       (read-number "local port: " ssh-tunnel-port 'ssh-port-history))))
  (let ((name (if (and local-port (not (= local-port port)))
                  (format "*ssh-tunnel:%s:%s:%s" local-port host port)
                (format "*ssh-tunnel:%s:%s" host port))))
    (async-shell-command
     (format "ssh -4 -N -L %s:localhost:%s %s" (or local-port port) port host)
     (concat " " name))))

It's also handy to have the ability to fix a specific remote port in a dir local variable, like I do above, so I could connect to a specific port immediately, instead of remembering what port this particular service uses every time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions