- Run goku:
just runor:
go run ./cmd/goku- Open the apps:
- Public endpoint:
http://localhost:9000 - Admin panel:
http://localhost:9001
- (Optional) enable admin login:
GOKU_ADMIN_PASSWORD=my-secret just runWithout GOKU_ADMIN_PASSWORD, the admin UI is open (no logout button shown).
- Alias-based redirects with placeholder support (
{}and named placeholders) - Public and admin endpoints split by port (
:9000and:9001) - Live health JSON (
/healthz) on both ports and WebSocket stream (/ws/health) on public - Admin alias directory with:
- search
- sortable columns
- add / edit / delete
- enable / disable toggle
- clickable destination links
- clickable alias preview page with countdown redirect via public endpoint
- API key + optional password authentication for admin/API operations
- Config live-reload from disk
- Dashboard/API alias changes are written back to
config/config.yamlfor persistence - Prometheus metrics (
/metrics) on admin
Edit config/config.yaml:
aliases:
- alias: gh
destination: https://github.com
- alias: gh/{owner}/{repo}
destination: https://github.com/{owner}/{repo}
- alias: r/{subreddit}
destination: https://www.reddit.com/r/{subreddit}
- alias: yt/{}
destination: https://www.youtube.com/results?search_query={}Placeholder rules:
- Single placeholder aliases can use
{}. - Multiple placeholders must be uniquely named.
- Destination placeholders must be defined by the alias pattern.
go/ prefix note:
- Keep using
go/style links if that is your workflow (for examplehttp://go/ghorhttp://go/r/golang). - This assumes your DNS (or local host mapping) resolves
go(or a hostname likego.home.arpa) to your goku endpoint. - Without DNS/host routing, use the explicit server URL instead (for example
http://localhost:9000/gh).
Public (:9000):
| Method | Path | Description |
|---|---|---|
GET |
/ |
Public status page |
GET |
/{path...} |
Alias redirect |
GET |
/preview |
Alias redirect preview |
GET |
/healthz |
Health JSON |
GET |
/ws/health |
Health WebSocket stream |
Admin (:9001):
| Method | Path | Description |
|---|---|---|
GET |
/ |
Admin panel |
GET |
/login |
Login page (when password auth is enabled) |
POST |
/login |
Create admin session |
POST |
/logout |
Clear admin session |
GET |
/metrics |
Prometheus metrics |
GET |
/api/aliases |
List aliases |
POST |
/api/aliases |
Create/update alias |
POST |
/api/aliases/edit |
Edit alias |
POST |
/api/aliases/toggle |
Enable/disable alias |
POST |
/api/aliases/delete |
Delete alias |
POST |
/api/import |
Batch import aliases |
GET |
/api/broken-links |
Read unresolved paths seen by server |
| Variable | Default | Description |
|---|---|---|
GOKU_API_PORT |
9000 |
Public endpoint port |
GOKU_ADMIN_PORT |
9001 |
Admin endpoint port |
GOKU_WEB_PORT |
9001 |
Backward-compatible admin port fallback |
GOKU_CONFIG |
config/config.yaml |
Config file path |
GOKU_PUBLIC_BASE_URL |
(empty) | Absolute public base URL used for admin preview links |
GOKU_ADMIN_USERNAME |
admin |
Username for basic auth compatibility |
GOKU_ADMIN_PASSWORD |
(empty) | Enables login page + session auth for admin UI |
GOKU_API_KEY |
(generated/file) | Admin API bearer token |
If you want links like http://go/gh on your LAN, set up local name resolution and route that hostname to goku.
- Pick a local hostname
- Recommended:
go.home.arpaor another local domain you control. - You can use single-label
goif your LAN resolver supports it.
- Configure DNS (or hosts as a fallback)
- DNS: create an
A/AAAArecord for your chosen host pointing to the machine running goku or your reverse proxy. - Hosts fallback (per client machine):
# /etc/hosts (macOS/Linux)
192.168.1.50 go go.home.arpa
- Route traffic to goku public port (
:9000)
- If you run goku directly on the host, send HTTP traffic for
goto:9000. - If you use a reverse proxy, point that hostname to
http://127.0.0.1:9000.
Minimal examples:
go.home.arpa {
reverse_proxy 127.0.0.1:9000
}server {
listen 80;
server_name go.home.arpa;
location / {
proxy_pass http://127.0.0.1:9000;
}
}# Traefik labels (example)
traefik.http.routers.goku.rule=Host(`go.home.arpa`)
traefik.http.services.goku.loadbalancer.server.port=9000- Validate
- Open
http://go.home.arpa/gh(orhttp://go/ghif using single-label hostnames). - Run
curl -I http://go.home.arpa/ghand confirm a redirect response.
- When
GOKU_ADMIN_PASSWORDis set:- Admin UI requires login.
- API can use session, basic auth, or bearer key.
- When
GOKU_ADMIN_PASSWORDis empty:- Admin UI is open.
- Bearer key can still protect API endpoints when configured.
The API key is generated on first run and stored at config/.api_key if not supplied via GOKU_API_KEY.
just fmt
just test
just buildGoku arguably started as an itch I first scratched during an internship at Cisco, where I built an auto-correcting URL shortener and redirection tool for the intranet there. The first of its kind at the time, it was a massive hit among my peers. So much so that the idea stuck with me.
There have since been multiple solutions and iterations in my homelab including janky DNS scripts (rite of passage), some Traefik magic and a one-off Caddy config, but none satisfied the itch especially when faced with expanding scenarios like multi-level queries (e.g. t/TWS-4291/comments), so I embarked on rewriting the concept from scratch and in Go.
The name goku (悟空) is eternally recognizable for anyone familiar with DBZ and also means enlightenment through emptiness. Match made in heaven for this project.
Made with ♥ in NYC