56

When I start an ngrok client with ./ngrok tcp 22 it runs in the foreground and I can see the randomly generated forwarding URL, such as tcp://0.tcp.ngrok.io:12345 -> localhost:22.

If I run in it the background with ./ngrok tcp &, I can't find any way to see the forwarding URL. How can I run ngrok in the background and still see the URL?

Julia Ebert
  • 1,583
  • 1
  • 21
  • 39

16 Answers16

63

There are a couple of ways.

You can either:

1) Visit localhost:4040/status in your browser to see a bunch of information, or

2) Use curl to hit the API: localhost:4040/api/tunnels

Abe Petrillo
  • 2,368
  • 23
  • 34
24

If you want to get the first tunnel then jq will be your friend:

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

When running more than one instance of ngrok then use the tunnel name /api/tunnels/:name.

icodebuster
  • 8,890
  • 7
  • 62
  • 65
avalanchy
  • 814
  • 1
  • 11
  • 19
  • 1
    In zsh for some reason, I had to prefix the '[' and ']' with '\', so here I had to run `curl -s localhost:4040/api/tunnels | jq -r .tunnels\[0\].public_url`. But works perfectly, thank! – Henrique Bruno Dec 10 '20 at 00:23
  • 4
    @HenriqueBruno for portability you can use double-quotes: `curl -s localhost:4040/api/tunnels | jq -r ".tunnels[0].public_url"` – François Leblanc Apr 30 '21 at 00:52
  • True! Haven't thought about it. Thanks! – Henrique Bruno Apr 30 '21 at 05:16
  • @François Leblanc Thanks! – Elon May 11 '21 at 18:45
  • Or if you don't want to install jq: #!/bin/bash ngrok_output=$(curl --silent --show-error http://127.0.0.1:4040/api/tunnels) # Find which subdomain ngrok assigned: ngrokUrl=$(echo $ngrok_output | sed -nE 's/.*public_url":"https:..([^"]*).*/\1/p') – Ryan Aug 11 '23 at 21:43
19

This little Python (2.7) script will call the ngrok API and print the current URL's:

import json
import os 

os.system("curl  http://localhost:4040/api/tunnels > tunnels.json")

with open('tunnels.json') as data_file:    
    datajson = json.load(data_file)


msg = "ngrok URL's: \n'
for i in datajson['tunnels']:
  msg = msg + i['public_url'] +'\n'

print (msg)
Gerard
  • 191
  • 3
5

Run ./ngrok http & This runs the ngrok tunnel as a background process. Ngrok usually opens a window showing the assigned URL but since we are using the nohup command this is not visible.

Thus, then run curl http://127.0.0.1:4040/api/tunnels too see the URL assigned by ngrok

M-Khawar
  • 855
  • 5
  • 17
Hemanth Kondapalli
  • 1,272
  • 12
  • 7
4

If it helps anyone I wrote a quick script to extract the generated random url in Node:

It makes assumption you're only interested in the secure url.

const fetch = require('node-fetch')
fetch('http://localhost:4040/api/tunnels')
  .then(res => res.json())
  .then(json => json.tunnels.find(tunnel => tunnel.proto === 'https'))
  .then(secureTunnel => console.log(secureTunnel.public_url))
  .catch(err => {
    if (err.code === 'ECONNREFUSED') {
      return console.error("Looks like you're not running ngrok.")
    }
    console.error(err)
  })

If you wanted all tunnels:

const fetch = require('node-fetch')
fetch('http://localhost:4040/api/tunnels')
  .then(res => res.json())
  .then(json => json.tunnels.map(tunnel => tunnel.public_url))
  .then(publicUrls => publicUrls.forEach(url => console.log(url)))
  .catch(err => {
    if (err.code === 'ECONNREFUSED') {
      return console.error(
        "Looks like you're not running ngrok."
      )
    }
    console.error(err)
  })
James Broad
  • 1,210
  • 12
  • 17
4

Use the ngrok API to get all active URLs

You will need to generate a token first (https://dashboard.ngrok.com/api)

Then fetch the active endpoints from the API

curl \
-H "Authorization: Bearer {API_KEY}" \
-H "Ngrok-Version: 2" \
https://api.ngrok.com/endpoints

check documentation: https://ngrok.com/docs/api/resources/endpoints

Mykyta
  • 71
  • 3
3
import json
import requests


def get_ngrok_url():
    url = "http://localhost:4040/api/tunnels/"
    res = requests.get(url)
    res_unicode = res.content.decode("utf-8")
    res_json = json.loads(res_unicode)
    for i in res_json["tunnels"]:
        if i['name'] == 'command_line':
            return i['public_url']
            break

This is an edit of JUN_NETWORKS python 3 code. It outputs the HTTPS URL only. I find Ngrok will randomly change the order of which is URL is displayed first sometimes outputting HTTP. The additional loop will consistently look for the 'tunnel' named 'command_line' which is the HTTPS URL.

Rex Tess
  • 31
  • 1
3

The easiest way for me to check random generated URL is to go to ngrok official site > dashboard > endpoints > status and check the URLs and status of my endpoints

Mykyta
  • 71
  • 3
  • 1
    That way the URL can't be used with programs and scripts. What if some program needs to access the ngrok URL or if you need the web page to be automatically updated with the correct link? – Chupo_cro May 21 '21 at 16:30
  • 1
    ngrok also provides API to check endpoints I described it here: https://stackoverflow.com/a/74403327/11280067 – Mykyta Nov 11 '22 at 13:37
2

In Python3

import json
import requests


def get_ngrok_url():
    url = "http://localhost:4040/api/tunnels"
    res = requests.get(url)
    res_unicode = res.content.decode("utf-8")
    res_json = json.loads(res_unicode)
    return res_json["tunnels"][0]["public_url"]

This returned json have 2 url for http and https. If you want only https url, you res_json["tunnels"][index num]["proto"]

JUN_NETWORKS
  • 351
  • 3
  • 7
2

If you love PowerShell, here it is in variables.

$ngrokOutput = ConvertFrom-Json (Invoke-WebRequest -Uri http://localhost:4040/api/tunnels).Content
$httpsUrl = $ngrokOutput.tunnels.public_url[0]
$httpUrl = $ngrokOutput.tunnels.public_url[1]
Johnny
  • 326
  • 4
  • 8
1

In Ruby

require 'httparty'

# get ngrok public url
begin
  response = HTTParty.get 'http://localhost:4040/api/tunnels'
  json = JSON.parse response.body
  new_sms_url = json['tunnels'].first['public_url']
rescue Errno::ECONNREFUSED
  print 'no ngrok instance found. shutting down'
  exit
end
Cruz Nunez
  • 2,949
  • 1
  • 23
  • 33
0

A Node.js solution.

Bonus: It copies the url to the clipboard in Windows, Mac and Linux1

const http = require("http");
const { execSync } = require("child_process");

const callback = (res) => {
    let data = "";
    res.on("data", (chunk) => (data += chunk));
    res.on("end", () => {
        const resJSON = JSON.parse(data);
        const tunnels = resJSON.tunnels;

        const { public_url: url } = tunnels.find(({ proto }) => proto === "https");

        console.log(url);

        // Copy to clipboard
        switch (process.platform) {
            case "win32":
                execSync(`echo ${url} | clip`);
                break;
            
            case "darwin":
                execSync(`echo ${url} | pbcopy`);
                break;
                
            case "linux":
                // NOTE: this requires xclip to be installed
                execSync(`echo ${url} | xclip -selection clipboard`);
                break;
                
            default:
                break;
        }
    });
};

http.get("http://localhost:4040/api/tunnels", callback);

[1] You need to install xclip first:

sudo apt-get install xclip
Abhijit
  • 468
  • 8
  • 22
0

If you're using nodejs I did this

const getURL = async () => {
  // inspect if the callback is working at: http://127.0.0.1:4040/inspect/http 
  const ngrok = await import('ngrok')
  const api = ngrok.getApi();
  const { tunnels } = JSON.parse(await api?.get('api/tunnels') ?? '{}')
  // if we already have a tunnel open, disconnect. We're only allowed to have 4
  if (tunnels?.length > 0) await ngrok.disconnect()
  return await ngrok.connect(3000)
}
Alex Cory
  • 10,635
  • 10
  • 52
  • 62
0

Here is a C# solution that fetches first URL from ngrok Agent API provided by localhost:4040/api.

//fetch xml from API `api/tunnels/command_line`
using var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, 
    "http://localhost:4040/api/tunnels/command_line");
request.Headers.Add(HttpRequestHeader.Accept.ToString(), "application/xml");
var response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();

//parse and get the first PublicURL element's text
const string Xpath = "/tunnelResource/PublicURL";
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(content);
var xmlNode = xmlDocument.SelectSingleNode(Xpath);
var xmlElement = xmlNode as XmlElement;
var url = xmlElement.InnerText;
zwcloud
  • 4,546
  • 3
  • 40
  • 69
-1

May be I'm a little too late in answering but would be glad if it is helpful for anyone visiting the question.

***Above answers are solutions to see/check the redirection URL. However to run ngrok in background, you could try using screen in linux . Incase you need help here a quick reference

Steps: 1. Just run the ngrok in screen and then detach. 2. Use the python script given by Gerard above to see the URL.

I have followed the same process and it works!

mohanjot
  • 1,490
  • 2
  • 11
  • 15
-1

There is a better way to do that just login to your account on ngrok.com. Your URL will be in your dashboard.