Self-host Go vanity imports on Cloudflare Workers for free
A lightweight Go vanity import path server built with Hono that supports both Cloudflare Workers and container-based deployments.
Transform github.com/yourorg/really-long-repo-name into clean imports like go.yourdomain.com/pkg β while maintaining full control over your packages and paying nothing for hosting on Cloudflare's free tier.
- Features
- Why This Project?
- Prerequisites
- Quick Start
- Installation
- Configuration
- Development
- Deployment
- Testing
- How It Works
- Project Structure
- License
- Contributing
- Custom Go vanity import paths with automatic pkg.go.dev integration
- Responsive web interface listing all packages
- Dark/light theme support with localStorage persistence
- Built with Hono for edge performance
- Multiple deployment options:
- Cloudflare Workers for global edge distribution
- Docker containers for self-hosted deployments
- Tailwind CSS styling
Unlike self-hosted solutions that require a VPS or alternatives that need paid infrastructure, go-vanity-pkg runs on Cloudflare Workers' free tier (100,000 requests/day). Deploy globally across 300+ edge locations with zero hosting costs and sub-50ms response times worldwide.
Just a single config.json file β no database, no complex setup. Compare to alternatives:
| Solution | Setup Complexity | Hosting Cost | Performance |
|---|---|---|---|
| go-vanity-pkg | Single JSON file | $0 (CF free tier) | Global edge (< 50ms) |
| nginx + VPS | nginx config, server management | ~$5-20/month | Single region |
| uber-go/sally | host setup | VPS required | Depends on hosting |
| Google Cloud Run | Container + Cloud config | Pay per request | Regional |
- Beautiful web UI with dark/light theme for browsing your packages
- Flexible deployment β Cloudflare Workers for edge hosting OR Docker for self-hosted control
- TypeScript-first β full type safety with modern tooling (Hono + Bun)
This project powers package imports for several Go projects in production:
// Instead of:
import "github.com/pixelfactory-go/some-internal-package"
// Use clean imports:
import "go.pixelfactory.io/pkg/server"
import "go.pixelfactory.io/pkg/logger"Benefits:
- Brand consistency β All your packages under your domain
- Migration flexibility β Move repos without breaking imports (change config, not code)
- Clean appearance β Clean import paths for public APIs
- Zero downtime β Global edge distribution with automatic failover
Development:
- Bun v1.0 or later - 3x faster, native TypeScript support
Deployment:
- Cloudflare Workers: Cloudflare account and Wrangler CLI
- Docker: Docker and Docker Compose (optional)
Get up and running in under 2 minutes:
# 1. Clone and install
git clone https://github.com/pixelfactory-go/go-vanity-pkg.git
cd go-vanity-pkg
bun install
# 2. Configure your packages
cp config.example.json config.json
# Edit config.json with your domain and packages
# 3. Deploy to Cloudflare Workers (free tier)
bunx wrangler login
bun run deployThat's it! Your vanity imports are now live on Cloudflare's global edge network.
bun install- Configure your domain in
config.json:
{
"godoc": "pkg.go.dev",
"url": "go.yourdomain.com",
"pkgs": [
{
"name": "pkg/server",
"repo": "github.com/yourorg/server"
},
{
"name": "pkg/logger",
"repo": "github.com/yourorg/logger"
}
]
}-
DNS Configuration: Point your domain to your Cloudflare Worker
- Add a DNS record (A, AAAA, or CNAME) for your vanity domain
- Configure it as a route in your Cloudflare Worker settings
-
Update wrangler.toml if needed to add custom routes or domains
The configuration is loaded from config.json in the project root. This JSON file is:
- Bundled at build time for Cloudflare Workers (via direct JSON import)
- Loaded at runtime in Docker containers (with optional CONFIG_PATH override)
Each package in the pkgs array supports the following options:
name: Path segment after your domain- Example:
"pkg/server"createsgo.yourdomain.com/pkg/server
- Example:
repo: Actual repository location- Example:
"github.com/yourorg/server"
- Example:
url: Override the global vanity domain for this package- Default: Uses the global
urlvalue
- Default: Uses the global
godoc: Override the documentation host- Default: Uses the global
godocvalue (typically "pkg.go.dev")
- Default: Uses the global
vcs: Version control system- Default:
"git" - Options:
"git","hg","svn","bzr"
- Default:
description: Package description displayed on the web interfacemodulePath: Full import path- Default: Auto-generated as
${url}/${name}
- Default: Auto-generated as
docBadge: Documentation badge URL- Default: Auto-generated as
//pkg.go.dev/badge/${modulePath}.svg
- Default: Auto-generated as
{
"godoc": "pkg.go.dev",
"url": "go.example.com",
"pkgs": [
{
"name": "pkg/http",
"repo": "github.com/example/http-server",
"description": "HTTP server utilities"
},
{
"name": "tools/cli",
"repo": "github.com/example/cli-tools",
"vcs": "git",
"description": "Command-line tools"
}
]
}This configuration allows users to import packages as:
import "go.example.com/pkg/http"
import "go.example.com/tools/cli"The configuration in config.json is automatically bundled at build/deploy time. Simply edit config.json and run:
bun run deployImportant: The pre-built Docker images contain only a placeholder config. You must provide your own config.json file.
Option 1: Use pre-built image with custom config (Recommended)
# Create your custom config file
cat > my-config.json << 'EOF'
{
"godoc": "pkg.go.dev",
"url": "go.yourdomain.com",
"pkgs": [
{
"name": "pkg/server",
"repo": "github.com/yourorg/server"
}
]
}
EOF
# Run with CONFIG_PATH environment variable
docker run -d \
-p 3000:3000 \
-e CONFIG_PATH=/config/config.json \
-v $(pwd)/my-config.json:/config/config.json:ro \
ghcr.io/pixelfactory-go/go-vanity-pkg:latestOption 2: Build custom image
# Copy the example config and edit it
cp config.example.json config.json
# Edit config.json with your settings
vim config.json
# Build the image
docker build -t my-vanity-pkg .
docker run -d -p 3000:3000 my-vanity-pkgNote: The Dockerfile copies config.example.json as the default config to prevent leaking the repository's internal configuration.
Start the development server with hot reload using Bun:
bun run devThis will:
- Build CSS from Tailwind
- Build JavaScript theme toggle
- Start Bun development server with hot reload
- Enable native TypeScript execution
The server will be available at http://localhost:3000
Why Bun?
- π¦ Native TypeScript support (no compilation needed)
- π₯ Built-in hot reload
- πΎ Smaller memory footprint
- β Drop-in replacement for Node.js/npm
To test with the CloudFlare Workers runtime:
bun run dev:cfThe server will be available at http://localhost:8787
This uses Wrangler to simulate the CloudFlare Workers environment locally.
Primary (Bun):
bun run dev- Start Bun development server with hot reload (fastest)bun start- Start production serverbun run deploy- Deploy to Cloudflare Workersbun test- Run testsbun run coverage- Run tests with coverage
CloudFlare Workers:
bun run dev:cf- Start Cloudflare Workers dev serverbun run deploy- Deploy to Cloudflare Workersbun run cf-typegen- Generate TypeScript types (run after changing wrangler.toml)
Build:
bun run build- Build the projectbun run css:build- Build CSS from Tailwindbun run css:watch- Watch and build CSSbun run js:build- Build JavaScript modules
Deploy to CloudFlare's global edge network for ultra-low latency worldwide.
-
Log in to Cloudflare:
bunx wrangler login
-
Configure your domain in Cloudflare DNS to point to your Worker
bun run deployThis command will:
- Build all assets (CSS, JS) using Bun
- Deploy to Cloudflare Workers with minification
- Distribute globally across 300+ edge locations
Note: CloudFlare Workers run on their own V8 runtime. Wrangler bundles your code and deploys it - the local runtime (Bun/Node) doesn't affect CloudFlare Workers deployment.
Docker images use Bun runtime for optimal performance:
- Native TypeScript support - No compilation or transpilation needed
- 3x faster than Node.js for most workloads
- Smaller image size - ~90MB vs ~180MB with Node.js
- Drop-in replacement - Works with existing Hono/Node.js code
Pre-built Docker images are automatically published to GitHub Container Registry on every release:
docker pull ghcr.io/pixelfactory-go/go-vanity-pkg:latest
docker run -d -p 3000:3000 ghcr.io/pixelfactory-go/go-vanity-pkg:latestAvailable tags:
latest- Latest stable releasemain- Latest commit on main branchv*- Specific version tags (e.g.,v1.0.0)sha-*- Specific commit SHA
-
Build and start the container:
docker-compose up -d
-
View logs:
docker-compose logs -f
-
Stop the container:
docker-compose down
The server will be available at http://localhost:3000 by default. You can customize the port by setting the PORT environment variable:
PORT=8080 docker-compose up -d-
Build the image:
docker build -t go-vanity-pkg . -
Run the container:
docker run -d \ --name go-vanity-pkg \ -p 3000:3000 \ -e NODE_ENV=production \ go-vanity-pkg:latest
-
View logs:
docker logs -f go-vanity-pkg
-
Stop the container:
docker stop go-vanity-pkg docker rm go-vanity-pkg
For production deployments, you can:
-
Push to a container registry:
docker tag go-vanity-pkg:latest your-registry.com/go-vanity-pkg:latest docker push your-registry.com/go-vanity-pkg:latest
-
Deploy to container orchestration platforms:
- Kubernetes
- Docker Swarm
- Amazon ECS
- Google Cloud Run
- Azure Container Instances
-
Configure reverse proxy (nginx, Caddy, Traefik) for:
- SSL/TLS termination
- Domain routing
- Load balancing
Run the test suite:
npm testRun with coverage:
npm run coverage- When a user runs
go get go.pixelfactory.io/pkg/server, Go tooling makes an HTTP request with?go-get=1 - The server responds with HTML containing meta tags that point to the actual repository
- Go tooling uses this information to clone the correct repository
- Regular browser requests show a user-friendly web interface listing all packages
.
βββ src/
β βββ index.tsx # Main application entry point
β βββ config.ts # Configuration loader and type definitions
β βββ pages/ # Page components
β βββ components/ # Reusable components
β βββ styles/ # Tailwind CSS
βββ public/ # Static assets
βββ test/ # Test files
βββ scripts/ # Build scripts
βββ config.json # Package configuration (JSON)
βββ config.example.json # Example config (used in Docker builds)
βββ wrangler.toml # Cloudflare Workers config
βββ package.json # Dependencies and scripts
See LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.