Mar 19, 2026
If you have a domain name, you possess (ok, rent) your very own little corner of the internet. Congrats!
When you now publish a Go module as github.com/jo-m/mymodule, you hand over part of that control.
The module path is a permanent identifier, baked into every go.mod file that imports it.
That would now be tied to GitHub, a company that is actually Microsoft, which can change its terms, ban you, or simply stop existing.
If you ever want to move your code to another forge or just host it yourself, all your importers break.
But you can have your cake and eat it too: use your own domain as the module path, and set up a tiny redirect so go get still finds the code on GitHub (or wherever it actually lives today).
Your module becomes jo-m.ch/go/mymodule - an address you own.
How go get discovers code
#
When you run go get jo-m.ch/go/mymodule, the Go toolchain makes an HTTP request to:
https://jo-m.ch/go/mymodule?go-get=1
It expects an HTML page containing a <meta> tag like this:
<meta name="go-import" content="jo-m.ch/go/mymodule git https://github.com/jo-m/mymodule">
This tells Go where the actual Git repository lives. The module path in go.mod stays jo-m.ch/go/mymodule, but the code is fetched from GitHub.
Github does the same:
$ curl -s https://github.com/jo-m/podfather | grep '<meta name="go-import"'
<meta name="go-import" content="github.com/jo-m/podfather git https://github.com/jo-m/podfather.git">
Setting it up #
Here is a PHP script that does exactly that - drop it at your domain at /go/index.php.
Adapt DOMAIN, PREFIX_PATH, and REDIRECT_BASE to your setup.
<?php
/**
* Redirect `go get` requests to a Git forge.
*
* Example: To redirect from jo-m.ch/go/<package>?go-get=1 to github.com/jo-m/<package>, set
* DOMAIN: "jo-m.ch"
* PREFIX_PATH: "/go"
* REDIRECT_BASE: "https://github.com/jo-m/"
*/
define("DOMAIN", "jo-m.ch");
define("PREFIX_PATH", "/go");
define("REDIRECT_BASE", "https://github.com/jo-m/");
function err_quit()
{
http_response_code(400);
die();
}
if ($_GET['go-get'] != "1") err_quit();
// Strip prefix from path.
$req_path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = explode('/', trim($req_path, "/"));
$prefix = explode('/', trim(PREFIX_PATH, "/"));
while ($path[0] == $prefix[0]) {
array_shift($path);
array_shift($prefix);
}
$package = DOMAIN . "/" . trim(PREFIX_PATH, "/") . "/" . implode('/', $path);
$redirect = trim(REDIRECT_BASE, "/") . "/" . implode('/', $path);
?><!DOCTYPE html>
<html>
<head>
<meta name="go-import" content="<? echo $package; ?> git <? echo $redirect; ?>">
</head>
</html>
.htaccess:
RewriteEngine On
# Skip rewriting for the index.php file itself
RewriteCond %{REQUEST_URI} !/index\.php$
# Rewrite everything else to index.php
RewriteRule ^.*$ index.php [L]
Users can now import your package as jo-m.ch/go/mymodule, and go get will follow the redirect to GitHub transparently.