Skip to content

Network protection

Use this page when you are ready to configure Cloudflare controls in front of the Worker. Network protection keeps commodity abuse, unexpected methods, scanner probes, unwanted crawlers, and infrastructure noise away from application code.

For the layered security rationale, read Layering Cloudflare protection around a short-link domain. The raw Cloudflare dashboard capture lives in data/cloudflare-protection-defaults.json; use it to track Cloudflare menu changes, not as an operator checklist.

For the features intentionally left out of the default setup, read Cloudflare features not to enable by default.

flowchart LR
A["Visitor request"] --> B["Cloudflare edge"]
B --> C["TLS, DDoS,
managed rules"] C --> D["WAF, rate limit,
bot controls"] D --> E{"Allowed to
reach Worker?"} E -->|"no"| F["Block, challenge,
or rate-limit response"] E -->|"yes"| G["vanityURLs Worker"] G --> H["Redirect short link"] G --> I["Public local page"] G --> J["Protected path
to the dashboard"]

Confirm the Worker custom domain

In Cloudflare, open Domains > your short domain > DNS > Records. Use the Worker Custom Domain record that Cloudflare creates for the short domain. It should appear as a proxied Worker record for the hostname, such as v8s.link -> v8s-link.

Remove legacy synthetic AAAA 100:: records for the same hostname once the Custom Domain is active. Keep mail, DKIM, DMARC, MTA-STS, and ownership verification records DNS-only unless the provider explicitly requires proxying.

Use the apex hostname as the only vanityURLs Worker hostname. If you publish www, create a proxied DNS record for www and redirect it to the apex in Cloudflare before the Worker. Use separate proxied records only for real web subdomains, such as mta-sts or a docs site.

Redirect www to the apex

In Cloudflare, open Domains > your short domain > Rules. Prefer Redirect Rules when available. If your zone already uses legacy Page Rules, a single forwarding URL rule is also fine for this hostname canonicalization because it runs before the Worker and stays outside the vanityURLs link registry.

Configure the redirect with these values:

FieldValue
Rule nameRedirect www to apex
Sourcewww.v8s.link/*
Destinationhttps://v8s.link/$1
Status code301 - Permanent Redirect
OrderBefore Worker/WAF evaluation

Keep the www DNS record proxied so Cloudflare can receive the request and apply the redirect. Do not add www to the Worker custom domain or to the WAF/rate-limit expressions below unless you intentionally serve the Worker on both hostnames.

Set the HTTPS baseline

In Cloudflare, open Domains > your short domain > SSL/TLS > Overview. In Configure encryption mode, select Custom SSL/TLS, choose Full (Strict), then save. Cloudflare may show Automatic SSL/TLS (default) with a current applied mode such as Flexible before you make this change; that is the state to replace for a production Worker custom domain.

Then open SSL/TLS > Edge Certificates and review the options in dashboard order:

Dashboard optionRecommendation
Manage Edge CertificatesConfirm an active Universal certificate covers the apex domain and wildcard, such as v8s.link and *.v8s.link
Advanced Certificate ManagerNo action unless the instance needs paid custom certificate controls
Total TLSNo action on the Free baseline; it requires Advanced Certificate Manager
Cipher suitesNo action on the Free baseline; it requires Advanced Certificate Manager
Always Use HTTPSOn
HTTP Strict Transport Security (HSTS)Leave Cloudflare dashboard HSTS disabled unless you intentionally want a zone-level policy beyond the repo header
Minimum TLS VersionTLS 1.2 or stricter
Opportunistic EncryptionOn is fine; no vanityURLs-specific action required
TLS 1.3On
Automatic HTTPS RewritesOn
Certificate Transparency MonitoringOptional, useful for unexpected certificate alerts
Disable Universal SSLDo not click it; seeing this action means Universal SSL is currently enabled

HSTS can look enabled when it is not

HSTS is the easy place to misread the UI. The repository ships a host-scoped Strict-Transport-Security: max-age=31536000 header for Worker and static-asset responses. Prefer that repo-managed header as the source of truth. Enable Cloudflare dashboard HSTS only when you deliberately want Cloudflare to own or strengthen the policy across the zone. Use includeSubDomains and Preload only when the whole zone is intentionally HTTPS-only.

Avoid competing header sources

Keep CSP, HSTS, frame, referrer, and permissions policy in the repository unless there is a deliberate zone-level reason to manage one of them in Cloudflare. If Cloudflare Transform Rules, Snippets, Zaraz, Rocket Loader, managed HSTS, or other dashboard features add or rewrite the same headers or inject scripts, they can conflict with the Worker and _headers policy.

This follows ADR 0014: Prefer repository-owned configuration: use the Cloudflare dashboard for controls that cannot reasonably live in Git, and leave dashboard duplicates disabled when the repository already owns the behavior.

Enable baseline security controls

In Cloudflare, open Domains > your short domain > Security > Settings for the dashboard, bot, browser integrity, challenge, content-rewrite, and security.txt controls. The Settings page is long and includes filter chips and a search field. They are useful for finding a known setting, but this checklist follows the page order because the filters hide context and can make setup harder to audit. Custom expressions are covered in Add WAF rules below.

The free-plan security settings should stay boring and explicit. Turn on protections that reduce commodity abuse, but avoid features that alter public content or expose extra visitor data unless there is a clear need.

Setting, in dashboard orderRecommendationWhy
AI LabyrinthOffIt intentionally modifies pages for bots; keep public redirect and policy pages deterministic
Block AI botsBlock on all pagesBlocks AI training crawlers across the zone without maintaining a custom user-agent rule list
Bot Fight ModeOn, default configurationThe Free-plan control is on/off; there are no per-rule options to tune
Browser Integrity CheckOn, default configurationBlocks malformed or suspicious browser requests before Worker code runs
Challenge Passage30 minutesKeeps managed challenges useful without making repeat legitimate visits too noisy
Cloudflare Managed Free RulesetOnCloudflare maintains and updates this free managed ruleset; it is generic baseline coverage, not vanityURLs-specific posture
Continuous script monitoringOff for the default instanceThe baseline uses same-origin, fingerprinted scripts with CSP and SRI. Enable inventory alerts only after intentionally adding third-party scripts
Custom fallthrough rulesNo rule by defaultOnly needed when you deliberately want a fallback rule for unmatched traffic
Email Address ObfuscationOffCloudflare rewrites matching email addresses and can inject helper code; keep generated pages, CSP, and SRI deterministic
HTTP DDoS attack protectionOn, always activeCloudflare-managed HTTP DDoS protection runs independently of the Worker
Manage your robots.txtDisable Cloudflare-managed robots.txt configurationThe repository ships defaults/public/robots.txt; keep the repo as the source of truth instead of letting Cloudflare replace it with Content Signals Policy output
Network-layer DDoS attack protectionOn, always activeBaseline network DDoS mitigation is handled at Cloudflare’s edge
Replace insecure JavaScript librariesOffThe baseline uses self-hosted, fingerprinted JavaScript with SRI; do not let Cloudflare rewrite script URLs or bytes unless you intentionally give up repo-owned hashes
Security levelLeave I’m Under Attack Mode disabledUse only for active incidents; it is too disruptive as a normal redirector baseline
Security.txtLeave Cloudflare dashboard Security.txt offThe repository generates and deploys /.well-known/security.txt; keep that file and the footer/security pages in one source of truth
SSL/TLS DDoS attack protectionOn, always activeTLS-layer DDoS mitigation is handled by Cloudflare
No-action security settings for a default redirector
SettingBaseline decision
Client certificatesDo not configure for the public redirector unless a future origin/API requires mTLS
Endpoint LabelsNo action; this belongs to API Shield endpoint organization, and the redirector does not expose an operator API
Hotlink ProtectionOff; shortener assets are small, and off-site image reuse is not product behavior
IP access rulesNo action; prefer precise custom rules or Cloudflare Access instead of broad IP rules
IP listsNo action unless custom WAF rules need reusable IP sets
Leaked Credentials DetectionOff unless the app later adds password login; vanityURLs does not authenticate visitors with passwords
mTLS rulesNo action for a Worker-only public redirector
Rate limit authentication requestsNo rule by default; private paths are protected by Cloudflare Access SSO, not a password endpoint on the redirector
Schema ValidationNo action unless explicit API schemas are added
User agent blockingNo rules by default; use it only for a specific aggressive client, and prefer managed bot controls or WAF rules first
Web asset discoveryNo action; leaving discovery visible is fine, but it does not change redirect behavior
Zone lockdownNo action on the Free baseline; Cloudflare documents Zone Lockdown as paid-plan only and recommends custom rules for allowlist-style behavior

Avoid extra visitor data and mTLS complexity

Do not enable client certificates, mTLS rules, visitor location headers, or True-Client-IP headers for the public shortener unless a downstream service explicitly needs them. The Worker already receives Cloudflare country and colo metadata for aggregate analytics.

Cloudflare moves dashboard labels regularly. Review the Cloudflare Docs changelog and product changelogs, especially Rules and bot controls, when refreshing this page. Use the raw capture in data/cloudflare-protection-defaults.json to compare menu labels over time.

Add WAF rules

In Cloudflare, open Domains > your short domain > Security > Security rules > Security rules. To add a custom rule, use Create rule or the Show all rule types menu, choose Custom rules, enter the rule name, click Edit expression, paste one expression, choose the action, then deploy. For rate limiting, use the Rate limiting rules row instead.

Cloudflare security rules run before the Worker. Use them for traffic that should never reach application code.

The expressions below use v8s.link and intentionally scope to the apex hostname. Redirect www.v8s.link to the apex before the Worker instead of adding www to every Worker, WAF, and rate-limit rule. A DNS CNAME alone aliases a hostname; it does not create an HTTP redirect by itself.

For the Free-plan rate limiting rule, use Rate limit short-link candidates as the rule name, IP as the characteristic, 20 requests per 10 seconds, Block as the action, 10 seconds as the duration, and First as the order. The expression excludes the /lookup page but not /lookup/resolve, so lookup resolution stays covered by the single available rate limiting rule.

RuleActionExpressionNotes
Rate limit short-link candidates
Rate limiting rule
Characteristic: IP
Threshold: 20 requests per 10 seconds
Action: Block
Duration: 10 seconds
Order: First
http.host eq "v8s.link" and
not cf.client.bot and
not starts_with(http.request.uri.path, "/_stats") and
not starts_with(http.request.uri.path, "/_tests") and
not starts_with(http.request.uri.path, "/_analytics") and
not http.request.uri.path in {"/" "/index" "/lookup" "/privacy" "/terms" "/abuse" "/security" "/404" "/expired" "/disabled" "/maintenance" "/security.txt" "/.well-known/security.txt" "/robots.txt" "/favicon.svg"} and
not lower(http.request.uri.path) contains ".css" and
not lower(http.request.uri.path) contains ".js" and
not lower(http.request.uri.path) contains ".png" and
not lower(http.request.uri.path) contains ".svg" and
not lower(http.request.uri.path) contains ".ico" and
not lower(http.request.uri.path) contains ".txt" and
not lower(http.request.uri.path) contains ".webmanifest" and
not lower(http.request.uri.path) contains ".woff"
Create this first. It counts likely short-link candidates and lookup resolution requests while excluding operator paths, policy pages, well-known files, the lookup page, analytics beacons, and static assets. On plans with only one rate limiting rule, use this rule as the baseline.
Rate limit lookup resolution
Rate limiting rule
Block for 60 seconds when the rate exceeds 30 requests per minute
http.host eq "v8s.link" and
http.request.method eq "POST" and
http.request.uri.path eq "/lookup/resolve" and
not cf.client.bot
`/lookup/resolve` is exact-match only and returns no list, but it can reveal destinations for guessed slugs. Add this tighter rule only when your Cloudflare plan allows multiple rate limiting rules.
Rate limit lookup analytics
Rate limiting rule
Block for 60 seconds when the rate exceeds 60 requests per minute
http.host eq "v8s.link" and
http.request.method eq "POST" and
http.request.uri.path eq "/_analytics/lookup" and
not cf.client.bot
Protects Umami/Fathom quota from direct beacon abuse. This endpoint does not resolve links; it only records lookup activity that reached the Worker.
Block scanner probes
Custom rule
Block
http.host eq "v8s.link" and (
  ends_with(lower(http.request.uri.path), ".php") or
  lower(http.request.uri.path) contains "/wp-content/" or
  lower(http.request.uri.path) contains "/wp-includes/" or
  lower(http.request.uri.path) contains "/wp-admin/" or
  lower(http.request.uri.path) contains "/wp-" or
  lower(http.request.uri.path) contains "wp-login.php" or
  lower(http.request.uri.path) contains "xmlrpc.php" or
  lower(http.request.uri.path) contains ".env" or
  lower(http.request.uri.path) contains "phpinfo" or
  lower(http.request.uri.path) contains "/vendor/" or
  lower(http.request.uri.path) contains "/.git" or
  lower(http.request.uri.path) contains "/cgi-bin/"
)
Blocks common PHP, WordPress, environment-file, dependency, Git, and CGI probes.
Block unexpected methods
Custom rule
Block
http.host eq "v8s.link" and
not http.request.method in {"GET" "HEAD" "OPTIONS"} and
not (
  http.request.method eq "POST" and
  http.request.uri.path in {"/lookup/resolve" "/_analytics/lookup"}
)
Allows only methods expected by the public redirect hostname, plus the two public lookup POST endpoints.
Challenge suspicious clients
Custom rule
Managed Challenge
http.host eq "v8s.link" and
not cf.client.bot and
not starts_with(http.request.uri.path, "/_stats") and
not starts_with(http.request.uri.path, "/_tests") and
(
  lower(http.user_agent) contains "curl" or
  lower(http.user_agent) contains "wget" or
  lower(http.user_agent) contains "python-requests" or
  lower(http.user_agent) contains "go-http-client" or
  lower(http.user_agent) contains "httpclient"
)
Challenges common script and HTTP-client user agents without challenging every ordinary non-verified browser.
Block unwanted AI crawlers
Custom rule
Block
http.host eq "v8s.link" and
http.request.uri.path ne "/robots.txt" and (
  lower(http.user_agent) contains "applebot" or
  lower(http.user_agent) contains "archive.org_bot" or
  lower(http.user_agent) contains "arquivo-web-crawler" or
  lower(http.user_agent) contains "bingbot" or
  lower(http.user_agent) contains "chatgpt-user" or
  lower(http.user_agent) contains "duckassistbot" or
  lower(http.user_agent) contains "googlebot" or
  lower(http.user_agent) contains "manus-user" or
  lower(http.user_agent) contains "meta-externalfetcher" or
  lower(http.user_agent) contains "mistralai-user" or
  lower(http.user_agent) contains "oai-searchbot" or
  lower(http.user_agent) contains "perplexity-user" or
  lower(http.user_agent) contains "perplexitybot" or
  lower(http.user_agent) contains "proratainc" or
  lower(http.user_agent) contains "terracotta"
)
Aggressive crawler blocklist. Remove search-engine crawlers such as `googlebot` and `bingbot` if public indexing matters.

Paste and validate one complete expression at a time. Deploy rules disabled while tuning if traffic is already flowing, then enable them after checking Security Events.

Lookup is public, not an inventory endpoint

The lookup page and /lookup/resolve endpoint intentionally let a visitor inspect one exact slug before clicking. They do not list links or autocomplete slugs, and the shipped X-Frame-Options: DENY plus frame-ancestors 'none' headers prevent clickjacking. The remaining risk is bulk guessing from scripts, so protect /lookup/resolve and /_analytics/lookup with explicit rate limits.

Decide crawler controls

In Cloudflare, use Domains > your short domain > AI Crawl Control for crawler-specific controls. This is separate from the broad Security > Settings > Block AI bots toggle covered earlier.

Use AI Crawl Control > Security to block named crawlers and configure the blocked-crawler response. If you use this page, set the block response allowed paths to:

  • /robots.txt
  • /llms.txt
  • /llms-full.txt
  • /.well-known/*

Leave /mcp and /ads.txt disabled unless the instance intentionally publishes those files. Keeping /.well-known/* allowed matters because vanityURLs publishes the security disclosure contact at /.well-known/security.txt.

Keep repository robots.txt authoritative

Use AI Crawl Control > Signals for crawler compliance monitoring. Leave Managed robots.txt off when the repository ships robots.txt; otherwise Cloudflare can replace the file seen at /robots.txt. The default vanityURLs file is:
User-agent: *
Disallow: /

Allow: /robots.txt
Allow: /llms.txt
Allow: /llms-full.txt
Disallow: /en/_stats/
Disallow: /*/_stats/
Disallow: /lookup/

The Signals page should show /robots.txt as reachable with 200 OK. Use Agent Readiness and Robots.txt violations as monitoring surfaces, not as the source of truth for the file content.

Configure Rules and URL normalization

In Cloudflare, open Domains > your short domain > Rules > Settings. Review Managed Transforms, Bulk Redirects, and URL Normalization.

Recommended Rules settings:

CategorySettingRecommendation
Managed TransformsRemove X-Powered-By response headersOn as defense-in-depth; Cloudflare does not appear to enable this by default, and vanityURLs does not intentionally emit X-Powered-By
Managed TransformsAdd visitor location headersOff; Umami and Fathom do not need city/latitude/longitude request headers from Cloudflare, and adding them increases location data exposure
Managed TransformsRemove visitor IP headersOff unless an origin behind the Worker receives them
Managed TransformsAdd security headers transformOff by default; vanityURLs owns headers in the Worker and repository _headers files, and Cloudflare’s broad transform adds a fixed header bundle that may not match the app policy
Bulk RedirectsBulk Redirect ListsNo action for Worker-based vanityURLs; useful for large static redirect lists, but they bypass the registry lifecycle, analytics, lookup pages, schedules, splats, and local publishing workflow
URL NormalizationURL normalization typeCloudflare
URL NormalizationNormalize incoming URLsOn, used by Access, WAF rules, and Workers
URL NormalizationNormalize URLs to originOff

Configure Network settings

In Cloudflare, open Domains > your short domain > Network.

Recommended Network settings:

SettingRecommendation
IPv6 CompatibilityOn
gRPCOff
WebSocketsOff unless a custom page requires them
Pseudo IPv4Off
IP GeolocationOn
Maximum Upload SizeLowest practical plan default
Network Error LoggingOn
Onion RoutingOn

Keep caching conservative

In Cloudflare, open Domains > your short domain > Caching > Configuration for general cache settings, then Caching > Cache Rules to confirm there are no cache rules.

Keep caching boring for a redirector:

  • Leave dynamic redirect decisions to the Worker
  • Let static assets under build/ use the Worker and asset headers
  • Keep Development Mode off except while actively debugging
  • Do not create Cache Rules or Cache Response Rules for the baseline
  • If any Cache Rules or Cache Response Rules exist, disable or delete them before go-live
Edit this page Last modified: