Created
February 20, 2026 14:07
-
-
Save svandragt/949e01096573a583bda7a97751857cff to your computer and use it in GitHub Desktop.
Ollama Proxy Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| from typing import Dict | |
| import httpx | |
| from fastapi import FastAPI, Request, Response | |
| from fastapi.middleware.cors import CORSMiddleware | |
| OLLAMA_BASE = os.getenv("OLLAMA_BASE", "http://127.0.0.1:11434") | |
| ALLOWED_ORIGINS = [ | |
| "https://workledger.org", | |
| ] | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=ALLOWED_ORIGINS, | |
| allow_credentials=False, | |
| allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], | |
| allow_headers=["*"], | |
| ) | |
| client = httpx.AsyncClient(timeout=60.0) | |
| HOP_BY_HOP = { | |
| "connection", | |
| "keep-alive", | |
| "proxy-authenticate", | |
| "proxy-authorization", | |
| "te", | |
| "trailer", | |
| "transfer-encoding", | |
| "upgrade", | |
| } | |
| def _filtered_headers(headers: Dict[str, str]) -> Dict[str, str]: | |
| out: Dict[str, str] = {} | |
| for k, v in headers.items(): | |
| lk = k.lower() | |
| if lk in HOP_BY_HOP: | |
| continue | |
| if lk in {"host", "origin", "content-length"}: | |
| continue | |
| out[k] = v | |
| return out | |
| @app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) | |
| async def proxy(path: str, request: Request) -> Response: | |
| url = f"{OLLAMA_BASE}/{path}" | |
| body = await request.body() | |
| upstream = await client.request( | |
| method=request.method, | |
| url=url, | |
| params=request.query_params, | |
| content=body if body else None, | |
| headers=_filtered_headers(dict(request.headers)), | |
| ) | |
| resp_headers = {k: v for k, v in upstream.headers.items() if k.lower() not in HOP_BY_HOP} | |
| return Response( | |
| content=upstream.content, | |
| status_code=upstream.status_code, | |
| headers=resp_headers, | |
| media_type=upstream.headers.get("content-type"), | |
| ) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you’re seeing Missing CORS origin because the webapp is a different origin from localhost, and Ollama isn’t sending Access-Control-Allow-Origin for it.
Even with CORS fixed, you may also need to address HTTPS→HTTP restrictions and preflight behavior.
The robust solution is usually a local bridge/proxy that explicitly authorizes the webapp and mediates access to Ollama.
Run
uv run --with fastapi --with "uvicorn[standard]" --with httpx \ uvicorn ollama_proxy:app --host 127.0.0.1 --port 8008.Set the Ollama base URL / host to:
http://127.0.0.1:8008. Now when it calls:/api/tagsit will hit the proxy and get forwarded to:http://127.0.0.1:11434/api/tags