Site Down from CC: Emergency Degradation and Error Pages
CC does not knock the box over in one blast. It starves dynamic pages with a flood of lookalike-normal requests. Eight Q&As cover the emergency order, degradation, Nginx rate limits plus static fallback, and a 503 page with Retry-After.
A CC takedown is not a volumetric DDoS. Traffic may sit at tens of Mbps while CPU hits 100% and pages crawl until 502. Fastest recovery is not IP bans. Degrade on purpose: drop dynamic features to static, turn over-limit requests into informative error pages. Eight Q&As cover the full CC emergency degradation playbook. Configs are copy-ready.
Q: Site is down from CC. First move?
Confirm the attack entry, then act. Count top URLs in the access log:
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -20
If one search page, detail page, or API dwarfs other URLs while source IPs are mixed, it is CC. Three tells: traffic is modest but origin CPU is high; requests concentrate on dynamic pages; IPs are scattered and query params look alike.
Then do two things immediately: rate-limit at Nginx to stop the bleed, degrade the hit entry to cache or a static fallback. Do not start by banning IPs. CC uses proxy pools; tens of thousands of IPs rotate in a day. Manual bans never catch up.
Q: What is service degradation? Why is it mandatory in a CC emergency?
Degradation is cutting non-core features on purpose when resources are tight, so core requests still get CPU. CC burns dynamic compute: DB queries, template render, search matching. Degradation means those hit requests do not compute — Nginx returns cache or a static file and never reaches the app.
Versus IP bans, three wins: fast (edit config, reload, seconds); no attacker ID required (no need to know which IP is hostile, fewer false positives); controllable (core pages stay up, only non-core is sacrificed). In CC, degradation is the highest ROI emergency move.
Q: How do I rate-limit and degrade fast in Nginx? Give a copy-ready config
Step one: global rate limit to stop the bleed. Define zones in the http block:
http {
# 10 req/s per IP; per-IP concurrent cap
limit_req_zone $binary_remote_addr zone=cc:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=cc_conn:10m;
# Over-limit always 503 so the custom page can catch it
limit_req_status 503;
limit_conn_status 503;
server {
# Rate-limit + conn limit on dynamic entries
location ~ \.(php|jsp|asp)$ {
limit_req zone=cc burst=20 nodelay;
limit_conn cc_conn 20;
proxy_pass http://backend;
}
# Hit high-cost entry: degrade straight to static
location = /search {
return 302 /search-static.html;
}
}
}
Params: rate=10r/s is plenty for a real visitor (nobody clicks 10 times a second); dense CC is dropped in bulk. burst=20 nodelay lets a short burst of 20 through so a refresh is not false-limited. limit_conn 20 caps per-IP concurrency; mainly stops Slowloris-class slow connections. After the edit: `nginx -t && nginx -s reload`.
Q: How do I write a friendly error page for rate-limited requests?
Do not dump 502 or a blank page. Serve a pure-static notice:
limit_req_status 503;
limit_conn_status 503;
error_page 503 /cc-busy.html;
location = /cc-busy.html {
root /usr/share/nginx/html;
internal;
add_header Retry-After 10 always;
}
Three rules: the error page must be pure static HTML with zero dynamic calls, or the fallback itself will kill the backend. Return a real 503 and set Retry-After so browsers and crawlers know when to retry. Copy must be plain: high traffic, refresh later — not a one-line exception dump.
SEO detail that gets missed: crawlers treat 503 + Retry-After as temporary unavailability. Failed fetch, rank intact. Returning 200 with error body looks like a soft 404 or content fault and hurts weight.
Q: How do I degrade login, register, checkout, and other dynamic APIs?
These cost the most (read + write). Three layers.
Layer 1: temporarily kill non-core APIs. Search, comments, list filters are cheap to lose and expensive to run. During CC, shut them:
location = /api/search { return 503; }
location = /comments { return 503; }
Layer 2: send reads to cache. If you have Redis, cut hot reads to cache with a short TTL. No cache? Temporary Nginx cache so identical requests stop hitting the backend every time:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:10m inactive=1h max_size=512m;
location /api/ {
limit_req zone=cc burst=20 nodelay;
proxy_cache api;
proxy_cache_valid 200 10s;
# On upstream faults, serve stale cache instead of a raw 502
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
proxy_pass http://backend;
}
Layer 3: challenge writes. Login, register, SMS OTP are shared targets for CC and credential stuffing. Add a human challenge and a hard rate cap, e.g. 1/min per IP. This layer cannot be degraded. Challenge + rate limit only.
Q: Degrade a URL or just ban it?
Score on three axes. Avoid a blanket ban that hits real users:
- Real user value and the attack is concentrated (search, list filters): degrade first — rate-limit + cache + static fallback. Keep availability.
- Hot writes, business-mandatory (checkout, SMS, ingest APIs): rate-limit + human challenge. Queue if needed. Do not shut them.
- Paths with no business meaning: logs full of random-string params. Almost all attack traffic. Reject by rule:
# Search param is a 20+ char nonsense random string; silent drop (tune to your log signatures)
if ($arg_s ~ "^[a-z0-9]{20,}$") { return 444; }
Core rule: degrade to keep availability, ban to keep resources. Degrade what users need. Ban garbage they never use.
Q: How do I keep UX and SEO during degradation?
Three rules:
- Do not degrade core pages: home, article detail, checkout stay up. Cut only non-core dynamic entries: search, comments, filters.
- Error page in human language: reason + retry time, with 503 + Retry-After. Users wait. Crawlers see a temporary fault.
- Config needs a rollback switch: put degrade directives in a dedicated include. On recovery, delete or rename it and reload. Stops you from leaving degrade on after the attack.
include /etc/nginx/emergency/cc-degrade.conf; # emergency switch: delete this line to restore
nginx -t && nginx -s reload # apply degradation
# after the attack: comment or delete the include, reload again to restore
Q: Anything else?
Freeze CC emergency into an order. Follow it when it hits: ① read logs, lock the hit entry → ② Nginx global rate limit to stop the bleed (10 r/s + concurrency 20) → ③ degrade high-cost dynamic entries (off / cache / static fallback) → ④ custom 503 + Retry-After → ⑤ human challenge on login/register → ⑥ after recovery, tune from logs and keep the emergency config as a template.
Degradation is not surrender. It is allocating scarce resources to core business. In CC, that is the most effective survival move. It is still last-ditch insurance. Long term, do frequency detection, JA3 fingerprints, and request-feature analysis at CDN/WAF so junk dies at the edge and origin only sees clean traffic. Then you are not cutting features every time just to stay alive.