https://github.com/taigrr/toga
Drop-in replacement for Athens Go module proxy, powered by goproxy
https://github.com/taigrr/toga
Last synced: 18 days ago
JSON representation
Drop-in replacement for Athens Go module proxy, powered by goproxy
- Host: GitHub
- URL: https://github.com/taigrr/toga
- Owner: taigrr
- License: 0bsd
- Created: 2026-03-01T19:58:07.000Z (4 months ago)
- Default Branch: master
- Last Pushed: 2026-04-15T01:34:32.000Z (2 months ago)
- Last Synced: 2026-04-15T03:22:46.272Z (2 months ago)
- Language: Go
- Size: 6.9 MB
- Stars: 3
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
Toga
A modern Go module proxy — drop-in replacement for Athens
---
Toga is a Go module proxy powered by [goproxy](https://github.com/goproxy/goproxy). It correctly handles vanity imports, `gopkg.in` redirects, and the full `GOPROXY` protocol by delegating module fetching to goproxy's `GoFetcher`, which uses the Go toolchain directly.
Toga maintains Athens-compatible storage layouts — point it at your existing S3/GCS/MinIO/Azure bucket and it just works.
## Why Toga?
Athens has a [long-standing bug](https://github.com/gomods/athens/issues/2029) where vanity import URLs don't resolve correctly, and the project is no longer actively maintained. Toga fixes this while keeping full compatibility with your existing Athens storage.
## Features
- **Athens-compatible storage** — works with your existing module cache, no data migration
- **Vanity import support** — correctly resolves vanity URLs and `gopkg.in` redirects
- **5 storage backends** — Disk, S3, MinIO, GCS, Azure Blob
- **Web UI** — browse cached modules with syntax-highlighted `go.mod` previews
- **Health endpoints** — `/healthz` and `/readyz` for orchestration
- **TLS & basic auth** — production-ready out of the box
- **Network modes** — `fallback` (default), `strict` (cache-only misses error), `offline` (no upstream)
- **Single binary** — no dependencies, no database
## Quick Start
### Binary
```bash
# Install
go install github.com/taigrr/toga/cmd/toga@latest
# Run with disk storage (default)
toga
# Point Go at it
go env -w GOPROXY=http://localhost:6060,direct
```
### Docker
```bash
docker run -p 6060:6060 ghcr.io/taigrr/toga
```
### With S3
```bash
TOGA_STORAGE_TYPE=s3 \
TOGA_S3_REGION=us-east-1 \
TOGA_S3_BUCKET=my-go-modules \
toga
```
## Storage Backends
| Backend | `TOGA_STORAGE_TYPE` | Athens Compatible |
| ---------- | ------------------- | :---------------: |
| Disk | `disk` | Yes |
| S3 | `s3` | Yes |
| MinIO | `minio` | Yes |
| GCS | `gcs` | Yes |
| Azure Blob | `azureblob` | Yes |
## Configuration
Toga is configured with environment variables (prefix `TOGA_`) or a config file (`toga.toml`, `toga.yaml`, `toga.json`).
### Server
| Variable | Default | Description |
| ----------------------- | ---------- | -------------------------------------------- |
| `TOGA_PORT` | `:6060` | Listen address |
| `TOGA_UNIX_SOCKET` | | Unix socket path (overrides port) |
| `TOGA_TIMEOUT` | `300s` | Request timeout |
| `TOGA_SHUTDOWN_TIMEOUT` | `30s` | Graceful shutdown timeout |
| `TOGA_PATH_PREFIX` | | URL path prefix |
| `TOGA_LOG_LEVEL` | `info` | Log level (`debug`, `info`, `warn`, `error`) |
| `TOGA_NETWORK_MODE` | `fallback` | `fallback`, `strict`, or `offline` |
| `TOGA_GO_BINARY` | `go` | Path to Go binary |
| `TOGA_SUM_DBS` | | Comma-separated sum DBs to proxy |
### TLS & Auth
| Variable | Description |
| ---------------------- | -------------------- |
| `TOGA_TLS_CERT` | TLS certificate file |
| `TOGA_TLS_KEY` | TLS key file |
| `TOGA_BASIC_AUTH_USER` | Basic auth username |
| `TOGA_BASIC_AUTH_PASS` | Basic auth password |
### Storage: Disk
| Variable | Default | Description |
| --------------------- | ------------------- | ----------------- |
| `TOGA_DISK_ROOT_PATH` | `/tmp/toga-storage` | Storage directory |
### Storage: S3
| Variable | Description |
| -------------------------- | --------------------------- |
| `TOGA_S3_REGION` | AWS region |
| `TOGA_S3_BUCKET` | Bucket name |
| `TOGA_S3_KEY` | Access key ID |
| `TOGA_S3_SECRET` | Secret access key |
| `TOGA_S3_TOKEN` | Session token |
| `TOGA_S3_ENDPOINT` | S3-compatible endpoint |
| `TOGA_S3_FORCE_PATH_STYLE` | Path-style access (`false`) |
### Storage: MinIO
| Variable | Description |
| ----------------------- | -------------------- |
| `TOGA_MINIO_ENDPOINT` | MinIO endpoint |
| `TOGA_MINIO_KEY` | Access key |
| `TOGA_MINIO_SECRET` | Secret key |
| `TOGA_MINIO_BUCKET` | Bucket name |
| `TOGA_MINIO_REGION` | Region |
| `TOGA_MINIO_ENABLE_SSL` | Enable SSL (`false`) |
### Storage: GCS
| Variable | Description |
| --------------------------- | ------------------------- |
| `TOGA_GCS_BUCKET` | Bucket name |
| `TOGA_GCS_PROJECT_ID` | GCP project ID |
| `TOGA_GCS_CREDENTIALS_FILE` | Service account JSON path |
### Storage: Azure Blob
| Variable | Description |
| ------------------------------- | -------------------- |
| `TOGA_AZUREBLOB_ACCOUNT_NAME` | Storage account name |
| `TOGA_AZUREBLOB_ACCOUNT_KEY` | Storage account key |
| `TOGA_AZUREBLOB_CONTAINER_NAME` | Container name |
## API Endpoints
| Endpoint | Description |
| --------------------------------- | --------------------- |
| `GET /healthz` | Liveness probe |
| `GET /readyz` | Readiness probe |
| `GET //@v/list` | List versions |
| `GET //@v/.info` | Version metadata |
| `GET //@v/.mod` | `go.mod` file |
| `GET //@v/.zip` | Module source archive |
## Running as a Service
### Linux (systemd user service)
Create `~/.config/systemd/user/toga.service`:
```ini
[Unit]
Description=Toga Go Module Proxy
After=network.target
[Service]
Type=simple
ExecStart=%h/go/bin/toga
Environment="TOGA_PORT=:6060"
Environment="TOGA_STORAGE_TYPE=disk"
Environment="TOGA_DISK_ROOT_PATH=%h/.cache/toga"
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
```
```bash
# Reload, enable, start
systemctl --user daemon-reload
systemctl --user enable toga
systemctl --user start toga
# Enable lingering (keeps service running after logout)
loginctl enable-linger $USER
# Check status
systemctl --user status toga
journalctl --user -u toga -f
```
### macOS (launchd)
Create `~/Library/LaunchAgents/com.taigrr.toga.plist`:
```xml
Label
com.taigrr.toga
ProgramArguments
/path/to/toga
EnvironmentVariables
TOGA_PORT
:6060
TOGA_STORAGE_TYPE
disk
TOGA_DISK_ROOT_PATH
/path/to/storage
RunAtLoad
KeepAlive
StandardOutPath
/tmp/toga.log
StandardErrorPath
/tmp/toga.err
```
```bash
# Load and start
launchctl load ~/Library/LaunchAgents/com.taigrr.toga.plist
# Unload
launchctl unload ~/Library/LaunchAgents/com.taigrr.toga.plist
# Check status
launchctl list | grep toga
```
## Migrating from Athens
Toga reads Athens storage layouts directly — no data migration required. See the full **[Migration Guide](docs/MIGRATION_GUIDE.md)** for step-by-step instructions.
The short version:
1. Keep your existing storage bucket
2. Rename `ATHENS_*` env vars to `TOGA_*` equivalents
3. Swap the container image
## License
[0BSD](LICENSE)