Skip to content

Put dalenguyen.me behind Cloudflare WAF to block scanner traffic #217

Description

@dalenguyen

Problem

Real bot-scanner traffic on dalenguyen.me (Cloud Run, blog-app) is
untouched by the #210/#213 fix, since it targets generic CMS/framework paths
outside our /api/v1/** namespace, not our own routes. Sampled from Cloud
Run logs (2026-07-05, various times):

  • /wp-login.php, /wp-admin/setup-config.php, /wp-config.php
  • /.git/config, /.git/HEAD
  • /wp-includes/wlwmanifest.xml under a dozen path prefixes (/blog/,
    /shop/, /2019/, etc.) — automated CMS fingerprinting
  • /.env, /.env.production, /config.php, /config.xml

All currently return 200 via the Angular SSR not-found fallback (see #216
for the underlying status-code bug). None of this is blocked or reduced —
every one of these requests still spins up Cloud Run compute and pollutes
logs.

Decision

Use Cloudflare (not GCP Cloud Armor) as the edge WAF layer in front of
the apex. Chosen over Cloud Armor for cost/simplicity — Cloudflare's free
tier covers Bot Fight Mode + custom firewall rules, no GCP load balancer
needed.

Plan

  1. Add dalenguyen.me as a site in Cloudflare (free plan).
  2. At the registrar (currently dns1/dns2.registrar-servers.com), switch
    nameservers to the two Cloudflare assigns.
  3. Recreate DNS records in Cloudflare:
    • dalenguyen.me (apex) → same target as today (Cloud Run domain
      mapping), proxied (orange cloud on).
    • www → leave pointed at Vercel; proxying is optional since Vercel
      already has its own edge.
  4. Security → WAF:
    • Enable Bot Fight Mode.
    • Add a Custom Rule, action Block:
      (http.request.uri.path contains "wp-login") or
      (http.request.uri.path contains "wp-admin") or
      (http.request.uri.path contains "wp-includes") or
      (http.request.uri.path contains "wp-content") or
      (http.request.uri.path contains ".env") or
      (http.request.uri.path contains ".git") or
      (http.request.uri.path contains "config.php") or
      (http.request.uri.path contains "xmlrpc.php") or
      (http.request.uri.path contains "wlwmanifest.xml")
      
      Safe to hard-block (not challenge) — this app (Analog/Angular) has no
      legitimate path matching any of these.
  5. Verify: re-run the Cloud Run log query for these paths a few hours after
    cutover and confirm they've dropped to zero (Cloudflare should be
    rejecting them before they ever reach Cloud Run).

Notes

Acceptance

  • dalenguyen.me nameservers point at Cloudflare.
  • Bot Fight Mode + the custom block rule are active.
  • A live probe to any of the listed paths (e.g.
    curl -o /dev/null -w '%{http_code}' https://dalenguyen.me/wp-login.php)
    returns a Cloudflare block response, not the app's 200.
  • Cloud Run log query for these paths shows near-zero hits a few hours
    after cutover.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions