Using Caddy to create Virtual Hosts for your Multi-Domain Names as a Reverse-Proxy from a single server

Pratik Chowdhury
3 min readMay 21, 2023

--

While this particular technique should work on the internet, personally this article is for:-

  1. Making it work on a permanently air-gapped network
  2. Reverse Proxy without root privilige
  3. Installing without root privilige
  4. Single Domain but Reverse-Proxying to different servers

Advantages

  1. Host multiple domains from the same server
  2. Reverse Proxy to Multiple Domains hosted on different servers
  3. Reverse Proxy to Multiple Domains based on path provided
  4. Internal servers hosting our items need not be made public or even be accessible from the user’s machines.
  5. Host API and Server on different machines or ports but based on URI routes make it look like they are being hosted on the same server
    This could be by having a ui.company domain hosting the UI on localhost:8989 whil ui.company/api hosting the internal API server on 127.0.0.1:8787
  6. Do it using easy to read and understand Caddyfile.
  7. Do it securely without root unless you need to access priviliged ports

What is a Virtual Host?

  1. Traditional idea regarding domains and DNS is that a domain maps to an IP
  2. The HTTP and HTTPs protocol traditionally operate on priviliged port 80 and 443 respectively
  3. Hence, each and every domain needs to be hosted on a separate IP and machine
  4. Okay Point 3 is wrong
  5. Thanks to virtual hosts, we can do without that requirement by making our Caddyfile host all our domains on 1 IP itself

Installing

For me Caddy was pretty easy to install. All you really need to do is go here and download the Caddy release for your platform and extract it.

Simple Virtual Hosts Caddyfile

http://code.internal:8080 {
# Could be another domain/IP as well
reverse_proxy {
to localhost:8081
}
}

http://stage.internal:8080 {
# Could be another domain/IP as well
reverse_proxy 127.0.0.1:8082
}

http://dev.internal:8080 {
# Proxy with a DNS Server name instead
reverse_proxy internal-site:8083
}

No server setup for this kind of task would be complete without showcasing a way to host static files (to kinda make it easier to showcase the power of Caddy)

http://site.internal:8080 {
root * /home/caddy_test/internalweb
file_server
}

Using Curl to Validate

 curl --resolve dev.internal:8080:127.0.0.1 http://dev.internal:8080

Using Domains within Paths

You are probably thinking something like this would work:-

http://web.internal:8080 {
handle /code/* {
# Could be another domain/IP as well
reverse_proxy {
to localhost:8081
}
}
}

Nooo

If we use that approach then what we end up is a good old 404

The reason must be pretty obvious. Caddy currently redirects our code to localhost:8081/code/index.html which does not exist.

As we wish to redirect it to localhost:8081/index.html, instead of modifying our entire server to suit our requirements,

http://web.internal:8080 {
handle /code/* {
# Could be another domain/IP as well
uri strip_prefix /code/
reverse_proxy {
to localhost:8081
}
}
}

This leads to all the URLS prefixed with web.internal:8080/code to be redirected to localhost:8081

--

--