How to Monitor Corsica with Vigilmon
Corsica is the go-to CORS (Cross-Origin Resource Sharing) Plug for Elixir and Phoenix. It handles preflight OPTIONS requests, sets Access-Control-Allow-* headers, and enforces your allowed-origin policy with minimal configuration.
CORS issues are notoriously hard to detect server-side — the request arrives and gets processed, but the browser silently drops the response because a header is missing or misconfigured. Your API logs show 200 OK while users see Failed to fetch in the browser console.
Vigilmon gives you external HTTP monitoring that catches Corsica misconfigurations before your users report them, and alerts you when your API goes down entirely.
This tutorial covers:
- A health endpoint that validates CORS headers are present
- HTTP monitoring with header assertions in Vigilmon
- Preflight check monitoring
- Alerts for CORS policy drift
Step 1: Add a health endpoint to your Phoenix app
A standard Phoenix health plug works as the monitoring target:
# lib/my_app_web/plugs/health_check.ex
defmodule MyAppWeb.Plugs.HealthCheck do
import Plug.Conn
def init(opts), do: opts
def call(%Plug.Conn{request_path: "/health"} = conn, _opts) do
checks = %{
database: check_db(),
cors: :ok # Corsica itself has no runtime state to check; we rely on header assertions
}
status = if Enum.all?(checks, fn {_, v} -> v == :ok end), do: 200, else: 503
conn
|> put_resp_content_type("application/json")
|> send_resp(status, Jason.encode!(%{status: status_text(status), checks: checks}))
|> halt()
end
def call(conn, _opts), do: conn
defp check_db do
case MyApp.Repo.query("SELECT 1", []) do
{:ok, _} -> :ok
_ -> :error
end
end
defp status_text(200), do: "ok"
defp status_text(_), do: "degraded"
end
Place it before the router so it bypasses authentication, and ensure it runs through Corsica so the CORS headers are present on the health response:
# lib/my_app_web/endpoint.ex
plug MyAppWeb.Plugs.HealthCheck # health check first
plug Corsica,
origins: [
"https://app.example.com",
"https://staging.example.com"
],
allow_headers: ["content-type", "authorization"],
allow_methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
plug MyAppWeb.Router
Step 2: Set up Vigilmon HTTP monitoring
- Sign in at vigilmon.online and click Add Monitor.
- Choose HTTP monitor type.
- Enter your health endpoint URL (e.g.,
https://api.example.com/health). - Set check interval to 60 seconds.
- Expected status:
200. - Click Save.
Step 3: Assert CORS headers are present
Vigilmon's Advanced response checks let you assert that specific headers appear in the response. Use this to catch Corsica misconfigurations:
In your monitor settings under Response Checks:
| Check type | Header name | Expected value |
|---|---|---|
| Header present | access-control-allow-origin | Any value |
| Header contains | access-control-allow-methods | GET |
This ensures Corsica is actually injecting CORS headers on your health endpoint. If you misconfigure the origin whitelist or accidentally remove Corsica from the plug pipeline, Vigilmon will alert within 60 seconds.
Step 4: Monitor preflight requests
OPTIONS preflight requests are the most common CORS failure point. Add a dedicated preflight check endpoint or use Vigilmon's custom request configuration:
In Vigilmon, add a second monitor:
- Add Monitor → HTTP
- URL:
https://api.example.com/health - Method: OPTIONS
- Add request header:
Origin: https://app.example.com - Add request header:
Access-Control-Request-Method: POST - Expected status:
200or204 - Response check — header present:
access-control-allow-origin
This simulates the browser's preflight and catches the case where Corsica rejects an origin that should be allowed.
Step 5: Write a CORS integration test (Elixir)
Complement Vigilmon's external checks with in-process tests that validate your Corsica configuration:
# test/my_app_web/cors_test.exs
defmodule MyAppWeb.CorsTest do
use MyAppWeb.ConnCase
test "allowed origin receives CORS headers" do
conn =
build_conn()
|> put_req_header("origin", "https://app.example.com")
|> get("/health")
assert get_resp_header(conn, "access-control-allow-origin") == ["https://app.example.com"]
end
test "disallowed origin does not receive CORS headers" do
conn =
build_conn()
|> put_req_header("origin", "https://evil.example.com")
|> get("/health")
assert get_resp_header(conn, "access-control-allow-origin") == []
end
test "preflight returns allow-methods header" do
conn =
build_conn()
|> put_req_header("origin", "https://app.example.com")
|> put_req_header("access-control-request-method", "POST")
|> options("/api/some-endpoint")
assert get_resp_header(conn, "access-control-allow-methods") != []
end
end
Run with mix test test/my_app_web/cors_test.exs.
Step 6: Configure alerts
In Vigilmon go to Alerts and add notification channels:
- Slack —
#api-healthor#frontend-issueschannel (CORS errors almost always surface first as frontend reports) - Email — backend team on-call
- PagerDuty — for production APIs serving paying users
Recommended alert policy:
| Condition | Severity | Action | |---|---|---| | HTTP non-200 | Critical | Page backend on-call | | CORS header missing | Critical | Alert backend + frontend leads | | Preflight returning 403 | Critical | Alert immediately — frontend fully broken | | Response time > 2 s | Warning | Investigate plug pipeline performance |
Why Monitor Corsica?
Corsica is middleware — it has no persistent state, no background processes, and no telemetry by default. Failures manifest as:
- Browser
Failed to fetch— theAccess-Control-Allow-Originheader is missing or wrong - Preflight 403 — an allowed origin was removed from the whitelist or a deploy reverted config
- Missing
Access-Control-Allow-Headers— a new request header was added to the frontend but not the Corsica config - Wildcard origin accidentally removed — a config refactor broke the origin list
None of these produce server-side errors. They look like 200 OK in your logs while the frontend is completely broken. Vigilmon's header assertions catch them externally.
Key Metrics to Watch
| Metric | Threshold | Meaning |
|---|---|---|
| HTTP status | Must be 200 | API reachable |
| access-control-allow-origin header | Must be present | Corsica active |
| access-control-allow-methods header | Must include GET/POST | Method policy correct |
| Preflight status | Must be 200 or 204 | Preflight working |
| Response latency | < 500 ms | No plug pipeline bottleneck |
Conclusion
Corsica keeps your Phoenix API open to the right origins and closed to the wrong ones. Vigilmon keeps Corsica's configuration under continuous external validation — so when a deploy changes your origin whitelist or removes the plug from the pipeline, you know within a minute, not after a flood of frontend bug reports.
Get started free at vigilmon.online.