sigil-rpc pods provide the application-layer defence.
Architecture
rpc-direct.sigil.ml) skips the top layer and goes straight to ingress-nginx and the pods. The lower pod-layer rate limit (10/25 rps) compensates.
Cloudflare DNS configuration
| Hostname | Type | Value | Proxied |
|---|---|---|---|
rpc.sigil.ml | A/AAAA | LB IP | yes (orange cloud) |
rpc-direct.sigil.ml | A/AAAA | LB IP | no (grey cloud) |
canary-rpc.sigil.ml | A/AAAA | LB IP | yes |
canary-rpc-direct.sigil.ml | A/AAAA | LB IP | no |
explorer.sigil.ml | A/AAAA | static-site IP | yes |
status.sigil.ml | CNAME | <R2 bucket>.r2.cloudflarestorage.com | yes |
WAF rules (Cloudflare)
Apply at therpc.sigil.ml and canary-rpc.sigil.ml zones.
Managed rules
- OWASP Core Rule Set, default sensitivity.
- Cloudflare Managed Rules.
- Exposed Credential Checks.
Custom rules
| # | Match | Action |
|---|---|---|
| 1 | POST /rpc without content-type: application/json | Block |
| 2 | Source ASN in the abuse list | Managed Challenge |
| 3 | Request body > 16 MiB | Block |
| 4 | Per-IP rate > 5,000 / 5 min | Managed Challenge |
| 5 | User-Agent contains sqlmap, nikto, or nmap | Block |
| 6 | Path not in {"/rpc","/health","/metrics","/ws","/"} | Block |
Edge rate-limit
The edge ceiling is 10x the application-layer cap so the application layer remains the primary defence.| Path | Method | Rate | Action |
|---|---|---|---|
/rpc | POST | 1,000 / 1 min / IP | Block (10 min) |
/ws | * | 30 connections / 1 hour / IP | Block (10 min) |
Bot Fight Mode
- Enabled on
sigil.mlandcanary-rpc.sigil.mlzones. - Super Bot Fight Mode: enabled on Pro+ plan.
TLS
- TLS mode: Full (Strict). Origin must present a valid Let’s Encrypt cert.
- Minimum TLS version: 1.2.
- HSTS:
max-age=31536000; includeSubDomains; preload. - cert-manager issues origin certs via HTTP-01 against a non-Cloudflare-proxied subdomain.
Direct endpoint hardening
Becauserpc-direct.sigil.ml is grey-cloud, the application-layer compensates:
- Stricter rate limit (10/25 rps vs 25/100).
- Same 4 MiB body cap.
- ingress-nginx sets
proxy-body-size: 4mandproxy-read-timeout: 60s. fail2banon the LB host blocks IPs that emit 100+ HTTP 429 responses in 5 minutes for 1 hour.
Operator procedures
Add an abuse ASN to the challenge list
- Identify the ASN from the WAF event log.
- Update WAF rule #2 with the new ASN.
- Commit the rule change to Terraform.
- Verify by issuing a test request from the abusive ASN.
Respond to a live attack
- Inspect the Cloudflare Security tab for the attack profile.
- Enable “Under Attack” mode if the attack overwhelms default protection. Every request is forced through a managed challenge for 30 minutes.
- Confirm
status.sigil.mlreflects the incident; post manually if not. - After the attack subsides, run a post-incident review and add a permanent rule.
Verify rules
Status page integration
status.sigil.ml auto-updates from Alertmanager:
SigilRpcRateLimited{quantile=p99} > 0.5for 5 minutes → degraded.- Cloudflare API “site under attack” boolean → degraded.
- ingress-nginx availability < 99% → outage.