ngrok to the rescue

Port forwarding with a public IP address is fine. But without a public IP address you need to be a little bit more savvy. I currently have that situation with Carrier Grade NAT with my internet service provider. It is often the case with LTE connections and I believe it is the case with Starlink and Hyperoptic too.

These ISPs will use a bank of IP addresses in the IPv4 range

100.64.0.0/10
which translates to this range
100.64.0.0 – 100.127.255.255

These are reserved addresses and are not public. You would share your public address with many other users. Your router will have an IP address like 100.114.45.3 but it is not public facing. That could be something like 212.204.194.84

So how do you get around that problem. You don’t have access to the ISP router. You need to tunnel in to your device from the outside? Maybe open a SSH tunnel or show a webpage on a computer hosted inside that network.

Some people will create elaborate OpenVPN systems and relay traffic to a VPS hosted on a DigitalOcean droplet or Google Cloud image.

A little easier to swallow for simple tasks is a service called ngrok. This is magically. a terminal command opens up a tunnel and you are able to use the random domain endpoint to tunnel in. It has a free service which fits the bill for a couple of processes.

But what if I want this process to start when I turn my computer on? Using the same process as the Unifi post we can utilise the launchd process and create a plist to start this daemon.

Firstly install ngrok as per these instructions. I also went ahead and created a ngrok folder in my /Library/Scripts folder too to keep everything together.

For this we need a bash script and a ngrok configuration file.

The bash script is fairly simple a couple of lines.

#!/bin/sh
ngrok start -config=/Library/Scripts/ngrok/ngrok.yml http1

This calls up ngrok and a specific config file and asks it to start the tunnel named http1

The configuration file looks like this.

authtoken: madeuptoken_7867qdiasdy86wq98eq98qweqDmLr9
tunnels:
  http1:
    addr: 80
    proto: http

The first line is your unique authtoken, next is the tunnels and you could have many and call them what ever you wanted. I have a VNC port open on another device so I changed the proto to TCP. Check the ngrok documentation for more details.

Next up we have to create a plist in the /LibraryLaunchDaemons folder.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin</string>
    </dict>
    <key>KeepAlive</key>
    <dict>
         <key>SuccessfulExit</key>
         <false/>
     </dict>
    <key>Label</key>
    <string>com.ngrok.onstartup.plist</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Library/Scripts/ngrok/ngrok.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

The important part here is the EnvironmentVariables PATH, without this the service doesn’t have a clue where to look to for the tools to execute the script.

Make sure you change ownership of the plist to root:wheel

chown root:wheel /Library/LaunchDaemons/com.ngrok.onstartup.plist

Now all you have to do it run it.

launchctl load -w /Library/LaunchDaemons/com.ngrok.onstartup.plist

You can check it has worked by logging in to the ngrok dashboard and going to the status of the Endpoints. Use the domain here to access the device and port you configured.

My favourite bit about ngrok is that you can point the service to a different IP address on the network.

ngrok http 192.168.1.254:443

Leave a comment

Your email address will not be published. Required fields are marked *