ngrok is a tunneling, reverse proxy that establishes secure tunnels from a public endpoint to a locally running network service while capturing all traffic for inspection and replay. It is an open-source project on GitHub.
-
When you double-click a command-line application on any modern Windows OS, a new cmd.exe window opens running the application that was launched. When the program terminates, Windows closes the whole cmd.exe window. When executed with no arguments, almost all command line apps print their help text and then exit. From the perspective of a user who just double-clicked a command line app, they will see a command prompt open, display a large amount of text that they don’t have time to read and then close almost instantly. Anyone who didn’t initially learn on a command line will probably remember this initial growing pain.
To say the least, this is a tremendously poor user experience. Not only did the program fail to work, but it did so without displaying any error message or diagnostic text that explains why it did not work. There isn’t even anything to search Google or Stack Overflow for!
Authors of most CLI tools simply choose to ignore that they completely fail for this cohort of users. It’s easy to rationalize that it’s not your problem, that it’s an error in how the user is interacting with their operating system. “All of my users are technical enough to understand that!” you cry. And I’ll tell you that they will have to be, if that’s your attitude.
I don’t have that luxury. Until about six months ago, I received a support email almost every week from an ngrok user who was running into this exact issue. ngrok’s target userbase spans everyone from network engineers to designers to hobbyist gamers who want to host their own minecraft server. In short, ‘non-technical’ describes a large percentage of the userbase. Here are a few examples of support emails:
i downloaded it and install it a terminal window poped out and nothing happened.
hi i have download for window when i try command prompt i suddent open and hide can you help me?
When I try to open the .exe file command prompt opens very briefly and then nothing happens. Please help?
Windows version for ngrok doesn’t work. I downloaded ngrok for windows 7 , 64 bit . When I click ngrok.exe , console flashes for half second and then vanishes.
I don’t get these support emails anymore. But before we dive into why that’s the case, I want to explain how I support ngrok.
As of this writing, there are over 17,000 registered ngrok users, and undoubtedly more who use it without an account. I support ngrok entirely by myself. There is no IRC channel for ngrok. There is no mailing list. Instead, I have made it extraordinarily easy to reach me, personally. Every page of ngrok.com not only has an email address that goes directly to me, but it also has an Olark chat window that you can use to communicate with me directly and synchronously at any hour of the day when I’m in front of my computer. The next version of ngrok will include this direct chat on the local introspection interface of every ngrok client. I’ve even idly toyed with including a phone number.
I have a secret, though: I hope you never use that chat window. I don’t want to talk to you. You’re all really lovely people, but I just don’t have the time for those interruptions. I’m being a bit hyperbolic here, of course. But think of it this way: when a new user has to talk to a human in order to fix a problem they’re having, the time-to-value of your product has just ballooned from seconds to minutes or possibly even hours or days. If a user contacts me to solve an issue, ngrok is no longer self-service and it has failed them as a product. Sometimes this is an error in the core functionality or an omission in the documentation. Those are the low hanging fruit of your support problem because they’re easy to fix. The more common cause is that the UX of the tool is not good enough, i.e. ngrok behaved in some way which did not match with the user’s expectations and it failed to communicate what change could be made to correct this expectation.
The goal of this support system I’ve constructed is to attempt to visit upon myself every pain that using ngrok inflicts on my customers. When you really boil it down to its essence, ngrok’s support strategy is to make it as easy as possible to contact me and then to optimize that conversion rate to zero. This is how you make a better product, this is how you really listen to your customers.
It works. I was sufficiently frustrated receiving these emails every week and typing the same explanation over and over again, that I decided to implement a fix.
The easy way to solve this problem is to create an FAQ or Knowledge Base item (or maybe in a larger organization to hire extra support staff). This is suboptimal. Users may not know to look in the FAQ. They may not know that it exists at all, or if it does what keywords they should search for. They may not even speak English! Even supposing neither of those apply and the user figures out what they were doing wrong, they will still experience the initial frustration of ngrok inexplicably failing. Don’t forget that this is part of ngrok’s first impression. A user just downloaded my application and is trying to use it for the first time. Failing in any way will decrease the perceived value of the product and make them that much less likely to pay for it and recommend it to their network.
With this in mind, I opted to pursue a technical fix. I initially didn’t know if this would work, but here’s the idea I experimented with:
If the parent process is named “explorer.exe” then display a message instructing users to open cmd.exe instead of running it from the command line, then sleep for a few seconds so they can read it.
So at that point, I went into the Go standard library, and found os.Getppid()
. It returns the parent process’ id which I could check against the id of explorer.exe. I tried it out and . . . nothing; it didn’t work. I discovered that, strangely os.Getppid()
was always returning -1 until I read the source code of syscall_windows.go
to find:
Oops! So I read some of the Win32 API documentation, and a bunch more examples from the standard library about how to call those functions from Go. Finally I had a working implementation of os.Getppid(), and when I wired it all into the stdlib, the whole thing worked!
Figuring that others could benefit from the work I’d done, I did two things. First, I submitted a changeset to the Go standard library to implement Getppid() for Windows. This was merged into Go 1.4. I then created a simple Go package which used os.Getppid() (and vendored the implementation for pre-1.4 versions) plus the other necessary Windows APIs to check if the parent process was explorer.exe. You can find it on github at inconshreveable/mousetrap.
I released ngrok 1.7 three months ago with mousetrap integrated, and I’ve only had a single support email about this issue since then from someone who didn’t understand how to open cmd.exe and use a command prompt. Victory!
In the process of writing up this blog post, I wondered if I could do even better. Is there a way I could eliminate that last support email? After searching around for a bit, I stumbled on cmd.exe’s /K
option which instructs cmd.exe to run the program and remain open after it terminates. The soon-to-released ngrok 2.0 contains the final iteration of this feature. When you double click it from explorer, it will relaunch itself using cmd /K
so that it executes as if you had opened the prompt yourself and run the command. Windows even launches the prompt in the directory of the double-clicked executable so there aren’t even problems with executable location. From there, a user can be instructed to type a proper incantation to invoke ngrok with the correct arguments. I’ve also wired it up to print out some additional help text that explains that you shouldn’t try double-clicking it from explorer again.
-
ngrok lives in a crowded marketplace. There are any number of similar programs and services. In the end, what makes ngrok the best in class tool is the attention to detail. It is the uncompromising focus on user experience. Sweat the small stuff, it matters more than you think.