I use nginx as a reverse-proxy for a side-project. It’s job is to sit between the user and the various back-end services. It’ll then serve the correct otherwise-inaccessible service depending on the URI or the port.

One of the hidden services is a minio storage. I use it to host multiple static websites with dynamic names. So I need to craft the correct nginx configuration to serve the right files depending on the requested URL.

There is a great deal of nginx documentation and many stack overflow pages regarding its configuration. But they all consider the domain-name to be some sort or logical root. This is not the case in this article and a simple trick allowed me to keep the configuration generic in term of bucket’s name and navigation’s depth.

The problem

Let’s see the initial issue here.

My side-project is a web front-end for an otherwise CLI1 based SSG2. At creation time, each website gets a dynamically-generated UUID3. This UUID is used to create a minio bucket in order to host the site’s static assets.

Once users are happy with their site’s content, they can hit the Generate button and then the Visit button. The first action will mix the database content and the static assets and generate the static website in a public directory at the bucket’s root. The second action simply opens a new browser tab to domain.name/UUID/.

So, the nginx configuration must extract the UUID part of the URI and redirect to minio’s /UUID/public/index.html file. But if the user navigates to domain.name/UUID/blog/, nginx should redirect to /UUID/public/blog/index.html. Let’s dive deeper: domain.name/UUID/blog/article/ should serve /UUID/public/blog/article/index.html. And see the invisible: pages load style sheets and static assets so domain.name/UUID/style.css should serve /UUID/public/style.css.

The solution

rewrite ^/([^/]+)/(.+)/$ /$1/public/$2/index.html break;
rewrite ^/([^/]+)/$ /$1/public/index.html break;
rewrite ^/([^/]+)/(.*)$ /$1/public/$2 break;

From bottom to top:

  • If the URI ends without a /, serve the file under the public directory.
  • If the URI ends with a / and has no path after the domain name, serve de index.html file.
  • Else, serve de index.html files under the trailing path with added public directory.

But why this post ?

It might seem a rather trivial problem to solve. So, why bother with a post ?

Well, simply because most if not all nginx documentation assume no path between the domain name and the actual file to serve. As a result, there is no mention of the first part of the three regular expressions ^/([^/]+)/. This is the magic part that allow one to separate the domain name $1 and the path $2 and make nginx behave the way I wanted.

1

Command Line Interface

2

Static Site Generator

3

Universaly Unique Identifier