Clojure - how to connect to running REPL process remotely
Asked Answered
B

6

17

How can I connect to a REPL session running on a remote server that I can access, for example via SSH?

Bimetallic answered 22/9, 2018 at 18:30 Comment(0)
B
20

This might be obvious to network specialists but took me a while to find out so documenting it here.

On the remote server, when launching your REPL application instead of just lein repl force binding to a port:

lein repl :start :port 40000

On your machine, connect to the remote server the normal way (for example via ssh). Then connect to your application this way:

lein repl :connect localhost:40000

That's it!

Bimetallic answered 22/9, 2018 at 18:30 Comment(0)
F
9

I just want to sum up the two answers above. It works on my machine:

On the remote machine

lein repl :start :port 40000

On the local machine

# SSH tunnel on one shell
ssh -NL 40000:localhost:40000 username@host

# Connect to the remote repl on another shell
lein repl :connect localhost:40000
Filamentous answered 24/9, 2018 at 14:55 Comment(1)
Thanks - but once you create the tunnel, how do you actually connect to port 40000 to interact with repl?Bimetallic
I
9

Well, that's simple. Briefly, there are some steps to be done:

  1. the nrepl package should be a part of the production build, but not just a dev dependency;
  2. When your app starts, it also spawns a repl session in a separate thread on a certain port;
  3. your server either exposes that port or you tunnel it through SSH.

Now the details:

1) Add these deps into the primary :dependencies vector:

:dependencies [[org.clojure/clojure "1.9.0"]
                 ;; for remote debugging
                 [cider/cider-nrepl "0.17.0"]
                 [org.clojure/tools.nrepl "0.2.13"]

You need cider-nrepl in case you work with Emacs/Cider. Otherwise, you may omit that.

2) Add a separate namespace to wrap nrepl server:

(ns project.nrepl
  (:require [clojure.tools.nrepl.server
             :refer (start-server stop-server)]))


(defn nrepl-handler []
  (require 'cider.nrepl)
  (ns-resolve 'cider.nrepl 'cider-nrepl-handler))


(defonce __server (atom nil))

(def set-server! (partial reset! __server))


(def port 7888)

(defn start
  []
  (when-not @__server
    (set-server!
     (start-server :port port :handler (nrepl-handler)))))


(defn stop
  []
  (when-let [server @__server]
    (stop-server server)
    (set-server! nil)))


(defn init
  []
  (start))

In your core module, just call (project.nrepl/init). Now your app allows connecting to it through nrepl.

3) On remote server, you may expose the TCP 7888 port to the outer world which is insecure. At least the port should be restricted from certain IP addresses, e.g. your office. The better option would be to forward it through SSH as follows:

ssh -L 7888:<remote-host>:7888 <user>@<remote-host>

Now, open Emacs, call M-x cider-connect RET localhost 7888 and it's done: you are connected to the remote app.

Invective answered 25/9, 2018 at 7:56 Comment(2)
Btw, nREPL 0.2.13 is ancient at this point. The current version is 0.4.5 (it has the new deployment artefact nrepl/nrepl).Factotum
Right, just copy-pasted from an old project.Invective
K
2

BTW, you can easily connect from one REPL/clojure app to other REPL (for example to compare eval results between dev and UAT) like this

=> (require '[clojure.tools.nrepl :as repl])
nil
=> (with-open [conn (repl/connect :port 59258)]
     (-> (repl/client conn 1000)    ; message receive timeout required
       (repl/message {:op "eval" :code "(+ 2 3)"})
       repl/response-values))
[5]

more here https://nrepl.org/nrepl/usage/clients.html#_talking_to_an_nrepl_endpoint_programmatically

Krishna answered 23/11, 2018 at 22:53 Comment(1)
wow it's just like a server-client mode that can be setup very easilyBlaylock
C
1

Secure way to connect to remote clojure repl

  1. start repl on localhost on remote machine
$ clj "-J-Dclojure.server.repl={:port 5555 :accept clojure.core.server/repl}"
  1. create ssh tunnel on local machine
$ ssh -L :5555:localhost:5555 remoteuser@remotehost -p 22 -N -v
  1. start repl on local machine and connect to remote repl via ssh:
$ clj -Sdeps '{:deps {vlaaad/remote-repl {:mvn/version "1.1"}}}'
Downloading: vlaaad/remote-repl/1.1/remote-repl-1.1.pom from clojars
Downloading: vlaaad/remote-repl/1.1/remote-repl-1.1.jar from clojars
Clojure 1.10.1
user=> (require '[vlaaad.remote-repl :as rr])
user=> (rr/repl :port 5555)
  1. or start repl on local machine and immediately drop into a remote repl
clj -Sdeps '{:deps {vlaaad/remote-repl {:mvn/version "1.1"}}}' -m vlaaad.remote-repl :port 5555
Congius answered 16/1, 2021 at 19:56 Comment(0)
D
0

maybe ssh tunnel (if repl running on remote host as localhost:6666)

on local machine ssh -L :6666:localhost:6666 remoteuser@remotehost -N -v

then just connect to localhost:6666

Danseur answered 23/9, 2018 at 6:59 Comment(2)
This didn't work for me - I opened the tunnel then started a separate terminal session on the local machine, typed nc localhost 6666 and nothing happened.Bimetallic
You need to use your repl port numberDanseur

© 2022 - 2024 — McMap. All rights reserved.