Tangible Bytes

A Web Developer’s Blog

Wildcard Proxy

I have a client who need to spin up webservers on demand to quickly test code and content, they use Docker to host these sites.

Currently they expose each site an a different port - which needs to be configured both within the container so that it can perform appropriate redirects, and by the user needing to get to the right site.

I’m automating the spin up process and wanted to make this a bit smoother.

I like to use wildcard DNS for ephemeral servers such as these.

A wildcard DNS record is a record in a DNS zone that will match requests for non-existent domain names.

A wildcard DNS record is specified by using a * as the leftmost label (part) of a domain name, e.g. *.example.com.

wikipedia

I just point this address at my Docker server and then any name like website1.testsites.example.com will resolve to my docker host.

I figured I’d spin up containers that can talk to each other by their short names (eg website1)

I thought a reverse proxy would be simple. What I wanted was a proxy I could connect to using the long name website1.testsites.example.com and have it fetch the requested pages from the Docker container with the matching short name eg website1.

I couldn’t get this to work with either Nginx or Apache (maybe there was a way - I just didn’t see it)

I’ve been programming in Go lately and I’ve been impressed with it so I decided to see if it could do what I wanted - turned out to be really simple

The whole things is only a few lines of code


func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {


	re := regexp.MustCompile(`^[a-z0-9_]+`)
	host := re.FindString(req.Host)
        url, _ := url.Parse("http://" + host)

	proxy := httputil.NewSingleHostReverseProxy(url)


	req.URL.Host = url.Host
	req.URL.Scheme = url.Scheme
	req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
	req.Host = url.Host

	proxy.ServeHTTP(res, req)
}

The result is that I can spin up any number of containers - both DNS and https encryption work via the wildcard.

So I spin up a container webserver1

Without having to change anything else and using any device on my network - I can now go to https://webserver1.testsites.example.com

and it Just Works

(see: how to get a valid local https certificate).