Troubleshooting noc
When noc cannot reach your endpoint, there are three reasons worth checking, and they need three different fixes. This page is about those failures. Setting an endpoint up is on the noc page; the board itself is at /noc/board.
Two of the three are not distinguishable from inside a browser, so noc does not guess between them and neither should this page. Where you see "check both", that is why — not vagueness, but the honest shape of what a page can observe about a request it was never allowed to send.
Worth knowing before any of it: every query goes straight from your browser
to the endpoint you configure, and nocternal never sees one. That is a
narrower promise than the redaction tools make, on purpose — their
connect-src 'none' is enforced by your browser, and noc's
policy has to stay open enough to reach wherever you point it. Open your
Network tab while noc is polling and check for yourself that every request
goes to the endpoint you configured, and nothing else.
1. CORS: the endpoint answers, the browser will not let noc read it
The tell: the endpoint's /api/v1/query?query=1 URL loads
fine in a new tab, and noc still reports the request as failing without a
response. A browser will not hand a cross-origin response to a page
unless the response says it may, and vanilla Prometheus already says so
for any origin. A reverse proxy in front of it usually does not.
Read this part before you paste either snippet. Allowing
an origin here is not configuration, it is weakening a control you put
there. Right now no web page in anyone's browser can read this endpoint.
After the change, any page served from the origin you name can read it
from the browser of anyone whose network position or credentials already
reach it — which, for an endpoint behind a VPN or an office network,
includes people you were relying on that boundary to keep out. Name one
origin. Never *, and never together with
Access-Control-Allow-Credentials.
Both snippets are a starting point for the CORS headers specifically, not a drop-in server block — authentication, TLS and the rest of your configuration are yours and are not shown.
They allow an origin and nothing else, because that is all noc's requests
need. noc asks for the query API with a plain GET and sends
no headers of its own, which makes every request it issues a "simple" one
in CORS terms — so your browser sends no preflight, and a rule matching
OPTIONS will never fire for noc. If you are watching for a
preflight that never arrives, that is why.
nginx
location / {
proxy_pass http://127.0.0.1:9090;
# One origin, named exactly. "always" so the header survives
# error responses too, which is where a 404 from a wrong
# context root would otherwise arrive unreadable.
add_header Access-Control-Allow-Origin https://nocternal.net always;
} Caddy
metrics.example.com {
@noc header Origin https://nocternal.net
header @noc Access-Control-Allow-Origin "https://nocternal.net"
reverse_proxy 127.0.0.1:9090
}
One more thing that looks exactly like a CORS failure and is not: a wrong
base URL. Prometheus attaches CORS headers to its real API routes only,
so a 404 from a path it does not serve arrives unreadable rather than as
a 404. Mimir usually wants /prometheus (or
/api/prom on Grafana Cloud), VictoriaMetrics in cluster mode
/select/<accountID>/prometheus, and GreptimeDB
/v1/prometheus.
2. A plain http:// endpoint: noc's own policy refuses it
noc's Content-Security-Policy names the plain-http origins it
permits, exactly: http://localhost:* and
http://127.0.0.1:*, and nothing else. Any other
http:// address — a LAN IP, a hostname on your network, an
IPv6 literal — is refused by that policy before the request is sent. The
refusal is unconditional, and it is noc's, not your network's.
noc used to call this mixed content. That named the wrong blocker, and the difference is practical rather than pedantic: a browser that has been granted local network access exempts an address it can tell is local before it resolves it, so a reader could satisfy the mixed-content rule exactly and land back here reading the same message. Two remedies actually work.
- Put TLS in front of it and use the
https://URL. noc's policy permits any TLS endpoint rather than naming them host by host, so nothing about noc has to change for this to work. - Or forward it to your own machine and point noc at
http://127.0.0.1:<port>, which the policy does name.kubectl port-forwardand an SSH tunnel both do this.
The forwarding wording is deliberate. A LAN address is a different
machine: 127.0.0.1 is the same server as
127.0.0.2 and is not the same server as
10.0.0.5, so swapping the address without forwarding
anything just points noc at a port with nothing behind it.
An IPv6 loopback literal — [::1] — is a special case with no
remedy of its own: a Content-Security-Policy has no way to express a
bracketed IPv6 literal at all, so there is no source expression noc could
add. Use 127.0.0.1 for a server that is listening on both.
http://localhost is the exception that makes the zero-setup
path work: modern browsers treat it as a secure context, and noc's policy
names it. Run a Prometheus-compatible server on your own machine, point
noc at localhost:9090, and there is nothing to configure.
3. The local network permission
Since 2025, a page on the public web needs your permission before it may reach an address on your own machine or your local network. Chrome shipped this in version 142; Firefox has its own, rolling out gradually. It is a separate gate from the two above: your endpoint can be up, its CORS headers correct, and the request still never gets sent.
A refused permission reports exactly what an unreachable endpoint reports. Both arrive as a request that failed with no response — Chrome says "Failed to fetch", Firefox says "NetworkError when attempting to fetch resource" — and there is nothing in either to tell them apart. noc cannot detect that a permission is holding a request, and does not claim to. So this is worth checking even when nothing appears to have asked you anything.
Both browsers split it into two settings, which is why "I already allowed it" and "it is still blocked" are often both true. A grant covering one endpoint can leave the next one waiting on the other half.
- Firefox calls them "Device apps and services", which covers this machine, and "Local network devices", which covers the rest of the network. Open the site's permissions from the address bar.
- Chrome calls them "Apps on device" and "Local network", each set to Ask, Allow or Block. "Apps on device" also has its own toggle to the left of the address bar; both live under Site settings for this page. Check both rather than guessing which one an endpoint falls under.
A Block is remembered, so re-running the check after one changes nothing until the setting itself is changed back. Set it to Ask or Allow, reload, and try again.
What noc stores, and where
The endpoint you type is written to localStorage in this
browser, on this device. It is sent to the endpoint you typed and to
nowhere else — there is no noc account, no server of noc's own, and
nothing to sync it to. Clearing the endpoint field on
the noc page removes the stored copy; clearing site
data for nocternal.net removes it along with everything else.
noc has no field for a credential today. The endpoint
form takes a URL, and noc sends no Authorization header with
any request it makes. So an endpoint that requires one is not reachable
from noc yet — not fiddly to set up, but not reachable: if yours answers
401 or 403, there is nothing you can type here that will change the
answer. Point noc at an endpoint you can already reach without a
credential, and if that means putting it behind your own network or a
proxy that handles the auth, that is the way in for now.
What is stored is stored where any page on this origin could read it, and two things are true about that at once. Anything able to run JavaScript on nocternal.net can read that storage — that is how browser storage works everywhere, and noc does not change it. And the scripts able to run here are only the ones this site ships: every page on nocternal.net allows scripts from this origin alone and loads no third-party code, no plugins and no ad tags, which is the same Network tab check as above. Fewer scripts can reach it than on a dashboard with a plugin catalogue; that is a smaller surface, not an absent one.
A URL is worth less than a credential, but it is not worth nothing: it names a host, and on a private network that name is itself something an attacker would otherwise have to discover. So it is still worth pointing noc at endpoints you would be content to see written down in this browser.