Origin servers often handle URL redirects in .htaccess, PHP scripts used only for simple rewrites, or application code that sets security headers. Suitable redirects, rewrites, and static header policies can instead be handled closer to visitors. Cloudflare Workers and BunnyCDN Edge Rules let you run logic on edge nodes around the world, so decisions are made before the request even hits your VPS or dedicated server. This can reduce latency and origin work, but a rewritten request may still need an origin response.
This guide covers internal URL rewrites, browser redirects, security headers and small edge functions. It distinguishes Cloudflare Workers, BunnyCDN Edge Rules and Bunny’s separate Middleware product. Updated 4 November 2026: the examples follow the current provider documentation. Replace example hostnames with your own; using both CDNs in series is not required.
What Does Running Logic at the Edge Really Mean?
“The edge” simply means servers that are geographically close to your visitors. A CDN like Cloudflare or BunnyCDN operates many PoPs (points of presence) worldwide. Caching and serving static files is a traditional CDN role. Today, they can also execute logic before forwarding a request to your origin or before sending a response back to the browser.
Instead of asking your PHP application or Nginx/Apache to handle every redirect, header, or micro-decision, you can move that logic to the CDN. The benefits are clear:
- Lower latency: Edge-generated redirects avoid an origin round trip. Rewrites change the upstream request but may still require an origin fetch.
- Less origin load: Requests answered entirely at the edge do not reach your VPS or dedicated server, leaving more capacity for application work.
- Simpler application code: Migrated rules can replace corresponding origin rules and glue scripts once their behaviour is validated.
- Central control: Rules live in one edge layer instead of being duplicated across multiple app servers.
If you already use a CDN, audit how the proposed edge logic interacts with its cache. Our CDN caching playbook for WordPress and WooCommerce provides related examples; fully dynamic responses still require their own privacy and cache policy.
Cloudflare Workers vs BunnyCDN Edge Rules: The Mental Model
Cloudflare Workers and BunnyCDN Edge Rules both live at the edge, but they occupy different layers of complexity.
- Cloudflare Workers: A programmable runtime for request/response handling, subject to platform limits.
- BunnyCDN Edge Rules: A configured set of supported conditions and actions. Change Origin URL, Redirect to URL and Set Response Header are distinct actions.
- Bunny Middleware: A separate programmable option for transformations such as the scoped SPA mapping below; it is not a text field in an Edge Rule.
Cloudflare Workers in Practice
The examples use the current ES module format. Each block is a separate Worker, not another default export to paste into one file. Use a Worker Route in front of an existing origin, with an active zone and proxied DNS record, and verify the origin TLS connection. Custom Domains and workers.dev are different deployment contexts. This first example maps GET/HEAD requests on www.example.com/blog and /blog/... to /articles; it does not match /blogger.
export default {
async fetch(request) {
const url = new URL(request.url);
const pageMethod = request.method === 'GET' || request.method === 'HEAD';
if (url.hostname === 'www.example.com' && pageMethod &&
(url.pathname === '/blog' || url.pathname.startsWith('/blog/'))) {
url.pathname = '/articles' + url.pathname.slice('/blog'.length);
}
return fetch(new Request(url.toString(), new Request(request, {
redirect: 'manual'
})));
}
};
The browser keeps its original URL, and the origin must serve the mapped path. The Request constructor preserves the incoming method and headers; manual redirect handling avoids automatically forwarding credentials to an upstream redirect destination. This code does not force caching. Beyond this rewrite example, Workers can:
- Rewrite URLs or route requests based on cookies, headers, or geo-IP.
- Generate responses entirely at the edge (for example, a maintenance page).
- Inject or modify headers on both the request and response.
- Implement lightweight authentication or feature flags at the edge. Authentication protects the origin only if requests cannot bypass that enforcement.
BunnyCDN Edge Rules in Practice
BunnyCDN Edge Rules are configured in the dashboard. Instead of code, you define conditions and actions through a UI. Some typical conditions:
- Match a documented Request URL pattern such as
*://www.example.com/blog/*; the hostname boundary matters. - Combine Country Code, Request Method, Request Header or Cookie Value conditions where supported.
- Match file extensions such as
jpg,pngandwebpwithout inventing an empty-extension rule. - Use the documented
pattern:Lua syntax when structured matching is needed; it is not a PCRE engine or proof that$1is available in targets.
And actions might include:
- Force SSL for HTTP→HTTPS; Redirect to URL for browser navigation.
- Change Origin URL for upstream routing, which runs when an origin request is needed.
- Set Response Header / Set Request Header for distinct header operations.
- Cache duration overrides or Block Request within the selected conditions.
Edge Rules are ideal for teams who want strong control but prefer configuration over code. For advanced behaviour (custom logic, third-party APIs, complex routing), consider a programmable edge runtime such as Cloudflare Workers.
URL Rewrites and Redirects at the Edge
Let us start with the most common and impactful use case: URL rewrites and redirects. These usually live in .htaccess, Nginx config, or even in application routes. Moving them to the edge can avoid origin round trips for redirects and simplify origin configuration; rewrites may still fetch content from the origin.
Common Rewrite and Redirect Scenarios
- HTTP to HTTPS: Force all visitors to use secure URLs.
- www to non-www (or the opposite): Canonicalize hosts for SEO and simplicity.
- Legacy URL migrations: Redirect
/old-blog/post-nameto/blog/post-nameafter a site restructure. - Language-specific paths: Offer
/en/,/de/, or/tr/paths based on language preference. Country can be a fallback hint, but should not override an explicit language choice. - Clean URLs for SPAs: Rewrite application routes under
/app/*to/app/index.htmlwhile keeping the original path in the browser, excluding asset and API requests.
A redirect returns a 3xx response with Location; the browser then makes another request. An internal rewrite changes the upstream request without changing the browser address. Neither approach automatically keeps canonical tags, sitemaps or incoming links consistent.
URL Redirect Example with Cloudflare Workers
This separate Worker combines HTTPS, a fixed canonical hostname and the legacy path change into one final destination. It is restricted to GET/HEAD page requests on example.com and www.example.com, using standard HTTPS port 443. Non-page HTTP methods and other hostnames pass through; do not use this as a general API redirect policy. Configure matching Routes and TLS for both hostnames.
export default {
async fetch(request) {
const source = new URL(request.url);
const hosts = new Set(['example.com', 'www.example.com']);
if (!hosts.has(source.hostname) ||
!['GET', 'HEAD'].includes(request.method)) {
return fetch(request);
}
const target = new URL(source);
target.protocol = 'https:';
target.hostname = 'example.com';
target.port = '';
if (target.pathname === '/old-blog') {
target.pathname = '/blog';
} else if (target.pathname.startsWith('/old-blog/')) {
target.pathname = '/blog/' + target.pathname.slice('/old-blog/'.length);
}
if (target.href !== source.href) {
return Response.redirect(target.href, 301);
}
return fetch(request);
}
};
For example, http://www.example.com/old-blog/post?x=1 receives one 301 to https://example.com/blog/post?x=1. The origin is contacted only if the subsequent final request needs it. For POST or other methods, separately decide whether a method-preserving 307/308 is required; do not silently reuse this page-only policy.
URL Rewrite and Redirect Examples with BunnyCDN Edge Rules
Bunny’s trigger matching and variable reference provide the following supported migration approach:
- Canonical hostname/HTTPS: Force SSL handles HTTP→HTTPS. If several URL components change, design an explicit final Redirect to URL target and inspect its interaction with Force SSL to avoid an extra hop.
- Legacy blog path: Match Request URL
*://www.example.com/old-blog/*together with Request Method GET/HEAD. Use Redirect to URL, status 301, targethttps://www.example.com/blog/%{Path.1-}./old-blog/post?x=1becomes/blog/post?x=1. The Path collection removes the first segment; the docs retain query data when the extracted path does not change the filename. Do not append the query twice. Define/old-blogand/old-blog/root targets separately and test empty suffixes/trailing slashes. A prefix condition does not create a$1capture. - SPA routes: Use the separate Bunny Middleware example below for an explicit list of page routes. Deploy it as an Edge Script attached to the Pull Zone, and enable Run script before cache under General → Origin. Without that setting,
onClientRequestdoes not run. TheservePullZoneURL is for local development; production uses the Pull Zone origin.
import * as BunnySDK from '@bunny.net/edgescript-sdk@0.13.0';
const pagePaths = new Set(['/app/', '/app/dashboard', '/app/settings']);
function mapSpaRequest(request: Request): Request {
const url = new URL(request.url);
if (url.hostname === 'www.example.com' &&
['GET', 'HEAD'].includes(request.method) && pagePaths.has(url.pathname)) {
url.pathname = '/app/index.html';
return new Request(url.toString(), request);
}
return request;
}
BunnySDK.net.http
.servePullZone({ url: 'https://origin.example.com' })
.onClientRequest((ctx) => mapSpaRequest(ctx.request));
Only the three listed GET/HEAD routes are rewritten. API paths, assets, POST and unknown pages remain unchanged, preserving genuine missing-file responses instead of returning HTML with status 200. Version the route list with the application. This mapping happens before cache lookup, so it affects the cache identity; the shared HTML shell must not contain personal data.
Bunny OrderIndex is processed from smaller to larger values. Redirect and origin-selection actions use the first applicable action of their type; multiple header actions can run. A high-priority exception is not a universal skip for all subsequent actions. Keep sensitive exclusions explicit, and verify both cache HIT and MISS paths.
Security Headers from the Edge Instead of the Origin
Static HTTP security header policies can also be managed at the edge. Headers such as HSTS, CSP, X-Frame-Options, and Referrer-Policy need appropriate scope and values, rather than identical treatment on every response. Policies that depend on application-generated content, such as a CSP using per-response nonces, require coordination with the application. The edge can attach them after the origin responds, or even for fully cached content without hitting the origin at all.
Our HTTP security headers guide provides background; the applicable policy still depends on your resources, framing requirements and HTTPS coverage.
Which Headers Make Sense at the Edge?
Most purely declarative headers are excellent candidates for edge injection:
- Strict-Transport-Security (HSTS)
- Content-Security-Policy (CSP) – for many static patterns
- X-Frame-Options
- X-Content-Type-Options
- Referrer-Policy
- Permissions-Policy
Application-generated CSP nonces, per-page policies and authentication cookies need application coordination. There is no universal percentage of headers that should move to the edge. An edge setter applied after origin processing may overwrite the origin header; the origin does not automatically override a broader edge policy.
Setting Security Headers with a Cloudflare Worker
This independent Worker adds missing headers while preserving existing policies. Before using SAMEORIGIN, confirm that the HTML must not be embedded by other origins. It uses a short initial HSTS lifetime on HTTPS and does not add includeSubDomains or preload. It is an HTTP response example, not a WebSocket proxy.
export default {
async fetch(request) {
if (request.headers.has('Upgrade')) return fetch(request);
const response = await fetch(new Request(request, { redirect: 'manual' }));
const result = new Response(response.body, response);
const headers = result.headers;
if (new URL(request.url).protocol === 'https:' &&
!headers.has('Strict-Transport-Security')) {
headers.set('Strict-Transport-Security', 'max-age=300');
}
if ((headers.get('Content-Type') || '').toLowerCase().includes('text/html')) {
if (!headers.has('X-Content-Type-Options')) {
headers.set('X-Content-Type-Options', 'nosniff');
}
if (!headers.has('Referrer-Policy')) {
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
}
if (!headers.has('X-Frame-Options') && !headers.has('Content-Security-Policy')) {
headers.set('X-Frame-Options', 'SAMEORIGIN');
}
}
return result;
}
};
The example leaves an existing CSP untouched. To develop a new policy, use Report-Only with an operational reporting endpoint and its report-to binding; Report-Only does not enforce blocking. Nonces and hashes must match the HTML. Expand HSTS coverage only after verifying HTTPS on every affected hostname.
If you are also using Cloudflare’s security features, you can combine this with WAF and bot protection as described in our Cloudflare security settings guide for WAF, rate limiting and bots. The Worker handles headers, while the WAF blocks malicious traffic before it reaches your application.
Setting Security Headers with BunnyCDN Edge Rules
BunnyCDN Edge Rules make header injection even simpler for straightforward setups. A common pattern:
- Create a Set Response Header action with one header name and one value; use separate actions for different headers.
- For HTML-specific policy, use a Response Header condition on
Content-Typecontainingtext/html. Restrict HSTS to HTTPS responses on HTTPS-ready hosts. - Example values after application review:
Strict-Transport-Security: max-age=300,X-Frame-Options: SAMEORIGIN,X-Content-Type-Options: nosniff, andReferrer-Policy: strict-origin-when-cross-origin. - Check the final headers on HIT, MISS and error responses; avoid duplicate or conflicting policies.
Keep nonce-based CSP or other content-dependent policies under application control, or explicitly coordinate the edge implementation. Header processing still consumes work somewhere; its main benefit here is consistent deployment, not a guaranteed measurable CPU reduction.
Offloading Simple Logic from Your Origin Server
Beyond rewrites and headers, there is a wide range of “small but useful” logic that fits naturally at the edge. Moving this code away from the origin helps you keep your VPS or dedicated server focused on running the main application and database.
Edge-Friendly Logic Examples
- Maintenance: A scoped 503 response with Retry-After and no-store.
- Region selection: A user-selected endpoint or suggestion, with explicit language choices taking priority over GeoIP.
- A/B assignment: Stable assignment across requests and a cache policy that cannot mix variants or users.
- Static configuration endpoints: Only genuinely public, non-personal responses with an appropriate expiry.
- Supplemental access checks: Referrer and User-Agent are spoofable and cannot establish identity. Close direct-origin bypasses and retain proper authentication.
Cloudflare Workers provide code for these decisions. Bunny Edge Rules cover supported conditions/actions, while Bunny Middleware offers custom code. Access checks in an origin-only middleware hook do not protect cache hits; use the documented before-cache/client hook when every request needs verification.
Maintenance Mode with Cloudflare Workers
This separate Worker reads a string environment variable named MAINTENANCE. Set it to true for the planned scope and restore it when work is complete:
export default {
async fetch(request, env) {
if (env.MAINTENANCE === 'true') {
return new Response(request.method === 'HEAD' ? null :
'<!doctype html><title>Maintenance</title><h1>We will be back soon</h1>', {
status: 503,
headers: {
'Content-Type': 'text/html; charset=utf-8',
'Retry-After': '300',
'Cache-Control': 'no-store'
}
});
}
return fetch(request);
}
};
Only requests reaching this Worker are affected. The flag does not stop direct origin traffic, scheduled jobs or in-flight writes. Plan database safety and any webhook/health-check exceptions separately. Purge any previously cached maintenance response, and ensure no outer cache can serve a stale Worker result instead of executing the current code.
Country Signals Without Forcing a Language
Bunny exposes a Country Code condition and %{User.CountryCode} in supported variable fields. Country is an estimate and does not prove a language preference. Prefer visible language links and a chooser; do not redirect visitors away from an explicitly selected locale.
- For an explicit regional-choice endpoint, combine an exact Request URL, GET/HEAD and Country Code condition with a 302 to a fixed locale landing page.
- If a deliberately designed cross-host rule must preserve a path and query, the documented variable is
{{path}}or%{Request.Path}, not$path. Restrict the source hostname/path to prevent loops. - Do not share country- or cookie-dependent redirects in cache. A country-vary setting changes cache behavior and purge options, so inspect the active zone configuration.
Or you might block traffic from certain regions from accessing an admin path:
- For supplemental admin restrictions, match the exact admin root and its slash-delimited subtree, not unrelated prefixes such as
/administrator-help. - Combine URL and country conditions with AND and use the documented Block Request action. Verify the actual response; IP or country blocking does not replace authentication.
Inside Cloudflare Workers, use request.cf?.country rather than assuming a client-visible CF-IPCountry header is always available. The origin header depends on IP Geolocation/location-header settings; dashboard/Playground previews may lack request.cf. Missing or unknown metadata should leave the user at a neutral chooser, not cause an exception or forced locale.
What Should Stay on the Origin?
Not everything belongs at the edge. In general, keep the following on your origin:
- Keep cart, account, permission and transaction decisions with a properly designed authoritative data layer.
- Place heavy computation where the chosen service supports the workload and its limits.
- Treat pricing, discounts and licensing as business rules requiring trusted state and clear ownership.
The edge is best for fast, stateless, request/response adjustments. While Cloudflare Workers can make external API calls and even maintain durable state, that is usually a later stage of maturity. Start by extracting clearly isolated logic (rewrites, headers, simple blocks) and scale from there.
Designing an Edge Logic Strategy for a Site Hosted on dchost.com
A possible architecture separates three responsibilities. It is not a claim that any particular hosting plan includes a managed CDN or edge deployment service:
- Layer 1 – DNS and CDN: Cloudflare or BunnyCDN in front, handling TLS termination, caching, and edge logic.
- Layer 2 – Origin web stack: Nginx or Apache, PHP-FPM or Node.js, running on a tuned VPS or dedicated server.
- Layer 3 – Data and background jobs: MariaDB/MySQL/PostgreSQL, Redis, and background workers.
This aligns well with other patterns we describe, such as building a robust CDN caching and edge rules strategy or using GeoDNS and multi-region hosting architectures for low latency. Edge logic simply becomes part of the first layer.
Step-by-Step Rollout Plan
- Inventory existing logic:
- Collect redirects from .htaccess, Nginx configs, and application code.
- List all security headers currently sent by your app or server.
- Identify small PHP or Node.js scripts that mostly do “glue” work.
- Classify what can move to the edge:
- Redirects and host/HTTPS canonicalization – edge-friendly.
- Static security headers – great at the edge.
- Small utility endpoints that rarely change – possible Worker candidates.
- Decide on the tool per task:
- Use BunnyCDN Edge Rules for straightforward redirects, header injection and access control.
- Use Cloudflare Workers when you need real logic, conditions or external calls.
- Roll out gradually:
- Start with non-critical paths (for example, old URL redirects).
- Monitor logs and error rates at the origin to ensure nothing breaks.
- Once stable, remove the equivalent rules from your origin configs.
- Document and version control:
- Keep Worker scripts in Git alongside your application.
- Export or document BunnyCDN Edge Rules so they can be recreated if needed.
The edge rules may remain during a hosting migration, but origin addresses, TLS, Host handling, access restrictions, data transfer and cache invalidation still require testing. Preserve the prior code and rules so a controlled rollback is possible.
When Not to Use Edge Logic: Pitfalls and Limits
Edge logic is powerful, but there are some pitfalls to avoid:
- Ownership: Document which layer changes each URL or header; avoid contradictory redirects and duplicate CSP.
- Cache identity: Cloudflare zone Cache Rules see the Worker fetch URL. A rewrite must preserve distinctions such as route, slug and language. An outer Workers Cache can bypass execution; include it in the design.
- Bunny cache settings: Vary Cache controls supported query/hostname/cookie/header variants separately from Edge Rule actions. The documentation contains conflicting descriptions of query defaults and some header-vary availability, so verify the actual Pull Zone rather than assuming a default.
- Private responses: Do not ignore Authorization or session cookies to improve HIT rate. Bypass shared caching for personal responses and purge old copies. Bunny’s documented Override Cache Time=0 caveat means a duration change alone is not proof that an existing cached copy disappeared.
- Portability and access: CDN-specific syntax needs migration work. Edge checks do not protect a publicly reachable origin on their own; retain a verified origin access boundary.
- Consistency: A per-instance global counter is not a globally consistent rate limiter. Use appropriate stateful services and do not put account balances in transient edge memory.
Test two users and two content variants through both cold and warm cache paths. Keep passwords, Authorization, cookies and sensitive query values out of logs. TTL alone does not imply stale-while-revalidate or stale-if-error support; verify the selected product/API. For background, see HTTP cache control and origin hardening and WAF.
Before Publishing Edge Changes
Check hostname/path/method boundaries, one-hop final redirects, retained query parameters and genuine 404/503 responses. Verify canonical tags, hreflang, sitemap entries and internal links against the public URLs. Unknown SPA routes and missing assets must not become generic 200 HTML pages.
Measure origin request count, HIT/MISS, latency and errors before and after rollout. Redirects or responses generated entirely at the edge can avoid an origin request; rewriting a URL or attaching headers may still require it. Size the remaining application and database workload using those measurements.
Document the final rule order, application assumptions and rollback procedure. Keep your origin and edge configurations in version control, and recheck them whenever either the application or CDN changes.





