A Nextjournal Webserver Environment With Ngrok and Clojure

Introduced in 1969, the PDP-15 was DEC's fifth (and last) 18-bit computer system. [Image: Digital Equipment Corporation via Bob Supnik]
Server
Localhost Tunnel: ngrok
Install ngrok.
curl -sS https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip -o ngrok.zipunzip /ngrok.zip-bind-tls=true
Settings for the ngrok configuration file. TODO: Why not Port 5000?
regionusconsole_uitruetunnels btf protohttp addr5000 subdomainbtfGrab 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.ymlRun 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 1tail /tmp/ngrok.logThe 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 updateapt-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"}}}