Golang Vanity URLs in nginx

in   code   ,

Go has a nice way of importing packages, just use go get and it automatically appears in your $GOPATH/src directory. The backing store can be any supported VCS, but most often is GitHub. This means that your custom package will be namespaced under github.com/<user>/package. Wouldn’t it be nice if you could just namespace it similar to rsc.io/quote?

The way go get works is that it has special cases for handling Github, Bitbucket and a few other VCS providers, but if it cannot match any of the known providers, it attempts a HTTPS request to the given URL with ?go-get=1 appended to the request. The server recognizes this special request and responds with a meta tag telling Go where to find this. The tag is of the following form:

<meta name="go-import" content="rsc.io/quote git https://github.com/rsc/quote.git">

The first part of the content (rsc.io/quote) tells Go where to namespace this package under $GOPATH/src. The rest of the content is the VCS type, followed by the URL to the actual source repository.

By allowing this model, the owner of the package can change the location of the source repository at any time, while still keeping the vanity import.

With nginx, this is actually super easy. I have namespaced all my Go modules (few they may be) under nirenjan.org. For example, if you run go get nirenjan.org/posix, you will end up with the source code under $GOPATH/src/nirenjan.org/posix, rather than $GOPATH/src/git.nirenjan.org/go/posix.

location ~ /([A-Za-z0-9_-]+)(/[A-Za-z0-9_.-]+)*$ {
    if ($args = "go-get=1") {
        add_header Content-Type text/html
        response 200 '<meta name="go-import" content="$host/$1 git https://git.nirenjan.org/go/$1.git">';
    }

    return 302 https://git.nirenjan.org/go/$1;
}

The overall idea is that all my packages would be at the root level under nirenjan.org, while any bump in the major versions would have the trailing /vX. The nginx config snippet above maps the root level to the actual Git repository, and ignores any trailing suffix.

The only drawback is that it will match any URL, so even non-existent modules get mapped. That said, it doesn’t really matter, since this is a non-existent module, the clone step would fail.