Background
I use a decent amount of home automation products, some of them are the KASA branded smart plugs. KASA has an app, which works, but I like to control stuff from my PC without needing to break out the phone. IFTTT has some official integrations which work really well. The problem is that IFTTT needs to make money, so they are starting to heavily restrict how many active integrations you can have (currently it’s 2). I have more plugs than two, so I needed a new way to trigger these integrations. IFTTT also enabled webhook integrations, so I could effectively hit a URL which would toggle my KASA devices on/off.
I could expose a webserver via my home Internet, setup the SSL, firewall, and all that jazz but there should be an easier way.
Enter NGROK. NGROK allows you to use an agent to do reverse SSL tunneling to a public url. In the free tier, the URL is randomized everytime you spin up the agent. In the Paid tier you can start to bring in your own domains(which is what I’ve done). NGROK is really designed to help you test public internet webhooks into development environments, but again in the paid tier you get a little more functionality that makes these more permanent.
NGROK has multiple ways to install agents, on almost all platforms. I chose to use Docker as I am also going to use the python-kasa module within a flask app to hold my own API. Coupled with NGROK I have a webhook I can trigger. I won’t go into the flask/python stuff here today, but plan to in a future post.
This project boiled down to me learning or improving the following technologies, but started with NGROK:
- NGROK
- Flask
- gunicorn
- python-kasa and asyncio
- Docker
NGROK
What I will use the remainder of this post describing, is my attempt at getting NGROK running in Docker. Why Docker? So I could learn a bit more about it. In the end I containerized this entire solution, so it was pretty informative.
NGROK has it’s own container documentation here. I did start with the one-liner commands, which worked pretty well, but ultimately I wanted this to run as a standalone container since it’s a bit more permanent. That led to looking at the documentation for Docker compose. The example they give does mostly work, however I could not get the volumes directive to actually run. Unfortunately my docker just refused to acknowledge the ngrok.yml file existed.
This led me to building my own Docker container based on the ngrok official version. My Dockerfile for that container is here but I will also post it here to make it easier to read:
FROM ngrok/ngrok:latest
COPY --chown=ngrok ngrok.yml /etc/ngrok.yml
ENTRYPOINT ["ngrok", "start", "--all", "--config", "/etc/ngrok.yml"]
Here’s a breakdown of what these mean
FROM ngrok/ngrok:latest
We’re going to use the latest version of the official ngrok container
COPY --chown=ngrok ngrok.yml /etc/ngrok.yml
This is what made it work. Wherever you’re building this container needs to have a ngrok.yml, which describes the ngrok tunnel configuration (how the agent connects to ngrok hosted servers, and to your application). This will copy that file into the proper place within the container for it to be available at run-time.
ENTRYPOINT ["ngrok", "start", "--all", "--config", "/etc/ngrok.yml"]
This tells the container what to do after it’s built, and when it starts. It’s the equivalent to running the following commandline, which starts all ngrok tunnels defined(I only have one, you could have multiples)
ngrok start --all --config /etc/ngrok.yml
Here is my boilerplage ngrok.yml definition, which again I’ll paste below for readability:
authtoken: <YOURAUTHTOKEN>
tunnels:
flask:
proto: http
addr: 8000
basic_auth:
- "user:pass"
domain: ngrok.your.domain # This might not be needed
version: 2
You should only need to fill in the authtoken, which ngrok provides you, and the user:pass to keep the tunnel secure(yes, there are other more secure options, this one is fine for me). I also have a custom domain, so I define that, exclude that section if you’re wanting the ngrok default URLs.
The name of the tunnel is flask, because that’s what it’s frontending. It’s using http to the backend, ngrok will front-end with an SSL certificate. The Address of the back-end is port 8000.
I hope this helps if you’ve stumbled on this post looking for NGROK and docker support.