A minimal Go HTTP server that proxies HLS playlists and segments with:
- Robust playlist rewriting to local endpoints
- Automatic, domain-based upstream headers (via
templates.go) - Segment streaming with Range passthrough
- CORS support with allowlist
- No caching (no Cache-Control set or forwarded)
Directory: e:/do/serrver/no/proxy/go-proxy/
GET /proxy?url={m3u8_url}&headers={optional_headers}- Fetches an m3u8, rewrites child URLs to proxy endpoints, returns playlist.
GET /ts-proxy?url={segment_url}&headers={optional_headers}- Streams media segments (TS/MP4/etc), forwards key headers, supports Range.
GET /healthz→200 ok
url(required): Percent-encoded absolute URL to the upstream resource.headers(optional): Percent-encoded JSON object of extra headers to merge on top of auto-headers.
Example headers JSON:
{"referer":"https://example.com","origin":"https://example.com"}Encode with encodeURIComponent before sending in the query string.
File: templates.go
GenerateHeadersForDomain(rawURL, additionalHeaders)picks a template by domain (regex) and returns default headers merged withadditionalHeaders.- Used in both handlers and during playlist rewriting so each rewritten child link carries the correct headers for its own domain.
- You can add/modify templates by editing
domainTemplatesintemplates.go.
- Allowlist comes from
WHITELIST_DOMAINSenv (comma-separated). If*present, all origins allowed. - Preflight
OPTIONShandled automatically. - Exposed headers:
Content-Length, Content-Range, Content-Type, Accept-Ranges.
- The server does not set
Cache-Control, and does not forward upstreamCache-Control. - If you want to force-disable all caching, add
Cache-Control: no-storeto responses (not enabled by default).
- Go 1.20+
The server loads environment variables from a local .env file automatically.
- Prepare
.envine:/do/serrver/no/proxy/go-proxy/:
WHITELIST_DOMAINS="*"
PORT="3000"
- Install modules and run (PowerShell, run inside
go-proxy/):
go mod tidy
go run .Server logs:
Go proxy server running on http://localhost:3000
- Playlist:
GET http://localhost:3000/proxy?url={ENCODED_M3U8_URL}
- Playlist with extra headers:
GET http://localhost:3000/proxy?url={ENCODED_M3U8_URL}&headers={ENCODED_JSON}
- Segment (normally produced by rewritten playlists):
GET http://localhost:3000/ts-proxy?url={ENCODED_SEGMENT_URL}
Where ENCODED_JSON is encodeURIComponent(JSON.stringify({ referer: "https://example.com" })).
- Playlist rewriting:
#EXT-X-STREAM-INF→ next line rewritten to/proxywith per-link headers.#EXTINF→ next line rewritten to/ts-proxywith per-link headers.#EXT-X-MAP URI=...→ rewritten to/ts-proxywith per-link headers.#EXT-X-MEDIA URI=...→ rewritten to/proxywith per-link headers.
- Segment streaming:
- Forwards status code and headers:
Content-Type,Content-Length,Accept-Ranges,Content-Range. - Passes through
Rangefrom client.
- Forwards status code and headers:
- User-Agent:
- A browser-like UA is ensured if not provided by templates or
headersparam.
- A browser-like UA is ensured if not provided by templates or
- This is an open proxy for any URL. Consider adding an allowlist for target hostnames if needed.
- Only a subset of headers is recommended to be passed via
headersfor safety (e.g.,referer,origin,user-agent).
go build -o hls-proxy.exeRun the built binary:
./hls-proxy.exe- If upstream requests fail, check:
- The domain has a matching template in
templates.go. - The
headersJSON is valid and percent-encoded. - CORS origin allowed by
WHITELIST_DOMAINS.
- The domain has a matching template in
- Use
/healthzto verify server is running.