DEV Community

Vigilmon
Vigilmon

Posted on

How to Monitor Your Cloudflare R2 Storage with Vigilmon

How to Monitor Your Cloudflare R2 Storage with Vigilmon

Cloudflare R2 is an S3-compatible object storage service with zero egress fees. It's increasingly popular for storing user uploads, static assets, AI model weights, and application backups. Like any storage infrastructure, R2 needs monitoring to detect outages and access failures before they cascade into application errors.

This guide explains how to monitor your Cloudflare R2 storage with Vigilmon.

Why Monitor Cloudflare R2?

R2 failures manifest as:

  • 403 Forbidden errors from expired or misconfigured API tokens
  • CORS failures blocking direct browser uploads
  • Custom domain outages when your R2 public bucket's custom domain fails
  • Regional connectivity issues for specific R2 endpoints
  • Signed URL failures when your URL signing logic breaks

Monitoring R2's Public Bucket URL

If you're using R2 with a public bucket or custom domain, the easiest monitoring approach is to check a known object's URL directly:

1. Upload a Health Check Object

Upload a small static file to your R2 bucket that serves as a health check sentinel:

# Using wrangler CLI
echo '{"status":"ok","service":"r2"}' > health.json
wrangler r2 object put your-bucket/health.json --file=health.json
Enter fullscreen mode Exit fullscreen mode

Make this object publicly accessible.

2. Monitor the Object URL

In Vigilmon:

  1. Go to vigilmon.onlineAdd Monitor
  2. Type: HTTP(S)
  3. URL: https://pub-your-account-id.r2.dev/health.json (or your custom domain)
  4. Interval: 1 minute
  5. Timeout: 10 seconds
  6. Expected status: 200
  7. Keyword check: "status":"ok"

This monitors both R2 availability and your CDN layer (Cloudflare's cache in front of R2).

Monitoring R2 API Access (For Private Buckets)

For private R2 buckets accessed via the S3-compatible API:

import boto3
import botocore
from flask import Flask, jsonify

app = Flask(__name__)

r2_client = boto3.client(
    "s3",
    endpoint_url="https://your-account-id.r2.cloudflarestorage.com",
    aws_access_key_id="your-r2-access-key-id",
    aws_secret_access_key="your-r2-secret-key",
    config=botocore.config.Config(signature_version="s3v4"),
    region_name="auto"
)

@app.route("/health/r2")
def r2_health():
    try:
        # Lightweight: head request on the health check object
        r2_client.head_object(Bucket="your-bucket", Key="health.json")
        return jsonify({"status": "ok"})
    except botocore.exceptions.ClientError as e:
        code = e.response["Error"]["Code"]
        if code == "404":
            return jsonify({"status": "error", "reason": "health object missing"}), 503
        elif code in ("403", "AccessDenied"):
            return jsonify({"status": "error", "reason": "access_denied"}), 503
        return jsonify({"status": "error", "code": code}), 503
    except Exception as e:
        return jsonify({"status": "error", "message": str(e)}), 503
Enter fullscreen mode Exit fullscreen mode

Add this endpoint to Vigilmon with a 5-minute check interval.

Monitoring R2 Upload Capabilities

If your application lets users upload directly to R2 (via presigned URLs), you need to monitor the upload path too:

@app.route("/health/r2/upload")
def r2_upload_health():
    try:
        # Try to generate a presigned URL (doesn't actually upload)
        url = r2_client.generate_presigned_url(
            "put_object",
            Params={"Bucket": "your-bucket", "Key": "health-upload-test.tmp"},
            ExpiresIn=60
        )
        if url and url.startswith("https://"):
            return jsonify({"status": "ok", "presigned_url_generated": True})
        return jsonify({"status": "error"}), 503
    except Exception as e:
        return jsonify({"status": "error", "message": str(e)}), 503
Enter fullscreen mode Exit fullscreen mode

Presigned URL generation fails if your R2 credentials are invalid, bucket doesn't exist, or R2 API is unreachable — without making any actual PUT request.

Custom Domain Monitoring

Many R2 deployments use Cloudflare custom domains. Monitor the custom domain separately from the R2 origin:

  • Monitor 1: Your custom domain (https://assets.yourdomain.com/health.json)
  • Monitor 2: The R2 public URL (https://pub-xxx.r2.dev/health.json)

If Monitor 1 fails but Monitor 2 is healthy, the issue is in your Cloudflare DNS/cache config, not R2 itself.

Alert Configuration

Scenario Priority Response
R2 completely unreachable P0 Check Cloudflare status page
403 Access Denied P1 Rotate R2 API keys immediately
Custom domain down, R2 up P2 Fix Cloudflare DNS/routing
Upload presigning fails P1 Check R2 token permissions

Checking Cloudflare Status

When Vigilmon alerts on R2 issues, check cloudflarestatus.com to distinguish R2 platform issues from your own configuration problems.

Conclusion

Cloudflare R2's zero egress fee model makes it attractive for high-traffic applications — but that traffic concentration makes outages more impactful. Set up R2 monitoring with Vigilmon at vigilmon.online and get instant alerts when your storage layer fails.

Top comments (0)