Skip to content

Caddy http tunnel

Custom reverse proxy with Caddy

In this tutorial we'll set up an inlets TCP tunnel server to forward ports 80 and 443 to a reverse proxy server running on our local machine. Caddy will receive a TCP stream from the public tunnel server for ports 80 and 443. It can terminate TLS and also allow you to host multiple sites with ease.

Caddy is a free and open-source reverse proxy. It's often used on web-servers to add TLS to one or more virtual websites.

Pre-reqs

  • A Linux server, Windows and MacOS are also supported
  • The inlets-pro binary at /usr/local/bin/
  • Access to a DNS control plane for a domain you control

You can run through the same instructions with other reverse proxies such as Nginx, or Traefik.

Scenario: * You want to share a file such as a VM image or a ISO over the Internet, with HTTPS, directly from your laptop. * You have one or more websites or APIs running on-premises or within your home-lab and want to expose them on the Internet.

You can subscribe to inlets for personal or commercial use via Gumroad

Setup your exit node

Provision a cloud VM on DigitalOcean or another IaaS provider using inletsctl:

inletsctl create \
 --provider digitalocean \
 --region lon1 \
 --pro

Note the --url and TOKEN given to you in this step.

Setup your DNS A record

Setup a DNS A record for the site you want to expose using the public IP of the cloud VM

  • 178.128.40.109 = service.example.com

Run a local server to share files

Do not run this command in your home folder.

mkdir -p /tmp/shared/
cd /tmp/shared/

echo "Hello world" > WELCOME.txt

# If using Python 2.x
python -m SimpleHTTPServer

# Python 3.x
python3 -m http.server

This will listen on port 8000 by default.

Setup Caddy 1.x

Pick your operating system, for instance Darwin for MacOS, or Linux.

Download the binary, extract it and install it to /usr/local/bin:

mkdir -p /tmp/caddy
curl -sLSf https://github.com/caddyserver/caddy/releases/download/v1.0.4/caddy_v1.0.4_darwin_amd64.zip > caddy.tar.gz
tar -xvf caddy.tar.gz --strip-components=0 -C /tmp/caddy

sudo cp /tmp/caddy/caddy /usr/local/bin/
  • Create a Caddyfile

The Caddyfile configures which websites Caddy will expose, and which sites need a TLS certificate.

Replace service.example.com with your own domain.

Next, edit proxy / 127.0.0.1:8000 and change the port 8000 to the port of your local webserver, for instance 3000 or 8080. For our example, keep it as 8000.

service.example.com

proxy / 127.0.0.1:8000 {
  transparent
}

Start the Caddy binary, it will listen on port 80 and 443.

sudo ./caddy

If you have more than one website, you can add them to the Caddyfile on new lines.

You'll need to run caddy as sudo so that it can bind to ports 80, and 443 which require additional privileges.

Start the inlets-pro client on your local side

Downloads the inlets Pro client:

sudo inletsctl download

Run the inlets-pro client, using the TOKEN and IP given to you from the previous step.

The client will look for your license in $HOME/.inlets/LICENSE, but you can also use the --license/--license-file flag if you wish.

export IP=""        # take this from the exit-server
export TOKEN=""     # take this from the exit-server

inlets-pro tcp client \
  --url wss://$IP:8123/connect \
  --ports 80,443 \
  --token $TOKEN \
  --upstream localhost

Note that --upstream localhost will connect to Caddy running on your computer, if you are running Caddy on another machine, use its IP address here.

Check it all worked

You'll see that Caddy can now obtain a TLS certificate.

Go ahead and visit: https://service.example.com

Congratulations, you've now served a TLS certificate directly from your laptop. You can close caddy and open it again at a later date. Caddy will re-use the certificate it already obtained and it will be valid for 3 months. To renew, just keep Caddy running or open it again whenever you need it.

Setup Caddy 2.x

For Caddy 2.x, the Caddyfile format changes.

Let's say you're running a Node.js service on port 3000, and want to expose it with TLS on the domain "service.example.com":

git clone https://github.com/alexellis/expressjs-k8s/
cd expressjs-k8s

npm install
http_port=3000 npm start

The local site will be served at http://127.0.0.1:3000

{
  acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

service.example.com

reverse_proxy 127.0.0.1:3000 {
}

Note the acme_ca being used will receive a staging certificate, remove it to obtain a production TLS certificate.

Now download Caddy 2.x for your operating system.

sudo ./caddy run \
  -config ./Caddyfile

sudo - is required to bind to port 80 and 443, although you can potentially update your OS to allow binding to low ports without root access.

You should now be able to access the Node.js website via the https://service.example.com URL.

Caddy also supports multiple domains within the same file, so that you can expose multiple internal or private websites through the same tunnel.

{
  email "webmaster@example.com"
}

blog.example.com {
  reverse_proxy 127.0.0.1:4000
}

openfaas.example.com {
      reverse_proxy 127.0.0.1:8080
}

If you have services running on other machines you can change 127.0.0.1:8080 to a different IP address such as that of your Raspberry Pi if you had something like OpenFaaS running there.