Trace and Fix CORS Policy Blocks with curl on AU Servers
CORS errors blocking your API? Learn terminal curl header tests, nginx/Apache fixes, and when Australian teams book Fixwebnode for remote server support.
If your browser console shows “blocked by CORS policy” while checkout, dashboards, or mobile apps fail to load API data, this guide walks you through terminal diagnostics and server fixes you can run yourself—or escalate cleanly.
Australian small businesses and site owners often hit this when a frontend on one domain calls an API on another (or on a subdomain) and the origin server never returns the right Access-Control-* headers. Below you will use custom curl header tests, inspect preflight responses, and patch nginx, Apache, or app middleware. For remote Linux server support in Australia, Fixwebnode works directly on the box—not as a freelance marketplace—so you get a specialist on the same failure mode you are seeing in DevTools.
Why CORS blocks and broken API assets matter under pressure
Cross-Origin Resource Sharing (CORS) is the browser’s rule set for whether JavaScript on origin A may read responses from origin B. When the server omits or misconfigures headers, the request may still reach the API, but the browser hides the body and logs a policy error. That looks like a “broken API asset”: empty product grids, failed auth, silent 200s that never hydrate the UI, or OPTIONS preflights returning 403/404.
Under launch or peak traffic pressure you need a repeatable path: reproduce with curl (no browser cache), compare simple GET vs preflight OPTIONS, fix the web server or app layer, then re-verify. Guessing wildcards in production without understanding credentials or Vary is how teams open security holes or still leave the SPA broken.
How do you trace CORS policy blocks on an Australian web server with curl?
Reproduce the failing call with curl -v using the same Origin the browser sends, then inspect whether the response includes Access-Control-Allow-Origin and, for credentialed or non-simple requests, a correct preflight. If those headers are missing or the OPTIONS route 404s, fix the server block or API middleware before touching frontend code. Book Fixwebnode when headers look right in curl but browsers still fail, or when multiple reverse proxies strip CORS on the way out.
| Symptom | Quick fix | When to call Fixwebnode |
|---|---|---|
| No ACAO header on GET | Add allow-origin (and methods) in nginx/Apache or app | CDN or multi-hop proxy still strips headers |
| OPTIONS returns 404/405 | Enable preflight route; allow requested headers | API gateway + origin disagree on OPTIONS |
| Credentials + wildcard origin | Echo exact Origin; set Allow-Credentials true | Auth cookies fail only in prod domains |
Common CORS and broken API asset issues
These problems show up repeatedly on Australian-hosted storefronts, booking tools, and internal apps. Each has a different root cause—do not treat them as one generic “turn CORS on” switch.
- Missing Access-Control-Allow-Origin on simple responses — Browser blocks reading JSON; Network tab shows 200 but console cites CORS. Often the app never set headers, or a reverse proxy overwrote them.
- Failed OPTIONS preflight (no Allow-Methods / Allow-Headers) — Custom headers,
Authorization, or non-simple content types trigger preflight; server returns 404, 405, or empty headers. - Credentialed requests with
*origin or wrong Vary — SPA usescredentials: 'include'or cookies; wildcard ACAO is illegal with credentials, so the browser rejects a “working” API. - Broken static or API assets behind a second origin — Fonts, tiles, or CDN JSON from another host lack CORS, so CSS/fonts fail or fetch() cannot parse payloads even though curl without Origin “works”.
Issue 1 — Trace missing ACAO with custom curl header tests
Confirm whether the origin server ever instructs the browser how to handle cross-domain data. Work from a shell with network access to the API host (your laptop or the server itself).
Step 1 — Capture the browser Origin and request URL
In DevTools → Network, open the failed call. Note request URL, method, and the Origin header (for example https://www.example.com.au).
Step 2 — Replay a simple GET with an explicit Origin
curl -sS -D - -o /tmp/cors-body.json \
-H 'Origin: https://www.example.com.au' \
-H 'Accept: application/json' \
'https://api.example.com.au/v1/products' | head -n 40
Look for Access-Control-Allow-Origin. If it is absent, the web server block or application lacks explicit cross-domain instructions—even if the JSON body is valid.
Step 3 — Compare without Origin
curl -sS -D - -o /dev/null 'https://api.example.com.au/v1/products' | head -n 30
If headers only appear without Origin, middleware may be conditional or a cache is serving a non-CORS variant. Check Vary next.
Step 4 — nginx: add CORS on the API location (example)
# Inside server { } for api.example.com.au — adjust origin allow-list
set $cors_origin "";
if ($http_origin ~* "^https://(www\.)?example\.com\.au$") {
set $cors_origin $http_origin;
}
location /v1/ {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, Accept" always;
add_header Access-Control-Max-Age 86400 always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Vary "Origin" always;
proxy_pass http://127.0.0.1:3000;
}
Test config and reload:
sudo nginx -t && sudo systemctl reload nginx
Step 5 — Apache equivalent (vhost or .htaccess where allowed)
Header always set Access-Control-Allow-Origin "https://www.example.com.au"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
Header always set Vary "Origin"
sudo apachectl configtest && sudo systemctl reload apache2
Step 6 — Re-verify
curl -sS -D - -o /dev/null \
-H 'Origin: https://www.example.com.au' \
'https://api.example.com.au/v1/products' | grep -i access-control
You should see ACAO matching your Origin (not a silent miss). If DIY stops here because multiple app nodes disagree, call a pro.
Issue 2 — Fix broken preflight (OPTIONS) for complex API calls
Custom headers, JSON POST, or Authorization force a preflight. If OPTIONS is not handled, the real POST never runs in the browser.
Step 1 — Send a preflight that mirrors the browser
curl -sS -D - -o /dev/null -X OPTIONS \
-H 'Origin: https://www.example.com.au' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: authorization,content-type' \
'https://api.example.com.au/v1/orders'
Expect status 204 or 200 plus Access-Control-Allow-Methods and Access-Control-Allow-Headers covering what you requested. 404/405 means the route or server block lacks OPTIONS.
Step 2 — Application-level allow (Node/Express sketch)
// Ensure OPTIONS is not swallowed by auth middleware before CORS
app.use((req, res, next) => {
const allowed = ['https://www.example.com.au', 'https://example.com.au'];
const origin = req.headers.origin;
if (origin && allowed.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Vary', 'Origin');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type,Accept');
}
if (req.method === 'OPTIONS') return res.sendStatus(204);
next();
});
Restart the process manager after deploy:
sudo systemctl restart your-api.service
# or: pm2 restart api && pm2 logs api --lines 50
Step 3 — Confirm preflight then real POST
curl -sS -D - -o /dev/null -X OPTIONS \
-H 'Origin: https://www.example.com.au' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: authorization,content-type' \
'https://api.example.com.au/v1/orders' | grep -iE 'HTTP/|access-control'
curl -sS -D - -o /tmp/order.json -X POST \
-H 'Origin: https://www.example.com.au' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer test-token' \
-d '{"sku":"demo"}' \
'https://api.example.com.au/v1/orders' | head -n 25
If OPTIONS is clean in curl but a WAF still challenges browsers, escalate—rule order on edge devices is easy to get wrong under pressure.
Issue 3 — Credentialed CORS and broken session APIs
Symptom: login cookie or Authorization works same-origin; cross-subdomain SPA gets CORS errors mentioning credentials or shows ACAO as *.
Step 1 — Prove the illegal combination
curl -sS -D - -o /dev/null \
-H 'Origin: https://app.example.com.au' \
-H 'Cookie: session=dummy' \
'https://api.example.com.au/v1/me' | grep -iE 'access-control|set-cookie|vary'
If you see Access-Control-Allow-Origin: * together with credentialed client config, browsers will block. ACAO must echo the specific Origin and Access-Control-Allow-Credentials: true must be present when cookies are used.
Step 2 — Align cookie attributes with cross-site needs
API Set-Cookie for SPA on another site typically needs appropriate SameSite, Secure, and domain scope. Prefer fixing CORS + cookie flags together; do not disable browser security.
Step 3 — Cache-aware Vary
curl -sS -D - -o /dev/null \
-H 'Origin: https://app.example.com.au' \
'https://api.example.com.au/v1/me' | grep -i vary
Missing Vary: Origin lets a CDN cache one client’s ACAO for everyone. Add Vary Origin at nginx or the app, then purge CDN cache for the API paths.
Issue 4 — Cross-origin fonts, tiles, or JSON assets still blocked
Symptom: CSS loads but fonts are missing; map tiles or public JSON endpoints fail only in the browser.
Step 1 — Test the asset URL with Origin
curl -sS -D - -o /dev/null \
-H 'Origin: https://www.example.com.au' \
'https://cdn.example.com.au/fonts/inter.woff2' | grep -iE 'HTTP/|access-control|content-type'
Step 2 — Allow only needed methods on static hosts
location ~* \.(woff2?|ttf|otf|json)$ {
add_header Access-Control-Allow-Origin "https://www.example.com.au" always;
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
add_header Access-Control-Allow-Headers "Range" always;
}
sudo nginx -t && sudo systemctl reload nginx
Re-test in an incognito window so cached failures clear.
When DIY is enough vs when to book Fixwebnode
DIY is enough when a single origin server is under your control, curl preflight and GET both show the headers you expect after reload, and the browser console goes quiet. Stop and book a specialist when: headers differ between edge CDN and origin; only some regions or mobile networks fail; OAuth or cookie auth works in staging domains but not production; OPTIONS is answered by a gateway that strips body headers; or you cannot safely change production nginx without downtime planning.
Fixwebnode provides direct remote server support for Australian businesses—Ubuntu/Linux diagnostics, reverse-proxy CORS, and API asset paths—via the same landing path as other Linux work. See where support is offered across the country on the service areas page. Related storefront builds (for context on multi-origin Shopify stacks, not marketplace bidding) include Melbourne bedding & textiles Shopify design and Melbourne gaming accessories Shopify design—useful when a headless or multi-domain shop is what triggered CORS in the first place.
Book remote help to clear CORS and restore API assets
If you are still blocked after the curl checks above, bring the failing URL, the exact console message, and a redacted curl -v transcript to a direct conversation with Fixwebnode. Remote tracing focuses on the real server blocks and preflight paths so your frontend can read cross-domain payloads again without guesswork.
Start here: Ubuntu Linux server support and bug fixing with Fixwebnode. Share the Origin pair and we will work the policy headers and broken API assets under pressure with you.