Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Get ngrok hostname from command line
#!/bin/sh
# ngrok's web interface is HTML, but configuration is bootstrapped as a JSON
# string. We can hack out the forwarded hostname by extracting the next
# `*.ngrok.io` string from the JSON
#
# Brittle as all get out--YMMV. If you're still reading, usage is:
#
# $ ./ngrok_hostname.sh <proto> <addr>
#
# To retrieve the ngrok'd URL of an HTTP service running locally on :3332, use:
#
# $ ./ngrok_hostname.sh http localhost:3332
#
# The protocol (http, https, etc) of the forwarded service
PROTO=$1
# The address of the forwarded service
ADDR=$2
# Hack JSON out of the web interface bootstrap
json=$(curl -s localhost:4040/inspect/http \
| grep -oP 'window.common[^;]+' \
| sed 's/^[^\(]*("//' \
| sed 's/")\s*$//' \
| sed 's/\\"/"/g')
# Parse JSON for the URLs matching the configured `$ADDR`
hosts=$(echo $json \
| jq -r ".Session.Tunnels \
| values \
| map(select(.Config.addr == \"$ADDR\") | .URL) | .[]")
echo "$hosts" | grep "^${PROTO}:"
@allank

This comment has been minimized.

Copy link

@allank allank commented Jul 27, 2017

I discovered today that ngrok have implemented an API on localhost that returns JSON without having to fiddle about in the HTML of the status page:

curl http://127.0.0.1:4040/api/tunnels

@rjz

This comment has been minimized.

Copy link
Owner Author

@rjz rjz commented Sep 19, 2017

Phew! That's much friendlier to work with.

@fvclaus

This comment has been minimized.

Copy link

@fvclaus fvclaus commented Mar 7, 2018

Extract the public url:
curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p'

@bpourriahi

This comment has been minimized.

Copy link

@bpourriahi bpourriahi commented May 19, 2018

Using jq:
curl --silent http://127.0.0.1:4040/api/tunnels | jq '.tunnels[0].public_url'

@markroxor

This comment has been minimized.

Copy link

@markroxor markroxor commented Jun 20, 2018

Wish I could give a thumbs up to the comments. Thanks a ton.

@Artistan

This comment has been minimized.

Copy link

@Artistan Artistan commented Aug 7, 2018

thanks for the inspiration @rjz and @bpourriahi

I created a couple scripts that will start ngrok in the background, get the new domain name, and update my domain name on digitalocean so that i have a consistent cname to use in development.

https://gist.github.com/Artistan/e1da8a060900d5db3c3eb001e076b4e9

CHEERS!

@jhalehol

This comment has been minimized.

Copy link

@jhalehol jhalehol commented Aug 21, 2018

Thanks @fvclaus, that's works for me

@derianpt

This comment has been minimized.

Copy link

@derianpt derianpt commented Sep 27, 2018

Thanks @fvclaus!

@ellisgl

This comment has been minimized.

Copy link

@ellisgl ellisgl commented Oct 18, 2018

Thanks @fvclaus!

@adamshamsudeen

This comment has been minimized.

Copy link

@adamshamsudeen adamshamsudeen commented Nov 22, 2018

Thanks @fvclaus :)

@ChieftainY2k

This comment has been minimized.

Copy link

@ChieftainY2k ChieftainY2k commented Jan 24, 2019

Thanks guys! 👍

@krzyk

This comment has been minimized.

Copy link

@krzyk krzyk commented Apr 21, 2019

my ngrok doesn't expose anything on port 4040, Is there a specific option when starting ngrok that I should use (normally I start it using ngrok tcp 123)

@scippacercola

This comment has been minimized.

Copy link

@scippacercola scippacercola commented May 20, 2019

Thanks. On minimal system setup I used:
echo -e 'GET /api/tunnels HTTP/1.1\nHost: 127.0.0.1\n' | nc localhost 4040

@stvnmntjy

This comment has been minimized.

Copy link

@stvnmntjy stvnmntjy commented Jan 23, 2020

Apologies for the rez, but to answer @krzyk: You can configure a web_addr property in the ngrok.yml (see "The ngrok configuration file" and "web_addr" here: https://ngrok.com/docs).

If you just want to know the port, it's the one listed in ngrok's session under Web Interface:

ngrok

Mine alternates from 4040 to 4041 at-whim.

@swathi-ashok

This comment has been minimized.

Copy link

@swathi-ashok swathi-ashok commented Feb 7, 2020

Thanks a lot. Works like charm. This is exactly what I was looking for.

@certainty157502

This comment has been minimized.

Copy link

@certainty157502 certainty157502 commented Mar 17, 2020

Extract the public url:
curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p'

Hi, I have two tunnels in Ngrok.. how do I extract the public url of two different tunnels?

@swathi-ashok

This comment has been minimized.

Copy link

@swathi-ashok swathi-ashok commented Mar 18, 2020

curl --silent http://127.0.0.1:4040/api/tunnels | jq '.tunnels[0].public_url' ---> This will give you the public URL of the first tunnel
curl --silent http://127.0.0.1:4041/api/tunnels | jq '.tunnels[0].public_url' ---> This will give you the public URL of the second tunnel.
Likewise, if you have multiple tunnels, increment the port number (4041) in the above URL by one to get the corresponding public URL.

Ex : 4042 for third tunnel, 4043 for fourth tunnel and so on.

@shamiul94

This comment has been minimized.

Copy link

@shamiul94 shamiul94 commented May 19, 2020

This one worked for me.

curl -s localhost:4040/api/tunnels | jq -r .tunnels[0].public_url
@TheDarkMythos

This comment has been minimized.

Copy link

@TheDarkMythos TheDarkMythos commented Jun 9, 2020

is there any way to do that with C#?

@AKASGaming

This comment has been minimized.

Copy link

@AKASGaming AKASGaming commented Jul 23, 2020

Is there a JavaScript version of this?

@pilotmaks

This comment has been minimized.

Copy link

@pilotmaks pilotmaks commented Sep 16, 2020

def get_ngrok_hostname():
url = "http://127.0.0.1:4040/api/tunnels"
try:
response = requests.get(url)
url_new_https = response.json()["tunnels"][0]["public_url"]
return url_new_https
except:
return None
# print(json.dumps(r.json(), indent=4))
# pprint.pprint(r, width=1)

@mikebridge

This comment has been minimized.

Copy link

@mikebridge mikebridge commented Sep 18, 2020

Or to query by name rather than position:

curl --silent http://127.0.0.1:4040/api/tunnels | jq -r '.tunnels[] | select(.name == "MY_TUNNEL_NAME") | .public_url'
=>
https://abcde12345.ngrok.io

** Edit Jan 15 2021: added -r to remove quotes

@michael-lins

This comment has been minimized.

Copy link

@michael-lins michael-lins commented Sep 29, 2020

for the Rails community:

With this code you run the rails app with assets pointing to the tunnel, if available 👍

Create an initializer and call it "ngrok.rb" (just for the sake of sanity) and paste this on:

require 'net/http'
require 'json'

begin
  uri = URI("http://127.0.0.1:4040/api/tunnels")
  ngork_resp = Net::HTTP.get(uri)
  ngork_json = JSON.parse(ngork_resp)
  tunnel = ngork_json["tunnels"].first
  tunnel_uri = URI(tunnel["public_url"])
  Rails.application.configure do
    config.hosts << tunnel_uri.host
    config.action_controller.asset_host = tunnel_uri.to_s
    config.action_mailer.asset_host = config.action_controller.asset_host
  end
  puts "Yep, tunnel configured! all set on #{tunnel_uri.to_s}"
rescue
  puts "no tunnel configured! skiping configuration..."
end
@scott-knight

This comment has been minimized.

Copy link

@scott-knight scott-knight commented Sep 30, 2020

@michael-lins That initializer is excellent! Thank you for posting that.

@vanbwodonk

This comment has been minimized.

Copy link

@vanbwodonk vanbwodonk commented Oct 9, 2020

Nice threads !! I make python scripts to send all ngrok connections to telegram bot. So, we can connect to ssh without login to ngrok web.
https://github.com/vanbwodonk/Ngrok-TelegramBot-Status

@fdeh75

This comment has been minimized.

Copy link

@fdeh75 fdeh75 commented Nov 23, 2020

Thanks @fvclaus)

@funder7

This comment has been minimized.

Copy link

@funder7 funder7 commented Dec 14, 2020

My gosh guys...thanks, this is awesome!

@funder7

This comment has been minimized.

Copy link

@funder7 funder7 commented Dec 15, 2020

I've created a bash script with the snippets found here, which takes the ngrok hostname and copies it into a spring configuration file (yml).

#!/bin/sh
#
# Wrapper script to launch reverse proxy with local configuration
# and copy tunnel's hostname into (spring) yml configuration
#
# Created 15 december 2020 - Federico Ricchiuto <f.ricchiuto@ital.dev>
#

FILE=./ngrok
CONFIGURATION=./ngrok.yml
SPRING_CONFIG_PATH=~/yourprojectpath/src/main/resources/config/application-dev.yml
OIDC_PROTOCOL='http'
OIDC_PATH='auth/realms/jhipster'
bold=$(tput bold)

echo "Checking ngrok executable..."

if test -f "$FILE"; then

  if test -f "$CONFIGURATION"; then

    echo "Starting ngrok..."
    (./ngrok start -config ./ngrok.yml --all ) > /dev/null &

    sleep .7 # Wait for ngrok launch

    NGROK_HOSTNAME=$(curl --silent --show-error http://127.0.0.1:4040/api/tunnels | sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p')

    echo "Replacing backend app IdP setting..."
    NEW_SETTING="$OIDC_PROTOCOL://$NGROK_HOSTNAME/$OIDC_PATH"
    sed -i -e "s#issuer-uri.*#issuer-uri: ${NEW_SETTING}#" "$SPRING_CONFIG_PATH"

    echo "${bold}ngrok running @ $NGROK_HOSTNAME"
    wait

  else
    echo "Missing ngrok.yml configuration file - Pull from repository if deleted"

  fi
else
    echo "ngrok executable not found" >&2
    echo "Download from: https://ngrok.com/download"
fi

It verifies also if the ngrok executable is present in the same folder. You can call directly ngrok without checking it's configuration file, but in case that you need it:

authtoken: xxxx
region: eu
tunnels:
  revproxy:
    addr: 80
    proto: http
    # bind_tls: true # enables https only
    inspect: true # enables console @ localhost:4040

Im not a bash scripting expert, it can be improved. The hard part is calling curl after it's launch, as the process is running. Without redirecting it to /dev/null it wouldn't be possible to execute the following commands.

This way ngrok's output is lost, it's kinda sad :/

@reachlin

This comment has been minimized.

Copy link

@reachlin reachlin commented Apr 8, 2021

seems not working anymore:

% curl --silent --show-error http://127.0.0.1:4040/api/tunnels 
curl: (52) Empty reply from server
% curl -v http://localhost:4040/inspect/http                   
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 4040 (#0)
> GET /inspect/http HTTP/1.1
> Host: localhost:4040
> User-Agent: curl/7.64.1
> Accept: */*
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server
* Closing connection 0
@funder7

This comment has been minimized.

Copy link

@funder7 funder7 commented Apr 8, 2021

Which version of ngrok?

@reachlin

This comment has been minimized.

Copy link

@reachlin reachlin commented Apr 8, 2021

Which version of ngrok?

should be latest one, just tried one hour ago

@funder7

This comment has been minimized.

Copy link

@funder7 funder7 commented Apr 11, 2021

should be latest one, just tried one hour ago

Just tried with the latest stable, it is working as usual.
Did you add inspect: true in your config file? (ngrok.yml)

@reachlin

This comment has been minimized.

Copy link

@reachlin reachlin commented Apr 12, 2021

no luck.thx anyway

@Ozymandias1700

This comment has been minimized.

Copy link

@Ozymandias1700 Ozymandias1700 commented Jul 17, 2021

url_new_https = response.json()["tunnels"][0]["public_url"]

Nice, good stuff. Amazing thread here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment