Content Pipes
Serve any raw file from your GitHub repo through a clean URL. Configuration files, manifests, templates, or anything else in your repository is accessible through your namespace.
Quick Start
Fetch your first file
Replace namespace, project, and path with your GitHub username/org, repo name, and file path.
curl -sSL easy-install.sh/acme/app/config.yaml > config.yaml
Deep Dive
How it works
When a user fetches easy-install.sh/acme/app/config.yaml, here is what happens:
-
Namespace resolution
The proxy parses the URL into namespace (
acme), project (app), and path (config.yaml). The namespace is validated against the allowlist. -
Branch lookup
The proxy resolves the default branch via the GitHub API and caches the result. The file is always fetched from the default branch.
-
Upstream fetch
The proxy fetches the file from GitHub's raw content endpoint and streams it directly to the client. No buffering in memory.
GET https://raw.githubusercontent.com/acme/app/main/config.yaml -
MIME type detection
The proxy guesses the correct
Content-Typefrom the file extension (e.g.application/jsonfor.json,text/yamlfor.yaml). If the extension is unrecognized, it falls back to the upstream header orapplication/octet-stream. -
Analytics recorded
An analytics event fires in the background (fire-and-forget). The download is never blocked by analytics. Content files are tracked separately from script files in your dashboard.
MIME Types
Content-Type handling
The proxy detects the correct MIME type from the file extension so downstream tools can parse the response correctly.
| Extension | Content-Type |
|---|---|
| .json | application/json |
| .yaml / .yml | text/yaml |
| .toml | text/toml |
| .xml | application/xml |
| .txt | text/plain |
| .md | text/markdown |
| .csv | text/csv |
| .env | text/plain |
| unknown | application/octet-stream (fallback) |
Detection
Scripts vs content
Content pipes and script forwarding use the same URL pattern and the same proxy. The only difference is how the hit is categorized in analytics:
| Category | Extensions |
|---|---|
| Script hits | Files ending in .sh, .bash, or .zsh |
| Content hits | All other file extensions |
Note
Both types appear separately in your analytics dashboard, so you can see how many users are downloading your install script vs your config files.
Headers
Response headers
The proxy sets the following headers on every response:
| Header | Value |
|---|---|
| Content-Type | MIME type guessed from file extension |
| Cache-Control | public, max-age=300 (5-minute cache) |
| X-Proxied-From | raw.githubusercontent.com (informational) |
Analytics
What gets tracked
Each content download records the following anonymous metadata. No personal information is collected.
| Field | Description |
|---|---|
| Namespace | GitHub user or org |
| Project | Repository name |
| File Path | Which file was downloaded |
| Hit Type | "content" for non-script files |
| Client Tool | Detected from User-Agent (curl, wget, browser, etc.) |
| Client Version | Version string extracted from User-Agent |
| Timestamp | When the download occurred (UTC) |
| Country | Derived from IP via geo lookup |
Note
IP addresses are hashed with a one-way SHA-256 function and never stored in plaintext. Analytics are fully anonymous.
Examples
Common usage
Download a config file
curl -sSL easy-install.sh/acme/app/config.yaml > config.yaml
Pipe JSON into jq
curl -sSL easy-install.sh/acme/app/defaults.json | jq '.database'
Fetch a Docker Compose file
curl -sSL easy-install.sh/acme/app/docker-compose.yml > docker-compose.yml
docker compose up -d
Fetch a Kubernetes manifest
curl -sSL easy-install.sh/acme/app/k8s/deployment.yaml | kubectl apply -f -
Use with wget
wget -qO config.toml easy-install.sh/acme/app/config.toml
Nested paths
curl -sSL easy-install.sh/acme/templates/envs/.env.production > .env
HEAD request to check availability
curl -I easy-install.sh/acme/app/config.yaml
Returns headers only (no body). Useful for checking file existence or content type before downloading.
Limitations
Current limitations
Public repos only
easy-install.sh can only proxy files from public GitHub repositories. Private repos require authentication that the proxy cannot forward.
Default branch only
Files are always fetched from the repository's default branch. There is no way to specify a tag, branch, or commit hash in the URL yet.
Extension-based detection
Content type detection relies on file extensions, not file contents. If your file has no extension or an unusual one, the proxy falls back to application/octet-stream.
5-minute cache
Responses are cached for 5 minutes. After pushing changes, it may take up to 5 minutes for the proxy to serve the updated file.