Running your own ngrok with docker


A while ago, I read a post explaining how to run a self hosted ngrok. To be honest I did not even know what ngrok was at the time.

It turns out ngrok is a service that allows you to make your websites running in local available to the internet. Pretty cool. This is really convenient to quickly test how well a website works on a mobile phone.

The rub is, it took me at least 1 or 2 hours to get this solution working. This was mostly caused by some missing piece of information without which I could not get it to work on my laptop.

Indeed I had to change my SSH configuration. When possible I am always trying to prevent touching my configuration files. As I don’t keep these files versionned I know I’m going to forget these settings as soon as possible.

After a bit of a struggle I successfully reached my local application from an other network. I was really excited about it and decided to dockerize the setup in order to:

  • prevent editing configuration file for a single purpose
  • provide a disposable solution

Let’s picture it.

Schema architecture docker

After writing this post I found out I was not the only one inspired by the previous post. Here is a link to another similar article.

You can get all files used in this tutorial from this github repository.


  • docker and docker-compose installed both on your local machine and on your server

Setup server side

  • Let’s create the following docker-compose.yml file on the server.

I decided to expose ports 8082 and 2222 assuming you might already have ports 80 and 22 used by a web and SSH server.

version: '3.7'


    image: nginx:1.15.8
      - 3333:3333
      - 8082:80
      - ./nginx_app.conf:/etc/nginx/conf.d/default.conf

      context: .
      dockerfile: Dockerfile_sshd
      - "2222:22"

In case you are very picky as well as very observant you might wonder: why the quotes for port 2222 but not for ports 8082 and 3333? Well if - not only being picky and observant - you are curious as well, have a look at this issue that explains why for once I had to wrap this particular port between quotes:

  • As referenced in the docker-compose file, you also need to create a file named Dockerfile_sshd.

Follow the documentation to get more information on this one. Do not forget to change the password.

FROM ubuntu:16.04

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:youyoupassword' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN echo 'AllowTcpForwarding yes' >> /etc/ssh/sshd_config
RUN echo 'GatewayPorts yes' >> /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s* optional' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

CMD ["/usr/sbin/sshd", "-D"]

The only things I changed from the docker docs are gatewayports and allowtcpforwarding set to yes. More about this on this page

  • Finally, just as Jacob Errington in his blog, create a specific nginx_app.conf
server {
    access_log /var/log/nginx/$host;

    location / {
	    proxy_pass http://ssh_reverse_tunneling:3333/;
	    proxy_set_header X-Real-IP $remote_addr;
	    proxy_set_header Host $host;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
	    proxy_redirect off;

    error_page 502 /50x.html;
    location = /50x.html {
	    root /usr/share/nginx/html;

Still on your server, run docker-compose up -d and reach your server in a browser on port 8082. Let’s say

Here is what you should get:

Nginx error

Setup client side

On the client side, we just need a local application running on any port.

You can quickly run one in a container:

docker run --rm -p 8888:80 rothgar/microbot:v1

Let’s glue everything together by running the following command:

ssh -N -R -p 2222

I strongly encourage you to read Jacob Errington’s post which will explain this command better than I could do.

Type your password (youyoupassword if still not changed…) then browse once again.

Microbot website

Done! Your local application is now available on external networks!

If you found this tutorial helpful, star this repo as a thank you! ⭐