HTTP/1.1 403 Forbidden with an empty body from Ollama, for a request that carries an Origin header, means the web page's origin is not on Ollama's allow list. Add that origin to the OLLAMA_ORIGINS environment variable and restart the Ollama server; nothing else about the request is wrong.

The value must match scheme, host and port exactly. List several with commas, and write http://app.example.test:* to allow every port of one host.

The error

PS> curl.exe -s -i http://127.0.0.1:15101/api/tags -H "Origin: http://app.example.test"
HTTP/1.1 403 Forbidden
Date: Fri, 30 Oct 2026 02:59:38 GMT
Content-Length: 0
PS> curl.exe -s -i -X OPTIONS http://127.0.0.1:15101/api/chat -H "Origin: http://app.example.test" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type"
HTTP/1.1 403 Forbidden
Allow: POST
Date: Fri, 30 Oct 2026 02:59:38 GMT
Content-Length: 0

Why it happens

A browser adds an Origin header to every request a page makes to another origin, and before a POST with a JSON body it first sends an OPTIONS preflight like the second one above. Ollama compares the header with its list and answers 403 when it does not match. A request with no Origin at all, from curl, a backend service or the CLI, is not checked, which is why the same call works in a terminal and fails in the page. The 403 carries no Access-Control-Allow-Origin header, so the page's script cannot read anything back.

Ollama's FAQ says: "Ollama allows cross-origin requests from 127.0.0.1 and 0.0.0.0 by default." (docs.ollama.com/faq, re-read on Oct 30, 2026). The server's own config line was broader: localhost, 127.0.0.1 and 0.0.0.0 over http and https on any port, plus the app://, file://, tauri:// and two VS Code schemes. That is why a dev server on http://localhost:5173 worked in the same test while http://app.example.test did not.

The fix

PS> $env:OLLAMA_ORIGINS = "http://app.example.test"
PS> Select-String -Path .\serve-e.err.txt -Pattern 'OLLAMA_ORIGINS:\[[^\]]*\]' | Select-Object -First 1 | ForEach-Object { $_.Matches[0].Value }
OLLAMA_ORIGINS:[http://app.example.test http://localhost https://localhost ...]
PS> curl.exe -s -i -X OPTIONS http://127.0.0.1:15101/api/chat -H "Origin: http://app.example.test" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type"
HTTP/1.1 204 No Content
Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS
Access-Control-Allow-Origin: http://app.example.test
Access-Control-Max-Age: 43200
PS> curl.exe -s -i http://127.0.0.1:15101/api/chat -H "Origin: http://app.example.test" -H "Content-Type: application/json" -d "@chat-ok.json"
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://app.example.test

Between the first two lines the test started ollama serve in the background from the same session, and the server's config line then showed the new list. Your origin is added in front of the defaults, it does not replace them. With only http://app.example.test listed, https://app.example.test and http://app.example.test:8080 still got 403; adding http://app.example.test:* and the https form fixed both. OLLAMA_ORIGINS="*" also worked, answering Access-Control-Allow-Origin: * for a made-up site, which means any web page you open could call your local models; list real origins instead.

For the installed app, the FAQ's Windows steps are: quit Ollama from the taskbar, add the variable for your account under "environment variables", and start Ollama again from the Start menu; on Linux, add an Environment= line with systemctl edit ollama.service, reload systemd and restart the service. To confirm what the running app uses, search its log the same way: Select-String on $env:LOCALAPPDATA\Ollama\server.log printed the default list here.

How it was reproduced

On Windows 11 with Ollama 0.40.11 and curl.exe 8.21.0 in Windows PowerShell 5.1, against a separate ollama serve on 127.0.0.1:15101, started four times from PowerShell: with no OLLAMA_ORIGINS, with one origin, with three, and with *. That port is the test's own; the installed app was only read, never reconfigured. app.example.test is a made-up host sent only as a header, so no browser or web page was involved.

Frequently asked

How do I fix Ollama CORS errors in the browser?
Add the page's origin, scheme, host and port, to the OLLAMA_ORIGINS environment variable and restart Ollama. Separate several values with commas; host:* allows every port of that host, and the https form must be listed separately.
Which origins does Ollama allow by default?
In version 0.40.11 the server's config line listed localhost, 127.0.0.1 and 0.0.0.0 over http and https on any port, plus the app, file, tauri and two VS Code schemes. Anything else gets 403 Forbidden.
Why does curl work but my web page gets 403 from Ollama?
curl sends no Origin header unless you add one, and Ollama only checks requests that carry it. A browser sends it for every request a page makes to another origin, so the page is refused while curl is not.

More decoded errors in the Fixes category. If the page talks to your own ASP.NET Core API instead, the same browser rule has its own post: 'No Access-Control-Allow-Origin header' in ASP.NET Core.