Goku admin panel showing golink aliases, destinations, and health checks

Update — October 7, 2026: Goku is here

The custom go-links service I wanted at the end of this post now exists: Goku. I built and released it as an open-source, self-hosted application written in Go.

Instead of editing Traefik redirect rules for every exception, I can manage aliases and destination templates in a web UI. Goku supports exact aliases, named placeholders, and placeholder defaults, with configuration stored in YAML. Public redirects and the admin UI run on separate ports.

The README has setup instructions, and releases are available on GitHub. The DNS setup still matters: go needs to resolve to the server or reverse proxy running Goku.

The Traefik approach below is where this started. The final section explains what became Goku and what remains on the wishlist.

The Problem

Typing full URLs gets tedious. status.example.com is a mouthful when you just want to check your dashboard. What if you could just type go/status in your browser and instantly get there?

Go links (also known as “go/” shortcuts) have been a staple at companies like Google for years. The concept is simple:

  • Type go/something in your browser
  • Get redirected to https://something.example.com

This is typically achieved through DNS search domains combined with HTTP redirects.

I helped develop a "Smartlink" solution during my time at Cisco to implement go-links with auto-correction in the intranet.

How It Works

The magic happens in two parts:

1. DNS Search Domain

Configure your LAN to use a search domain example.com. When you type go/status in your browser:

  • Your browser searches for go.example.com
  • DNS resolves go.example.com to your Traefik instance
  • Request arrives: http://go.example.com/status

2. Traefik Path-Based Redirects

Traefik intercepts the request and applies custom middleware to parse the path and construct a new URL:

  • $1 = subdomain (extracted from path)
  • $2 = subpath on destination (optional trailing path)

For example:

  • go/status → https://status.example.com
  • go/grafana/dashboards → https://grafana.example.com/dashboards

Flow Diagram

sequenceDiagram
  participant Browser
  participant DNS
  participant Traefik
  participant Destination

  Browser->>Browser: User types "go/status"
  Browser->>DNS: Lookup "go.example.com"
  DNS-->>Browser: Returns Traefik IP
  Browser->>Traefik: GET http://go.example.com/status
  Traefik->>Traefik: Parse path: $1="status", $2=""
  Traefik->>Traefik: Construct: https://status.example.com
  Traefik-->>Browser: 302 Redirect to https://status.example.com
  Browser->>Destination: GET https://status.example.com
  Destination-->>Browser: Return page

Implementation

Step 1: DNS Configuration

Here is relevant code snippet for my AdGuard Home configuration:

filtering:
...
rewrites:
  - domain: 'go.example.com'
    answer: '192.168.0.2'
  - domain: 'go'
    answer: 'go.example.com'

Step 2: Traefik Middleware

http:
  middlewares:
    go-slug:
      redirectRegex:
        permanent: false
        regex: "^https?://go(?:\\.example\\.com)?/([^/?#]+)(.*)$"
        replacement: 'https://$1.example.com$2'
  routers:
    go:
      entryPoints:
        - web
        - websecure
      middlewares:
        - go-slug
      priority: 100
      rule: 'Host(`go`) || Host(`go.example.com`)'
      service: 'noop'
  services:
    noop:
      loadBalancer:
        servers:
          - url: 'http://127.0.0.1:65535'

Step 3: Common Shortcuts

Now instead of typing full URLs or bookmarking everything, you can simply:

  • Type go/status → https://status.example.com
  • Type go/grafana → https://grafana.example.com

Clean, fast, and elegant.

Beyond simple redirects

While the original implementation works great for internal services following the subdomain.example.com pattern, there are cases where you need more flexibility:

The Limitation

Not every shortcut fits the pattern. For example:

  • go/google → https://google.com (external site)
  • go/docs/k8s → https://kubernetes.io/docs (custom mapping)
  • go/gh/jovalle → https://github.com/jovalle (specific profile)
  • go/technis/pull/24 → https://github.com/jovalle/technis/pull/24 (parameterized)

These don’t map to *.example.com subdomains and require custom rules.

The Solution: Goku

Goku is the dedicated go-links application I built to handle these cases. Traefik can route the go hostname to Goku’s public endpoint on port 9000; the admin UI and API live on port 9001.

An alias such as gh/{owner}/{repo} can resolve to https://github.com/{owner}/{repo}. The destination is explicit, so a shortcut can point to an external site just as easily as an internal service:

flowchart LR
    A[Browser: go/google] --> B{Traefik}
    B --> C[Goku: resolve alias]
    C --> D[Match exact alias or placeholder pattern]
    D --> E[Expand destination template]
    E --> F[Redirect to destination]

What shipped

  • Exact aliases and placeholder patterns, including named placeholders and defaults.
  • An admin UI to search, sort, add, edit, delete, enable, disable, and preview golinks.
  • A YAML configuration file that reloads from disk and persists admin/API changes.
  • Optional admin login, with session, basic, and bearer authentication for admin/API requests.
  • Health endpoints and Prometheus metrics.

Still on the wishlist

The original roadmap went further than the released application. Per-link expiration, team-specific access rules, redirect analytics, and A/B testing remain ideas rather than shipped features.

Alternatives

There are browser extensions (Golinks and Trotto) that accomplish must of the same thing but require manually adding links. There’s also Tailscale’s golink but only works within a tailnet and still needs to be manually populated.

References