Skip to content

Instantly share code, notes, and snippets.

@lyoshenka
Last active February 1, 2024 20:14
Show Gist options
  • Save lyoshenka/002b7fbd801d0fd21f2f to your computer and use it in GitHub Desktop.
Save lyoshenka/002b7fbd801d0fd21f2f to your computer and use it in GitHub Desktop.
How to setup Ngrok with a self-signed SSL cert

Intro

The plan is to create a pair of executables (ngrok and ngrokd) that are connected with a self-signed SSL cert. Since the client and server executables are paired, you won't be able to use any other ngrok to connect to this ngrokd, and vice versa.

DNS

Add two DNS records: one for the base domain and one for the wildcard domain. For example, if your base domain is domain.com, you'll need a record for that and for *.domain.com.

Different Operating Systems

If the OS on which you'll be compiling ngrok (that's the server section below) is different than the OS on which you'll be running the client, then you will need to set the GOOS and GOARCH env variables. I run Linux everywhere, so I don't know how to do that. Please Google it or see the discussion here. If you know how to do this and want to add GOOS/GOARCH instructions here, please let me know.

On Server

MAKE SURE YOU SET NGROK_DOMAIN BELOW. Set it to the base domain, not the wildcard domain.

NGROK_DOMAIN="my.domain.com"
git clone https://github.com/inconshreveable/ngrok.git
cd ngrok

openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000

cp rootCA.pem assets/client/tls/ngrokroot.crt
# make clean
make release-server release-client

Copy bin/ngrok to whatever computer you want to connect from. Then start the server:

bin/ngrokd -tlsKey=device.key -tlsCrt=device.crt -domain="$NGROK_DOMAIN" -httpAddr=":8000" -httpsAddr=":8001"

On Client

MAKE SURE YOU SET NGROK_DOMAIN BELOW. Set it to the base domain, not the wildcard domain.

NGROK_DOMAIN="my.domain.com"
echo -e "server_addr: $NGROK_DOMAIN:4443\ntrust_host_root_certs: false" > ngrok-config
./ngrok -config=ngrok-config 80

Or for SSH forwarding: ./ngrok -config=ngrok-config --proto=tcp 22

@goofansu
Copy link

Thank you so much. I've created one as ngrok.com is slow in China.

@damtur
Copy link

damtur commented Aug 17, 2015

Hey there,

I have question about *.host.com certificate. Why when I issue cert on *.host.com and compile code with same certificate ngrok client can't connect with server?
Why do I need *.host.com? Well to use https. I have been only able to set up tunnel with certificate issued on host.com. When after setting up a tunnel I type http://subdomain.host.com it works fine, but when I go to https://subdomain.host.com It doesn't work - it complains that certificate is not issued on subdomain.host.com but on host.com.
Also why if I create CA with host.com and then create server.crt with *.host.com it also doesn't work?
Can anyone please explain me how ngrok is using both those certs (root.pem and server.key, server.crt)

Thanks

@wouterh-dev
Copy link

It might be a good idea to also edit defaultServerAddr in src/ngrok/client/model.go to $NGROK_DOMAIN:4443 (Don't put $NGROK_DOMAIN literally in the file. Put your domain there). Then everything will work for your users without them needing a config file.

Also you can easily cross-compile using GOPATH=$(pwd) gox -tags 'release' ngrok/main/ngrok (to install gox: go get github.com/mitchellh/gox), as long as you've done everything lined out in the gist above, including make release-client.

@goofansu
Copy link

Just FYI, if you use server on linux and client on OS X, it will be very easy to use golang docker image to make a cross compile.

docker pull golang:1.4.3-cross
cd ngrok
docker run --rm  -v `pwd`:`pwd` -w `pwd` golang:1.4.3-cross make release-server
docker run --rm  -v `pwd`:`pwd` -w `pwd` -e GOOS=darwin -e GOARCH=amd64 golang:1.4.3-cross make release-client

Then in the bin directory, you can find ngrokd and darwin_amd64/ngrok.

🍻 😆

@lukehorvat
Copy link

In my case, I needed a server binary for an Ubuntu droplet on Digital Ocean, and client binaries for a Macbook Pro and Raspberry Pi. So I did the following:

GOOS="linux" GOARCH="amd64" make release-server
GOOS="darwin" GOARCH="amd64" make release-client
GOOS="linux" GOARCH="arm" make release-client

All possible GOOS / GOARCH values are documented here.

@Yaoshicn
Copy link

Thanks a lot! It works well!

@dmorn
Copy link

dmorn commented May 19, 2017

I just want to point out a thing for the people that stumble upon this article (very helpful btw, thank you). It is really important that you compile you server and client application with the certificate that your going to use already copied into the assets/client/tls/ folder. Otherwise you'll get the Failed to read message: remote error: bad certificate error.

@h4ck4life
Copy link

Hi @danielmorandini , I'm getting the error you mentioned. Don't really understand your suggestion on how to fix it, do you mind to explain more? Thanks!

@koenhendriks
Copy link

@danielmorandini , @h4ck4life,

same problem here. Tried to rebuild client with custom root CA but its not working, still getting errors of invalid certificates..

@przano
Copy link

przano commented Jul 14, 2018

I've tried everything suggested here. Just can't seem to get it working.. bad certificate error.

I have more general questions. Preface; Once the binaries are compiled using "make release-server release-client", they show up in the "bin" sub directory (along with another file in there called "go-bindata").

When starting the server as described in this forum, does the "device.key" and "device.crt" need to be in the "bin" directory as well (same directory as "ngrokd")?

When starting the client (using the "ngrok-config"), does the "ngrokroot.crt need to be in the same directory as "ngrok"?

Or, am I totally confused?

Any help is greatly appreciated.

@goofansu
Copy link

Make sure to do cp rootCA.pem assets/client/tls/ngrokroot.crt and rootCA.pem is your own certificate.

@goofansu
Copy link

@przano

When starting the server as described in this forum, does the "device.key" and "device.crt" need to be in the "bin" directory as well (same directory as "ngrokd")?

Yes.

For simplicity, you can build a ngrokd image with docker:

Dockerfile

FROM alpine:latest

WORKDIR /opt
ADD ngrokd device.key device.crt ./

EXPOSE 80
EXPOSE 443
EXPOSE 4443

ENTRYPOINT ["./ngrokd","-tlsKey","device.key","-tlsCrt","device.crt","-domain","yourdomain.com"]

Build and push the image

env GOOS=linux GOARCH=amd64 make release-server
cp bin/ngrokd
docker build . -t yourname/ngrok:latest
docker push yourname/ngrok:latest

Run on server

On the server, just execute docker run -d --restart=always -p 80:80 -p 443:443 -p 4443:4443 yourname/ngrok:latest.

When starting the client (using the "ngrok-config"), does the "ngrokroot.crt need to be in the same directory as "ngrok"?

No.

Make sure you have put the crt in assets/client/tls/ before make release-client. It will be packaged into the binary.

@przano
Copy link

przano commented Jul 21, 2018

Thanks for response @goofansu. It appears to be working now.

@g10guang
Copy link

I execute the same command. But I always meet:

[16:12:42 CST 2018/11/17] [INFO] (ngrok/log.(*PrefixLogger).Info:83) [tun:201b1722] New connection from 113.87.12.25:26278
[16:12:42 CST 2018/11/17] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [tun:201b1722] Waiting to read message
[16:12:42 CST 2018/11/17] [WARN] (ngrok/log.(*PrefixLogger).Warn:87) [tun:201b1722] Failed to read message: remote error: tls: bad certificate
[16:12:42 CST 2018/11/17] [DEBG] (ngrok/log.(*PrefixLogger).Debug:79) [tun:201b1722] Closing

What's the problem?
Thank you.

@pengyou200902
Copy link

pengyou200902 commented Apr 8, 2019

Also why if I create CA with host.com and then create server.crt with *.host.com it also doesn't work?Can anyone please explain me how ngrok is using both those certs (root.pem and server.key, server.crt)

@damtur I just have the same problems !!!!

@tango-j
Copy link

tango-j commented Apr 30, 2020

It might be a good idea to also edit defaultServerAddr in src/ngrok/client/model.go to $NGROK_DOMAIN:4443 (Don't put $NGROK_DOMAIN literally in the file. Put your domain there). Then everything will work for your users without them needing a config file.

Also you can easily cross-compile using GOPATH=$(pwd) gox -tags 'release' ngrok/main/ngrok (to install gox: go get github.com/mitchellh/gox), as long as you've done everything lined out in the gist above, including make release-client.

Cant we put defaultServerAddr in src/ngrok/client/model.go to $NGROK_DOMAIN:443 and not 4443?

@doraeric
Copy link

doraeric commented Feb 12, 2021

I encounter the "bad certificate", too.
The error message from client shows

[01:53:34 CST 2021/02/13] [EROR] (ngrok/log.Error:120) control recovering from failure x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

After searching, seems like ignoreCN are relative to go 1.15,
I tried export GODEBUG=x509 ignoreCN=0 and export GODEBUG=x509ignoreCN=0 with no luck.

Finally, I use gvm to install go 1.14 and rebuild, and it works now.

gvm install go1.14.15
gvm use go1.14
make release-server release-client

@ajaxsys
Copy link

ajaxsys commented Mar 2, 2021

I encounter the "bad certificate", too.
The error message from client shows

[01:53:34 CST 2021/02/13] [EROR] (ngrok/log.Error:120) control recovering from failure x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

After searching, seems like ignoreCN are relative to go 1.15,
I tried export GODEBUG=x509 ignoreCN=0 and export GODEBUG=x509ignoreCN=0 with no luck.

Finally, I use gvm to install go 1.14 and rebuild, and it works now.

gvm install go1.14.15
gvm use go1.14
make release-server release-client

You save my life...
I tried to install on ec2, and by default yum install golang installed go1.15

@doraeric
Copy link

doraeric commented May 2, 2021

I found a similar tool with more features, it's frp

It support udp port forwarding, range port forwarding, and forwarding specific ip on local (192.168.x.x for example) rather than localhost (127.0.0.1).

Just leave a note in case someone has similar needs.

@iAbhinav
Copy link

iAbhinav commented May 8, 2021

Thankyou this helped a lot

@Saransh-spec
Copy link

Hello Guys, i am getting this error
image
Please help me, I am new to this.

@KlausHao
Copy link

I encounter the "bad certificate", too. The error message from client shows

[01:53:34 CST 2021/02/13] [EROR] (ngrok/log.Error:120) control recovering from failure x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

After searching, seems like ignoreCN are relative to go 1.15, I tried export GODEBUG=x509 ignoreCN=0 and export GODEBUG=x509ignoreCN=0 with no luck.

Finally, I use gvm to install go 1.14 and rebuild, and it works now.

gvm install go1.14.15
gvm use go1.14
make release-server release-client

Well done!
Thanks man!

@dkk421
Copy link

dkk421 commented Feb 1, 2024

make: *** No rule to make target 'release-server'. Stop.
hi, does anyone know how to solve this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment