tutorial

How to Monitor Corsica with Vigilmon

Monitor your Elixir/Phoenix API's CORS middleware with Vigilmon — detect misconfigured origins, rejected preflight requests, and header policy drift before they break your frontend users.

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

  1. Sign in at vigilmon.online and click Add Monitor.
  2. Choose HTTP monitor type.
  3. Enter your health endpoint URL (e.g., https://api.example.com/health).
  4. Set check interval to 60 seconds.
  5. Expected status: 200.
  6. 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:

  1. Add Monitor → HTTP
  2. URL: https://api.example.com/health
  3. Method: OPTIONS
  4. Add request header: Origin: https://app.example.com
  5. Add request header: Access-Control-Request-Method: POST
  6. Expected status: 200 or 204
  7. 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-health or #frontend-issues channel (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 — the Access-Control-Allow-Origin header 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.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →