A Nextjournal Webserver Environment With Ngrok and Clojure
Server
Localhost Tunnel: ngrok
Install ngrok.
curl -sS https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok.zip
unzip /ngrok.zip
-bind-tls=true
Settings for the ngrok configuration file. TODO: Why not Port 5000?
region us
console_uitrue
tunnels
btf
proto http
addr5000
subdomain btf
Grab your authtoken from ngrok. The token will authenticate this notebook with the ngrok service.
Store the token in your Nextjournal secret vault and add it to the environment.
Prepend the authtoken to the configuration file above, ngrok.yml
.
echo 'authtoken:' $ngrok | cat - ngrok.yml > /tmp/out && mv /tmp/out ngrok.yml
Run ngrok
in the background using nohup. Unfortunately, there are no plans to offer a daemon service in the basic ngrok package.
nohup /ngrok start --all --config="/ngrok.yml" &> /tmp/ngrok.log & sleep 1
tail /tmp/ngrok.log
The service is up and running. To stop the ngrok tunnel, use the kill
command with the process ID: kill <PID>
or kill -9 "$(pgrep ngrok)"
.
ps aux
# kill 982
# kill -9 "$(pgrep ngrok)"
Server: Ring
Define a function to handle the request to the ngrok domain.
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"})
Start a Jetty server.
(require [ring.adapter.jetty :as jetty])
(jetty/run-jetty handler {:port 5000
:join? false})
Open the ngrok URL in another window. My ngrok service is configured to use the subdomain btf
(as configured in ngrok.yml
above). The result is "Hello World" at http://btf.ngrok.io/. This is only available to my account using my credentials.
If you do not have a paid account, you can simply use the free tunnel service with the dynamically-generated subdomain.
Client
Use clj-http to GET
/PUT
/POST
/DELETE
, etc.... Successfully get a website and receive a 200
response.
(require [clj-http.client :as client])
(:status (client/get "https://archive.org"))
Use cemerick.url to generate a valid URL.
(require [cemerick.url :refer (url url-encode)])
(str "https://html.duckduckgo.com/html/"
"&q=" (url-encode "clojure/clojurescript"))
Get the URL with a query.
(let [url (str "https://html.duckduckgo.com/html/"
"&q=" (url-encode "clojure/clojurescript"))]
{:nextjournal/viewer "html"
:nextjournal.viewer/value (:body (client/get url))})
Browser
Install firefox-geckodriver to use with Etaoin. Etaoin is a Clojure Webdriver protocol implementation.
apt-get update
apt-get install firefox-geckodriver
(require [etaoin.api :as e])
(def driver (e/firefox {:headless true}))
(e/headless? driver)
Where are we?
(e/go driver "https://nextjournal.com/")
(e/get-title driver)
Browse to the ngrok endpoint we just built in this notebook. It will return the server response, "Hello World."
(doto driver
(e/go "http://btf.ngrok.io/")
(e/screenshot "/results/server.png"))
Appendix
This work is licensed under a Creative Commons Attribution 4.0 International License.
{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
clj-http {:mvn/version "2.3.0"}
com.cemerick/url {:mvn/version "0.1.1"}
ring/ring-core {:mvn/version "1.8.2"}
ring/ring-jetty-adapter {:mvn/version "1.8.2"}
etaoin {:mvn/version "0.4.1"}
compliment/compliment {:mvn/version "0.3.9"}}}