Replacing Netlify redirects and headers when self-hosting

Netlify's _redirects file and netlify.toml rules have no direct file equivalent on a self-hosted server, so the rules move to the reverse proxy in front of the site. This page maps each rule type to Traefik, Caddy or NGINX and names what to test before cutover.

On this page

How to replace Netlify redirects and headers on your own servers

A team moving a Netlify site to Coolify or Dokploy must keep its _redirects file and netlify.toml rules working, and those rules do not move into a file the new platform reads. They move into the reverse proxy in front of the site: Traefik or Caddy in Coolify, Traefik in Dokploy, or the NGINX configuration of a static container. Each Netlify rule therefore has to be re-expressed in proxy configuration, and the work is mostly inventory and testing rather than copying lines across. Start by listing every rule, including its status code, whether it is a forced redirect, how it matches paths and whether it uses splats or placeholders such as :splat and :id. Record which headers apply to which paths in netlify.toml, since Netlify scopes header rules by path pattern and a header meant for one folder can leak onto others if it is copied into a global block. Confirm each construct with the proxy's own documentation, because the syntax for wildcards, placeholders and rewrites differs between Traefik, Caddy and NGINX, and the Coolify proxy overview is the place to check how the default proxy is configured on your server.

Test the rules against the old site before cutover. Request every redirect source URL and confirm the status code, the destination and that a rewrite still serves the same content without changing the address. Check the headers returned for a sample of paths in each scope, including security headers and cache controls, and compare them with the Netlify responses. Keep a short list of rules that do not translate cleanly, such as conditional redirects by country or language or rules that depend on Netlify's own edge behavior, and decide whether each one is dropped, moved into the application or handled by a separate service. Do not assume one proxy covers every Netlify rule until your own test set passes. Ask your implementation partner or platform team to confirm three points before the change: where the proxy configuration lives on each server, how it is backed up and restored, and who approves a change to it. A rule set that exists only in a running container is easy to lose during an upgrade, so keep it in version control next to the site code.

Which proxy handles each Netlify redirect and header rule

This table maps each Netlify _redirects and netlify.toml rule type to the matching feature in Traefik, Caddy and NGINX. Read each row as a starting point, then check the notes against the proxy version your Coolify or Dokploy server actually runs. The main takeaway is that Traefik rules are expressed as labels and middleware, Caddy as site block directives, and NGINX as server and location blocks.

Netlify ruleTraefik (Coolify or Dokploy)Caddy (Coolify alternative)NGINX (static container)
301 and 302 redirectsRedirect middleware (redirectRegex or redirectScheme) attached through labels; confirm the permanent flag per versionredir directive in the site block with a 301 or 302 codereturn 301 or 302 inside a server or location block
200 rewrites to a pagereplacePath or replacePathRegex middleware on the router, so the same content serves under a new pathrewrite directive for internal path changestry_files fallback to index.html, or an internal location
200 proxies to another serviceRouter forwards to a separate service on the Docker network; confirm the target service name and portreverse_proxy directive to the upstream addressproxy_pass inside a location block with proxy_set_header lines
Splat wildcards (/news/*)PathRegex matcher with capture groups, reused in the redirectRegex replacementPath matcher with a regexp matcher; read captures as named placeholdersRegex location with numbered captures, referenced as $1 in return or rewrite
Named placeholders (:slug)Translate to named regex groups in the matcher; test each rule after deployNamed regexp captures read as placeholders; {path} and {query} are built inConvert to numbered captures; confirm named capture support in the NGINX build
Custom headers and cache controlheaders middleware with custom response headers, attached to the matched routerheader directive in the site block, scoped with a path matcheradd_header with the always flag, inside the matching location block
Trailing slash and path normalizationRedirect regex middleware for the slash rule; test that it does not redirect in a loopfile_server redirects directory paths to a trailing slash by default; confirm for your versionReview absolute_redirect and merge_slashes defaults; confirm them in your build
HTTPS redirectsEntry point redirection from web to websecure, or a redirectScheme middlewareAutomatic HTTPS redirects for hostnames the server managesSeparate port 80 server block returning 301 to the HTTPS address
Rule order and precedencePriorities set with router labels; confirm which rule wins when paths overlapDirective order within the site block decides the outcome; confirm with test requestsFirst matching location wins by modifier; confirm the order in the configuration

Traefik, Caddy or NGINX: which proxy fits which rule set

Traefik is the default reverse proxy Coolify runs in its coolify-proxy container on each server. For a small set of rules, such as a canonical host redirect, a few path redirects and a couple of security headers, it is usually the least work, because Coolify already routes domains and issues certificates. Rules are typically expressed as Traefik middlewares attached to a router, which you manage through Coolify's proxy configuration or dynamic configuration files on the server.

  • Small rule sets: A short list of exact-match redirects and header middlewares is easy to review in one place.
  • Large redirect lists: Thousands of entries as individual router labels become hard to read and diff. Consider generating a dynamic file from a source table, or moving lookups to the application.
  • Platform UI versus files: UI edits are quick and recorded per application, but a rule written in a server file may be overwritten or missed when the proxy is reconfigured. Decide which one is the source of truth.
  • Wildcards and placeholders: Traefik matching works with path and host rules and regular expressions. Confirm how Netlify placeholders such as :splat map to your expressions before cutover.
  • Ownership: Keep a copy of the proxy configuration under version control so a restore does not silently drop rules.

Before relying on any rule, test it against a staging domain and check the response codes and headers the browser actually receives.

Migrating Netlify redirect rules step by step

This sequence moves redirect and header rules from Netlify's configuration to the proxy in front of a self-hosted site, with each rule tested and cut over one domain at a time.

  1. Export the current redirect and header rules

    Pull the live _redirects file and the netlify.toml redirect and headers blocks from the repository that produced the currently deployed site, and confirm they match the deploy you are serving. Also check the Netlify dashboard for rules added outside the repository, such as domain-level redirects or header rules set in the UI, because those will not appear in the code. The output is a single inventory file that lists every source path, destination, status code and header, with the source noted for each entry.

  2. Sort rules by type and flag edge cases

    Group the inventory into exact-path redirects, wildcard or splat redirects, placeholder redirects, domain or host redirects, forced redirects, and header rules. Mark rules that depend on Netlify-specific behavior, such as country or language conditions, cookie conditions, or fallback rules that serve index.html for single-page apps, because each needs an explicit equivalent or a documented decision to drop it. The output is a sorted list with a column for the proxy mechanism you expect to use for each group.

  3. Write proxy equivalents in a staging application

    Create a staging application in Coolify or Dokploy from the same repository and write the matching rules in the proxy layer. Coolify runs Traefik by default or Caddy as an alternative, while Dokploy uses Traefik, so confirm which proxy your server runs before writing rules, and keep the Static site or NGINX configuration for rules the proxy cannot express cleanly. Store the proxy configuration files in version control next to the site code. The output is a staging build that serves the site on a test domain with all rules present.

  4. Test every rule with a scripted request set

    Write a script that sends a request for each inventory entry to the staging URL and checks the returned status code and the Location header against the expected value, plus the presence and value of each response header. Include negative cases, such as paths that should return the 404 page, and trailing-slash and query-string variants. Run the script against the production Netlify site first to confirm the expected values are what the live site actually returns. The output is a passing test report with any mismatches listed for correction before cutover.

  5. Version the proxy configuration separately

    Record the proxy configuration in its own versioned location and tag the version that passed testing. This matters because a rollback in Coolify redeploys the application image but does not change proxy rules, so a previous application image can run against new routing rules. Keep a dated record of which proxy configuration version each deployed image was tested with. The output is a tagged proxy configuration and a short runbook entry that states how to revert the proxy layer independently of the application.

  6. Cut over domain by domain

    Move one domain at a time by changing its DNS record to the self-hosted server, starting with a low-traffic domain or subdomain. Run the request script against the public hostname immediately after the change and watch error logs and analytics for unexpected 404 or redirect loops. Keep the Netlify site active until each domain has been verified, so you can point DNS back if a rule fails. The output is a verified domain with a logged cutover time and test result.

  7. Retire the Netlify rules after a stable period

    Once every domain has run on the self-hosted proxy and the logs show no unexplained requests, remove the _redirects and headers configuration from the active branch only after the team agrees on a retention period for the old files. Keep the exported inventory and test results in the documentation set, since auditors and future maintainers will ask how routing decisions were made. Confirm with the team how long the Netlify site should stay available before deletion. The output is a closed migration record with the final inventory, test results and cutover log.

Where wildcards, placeholders and large redirect sets break

Netlify's redirect and header rules are interpreted by Netlify's own edge, so moving them to a proxy changes matching behavior in small ways that rarely show up in a quick smoke test. The cards below cover the parallel risks that most often surface after cutover, and what to check for each before the site goes live.

Splat and placeholder syntax

Netlify's :splat and named placeholders such as :id do not map one to one onto the matching syntax of Traefik, Caddy or NGINX. Each proxy expresses capture groups, path variables and rewrite targets differently, so a rule that looks equivalent can capture the wrong segment or drop a trailing portion of the path. Check every wildcard rule against a list of real request paths, and confirm the capture and substitution syntax in the proxy documentation for your chosen version.

Rule order and first-match behavior

Netlify evaluates _redirects lines from top to bottom and applies the first match, so a specific rule placed above a catch-all wins. Proxies may evaluate routers by priority, by specificity or by file order, and a generic path rule can silently shadow a more specific one after migration. Ask each proxy how it orders competing matches, then write a test case for every pair of rules that overlap.

Large redirect lists at scale

Long redirect sets, often inherited from years of site restructuring, become slow to reload and hard to review when they are pasted into proxy configuration. Some teams keep them as one large file, others split them into generated fragments, and neither approach removes the need for review. Keep the source list under version control, generate the proxy configuration from it, and measure reload time and config size on the target server before cutover.

Header rules on unintended paths

A Netlify header rule with a broad path pattern can apply security or cache headers to assets, API routes or redirect responses that were never meant to receive them. When the same headers move into a proxy middleware or a site-level NGINX block, the scope often widens because the match defaults to the whole server. Compare the response headers for a sample of HTML, asset, redirect and error URLs before and after migration, and confirm that each header rule matches only the paths its original rule covered.

Trailing slashes and query strings

Netlify applies its own rules for trailing slashes and for whether query strings are forwarded or matched, and those defaults do not carry over automatically. A redirect from /blog to /articles may loop or miss when the proxy adds or strips a trailing slash, and a rule that ignores query strings in one environment may keep them in another. Write test requests with and without trailing slashes and with common tracking parameters, and confirm each proxy's normalization and query handling in its documentation.

Questions teams ask before moving Netlify redirects

How much effort does translating Netlify redirects into proxy rules take?

The effort depends mainly on how many rules exist, how many of them use splats and placeholders, and how many domains and subdomains the site serves. Start by exporting the _redirects file and the redirect and header blocks in netlify.toml, then count rules by type: exact paths, prefix rules, wildcard rules, status code overrides and forced rules. A short list of rules on one domain is a small job. A long list with many splat patterns spread across several domains takes longer because each pattern must be tested against the proxy's own syntax. Ask whether the rule inventory is part of the quote and whether it covers every domain the site uses.

Can our own engineers move Netlify redirects without outside help?

Often yes, if the team already runs containers and a reverse proxy. The work needs a working knowledge of HTTP status codes such as 301, 302 and 404 with a rewrite, how the proxy matches paths and hosts, how TLS is handled for each domain, and how to read access logs. Someone who has written Traefik labels or a Caddyfile, or NGINX location blocks, can translate most rules. Teams with no proxy experience usually take longer and risk subtle loops or cache problems. Be honest about who will own the config after go-live, since every later redirect change goes through the same files.

How long does testing redirects and headers take?

Testing time is set by the number of rules, the number of domains, and how many distinct request patterns must be checked. A good test set covers each exact rule, each splat or placeholder rule with a sample of matching paths, forced and non-forced behavior, query string handling, and trailing slash behavior. Each check should confirm the status code, the destination and the response headers. Plan extra time for a staging run against the real domain names, because DNS and certificate differences often show up only there. Ask a provider to describe its test cases and to show the results before cutover.

What should we ask a consultant for in a fixed-scope quote?

A fixed-scope quote should state the exact inputs and outputs. Ask for the number of rules and domains included, the proxy the work targets (for example Traefik or Caddy in Coolify, Traefik in Dokploy, or NGINX in a static container), and whether the inventory of existing Netlify rules is part of the work. Confirm the test cases and the environments used, whether the work includes staging and a cutover window, and what documentation is handed over. Ask what happens to changes requested after the scope is agreed. DeployOpen agrees scope, deliverables and timelines in writing before work starts, so ask for those items to be listed explicitly.

Do header and cache rules need a CDN after leaving Netlify?

Not necessarily. Security headers such as content security policy, cache control and frame options are set by the proxy or the web server, so a self-hosted site can serve them without a CDN. A CDN matters when you need edge caching across regions, lower latency for distant visitors, or DDoS absorption at the network edge. Without one, cache behavior depends on the origin server and on any cache headers the app sends. Confirm which headers Netlify currently sends from netlify.toml, decide which must stay, and check how each one reaches visitors once the site runs behind your own proxy.

What are the most common redirect mistakes during a move?

The most frequent problems are redirect loops caused by a forced rule that matches its own destination, wildcard rules that capture more paths than intended, and status codes that change from permanent to temporary without anyone noticing. Trailing slash differences and case sensitivity also cause missed matches. Check that rules are applied in the same order as on Netlify, because the first match often wins. Keep the old Netlify rule file in version control so each translated rule can be compared line by line during review and testing.

Should we keep the old Netlify rules during cutover?

Keep them until the new proxy has passed the agreed test set and the logs show the expected traffic. Running both during a short overlap helps catch missing rules, but it requires a clear rule for which system answers each domain at each moment. Record the old rule file, the new proxy configuration and the test results together, so the change can be reviewed or reversed. Confirm with the provider how a rollback is done and who approves it.

What stops working when Netlify's rule engine is gone

Moving off Netlify means rebuilding three behaviors that teams rarely write down: rule evaluation at the CDN edge, redirect handling tied to each deploy, and any routing that depended on Netlify Functions or Forms. Netlify evaluates _redirects and netlify.toml rules in its own platform before a request reaches your files, so a self-hosted site receives every request as-is unless the proxy in front of it applies the same logic. Start by exporting your current rules and classifying each one as a redirect, a header, a rewrite to a function, or a rule that only made sense on Netlify's build output.

Redirects that Netlify generated automatically also need a decision. Netlify tied some redirect and asset behavior to each deploy, so old URLs continued to resolve as a site was rebuilt. On a self-hosted server, a redirect exists only if you write it into the proxy configuration or the static container, and a redeploy does not carry it forward. Rules that pointed at /.netlify/functions/ paths or relied on Forms submissions cannot be translated into a proxy rule at all. Each of those paths needs a replacement service, and the replacement must be reachable from the same domain or the browser will break.

Caching and edge behavior depend on the server you choose and on any CDN placed in front of it. A Traefik or Caddy proxy in Coolify, the Traefik instance in Dokploy and an NGINX container for static files each set cache and security headers differently, and none of them reproduces Netlify's global edge network by default. Confirm in your own environment which headers reach the browser with a command such as curl -I, whether your DNS, TLS termination and any external CDN preserve those headers, and how long cached responses persist after a deploy. Ask your CDN provider and your operations team to sign off on these settings before cutover.

Keeping rules in step with the rest of the stack

Redirect and header rules do not work alone. They sit next to preview hostnames, certificates, form and function endpoints and the pipeline that deploys both. Each card below names one of those parts and a check to run before cutover.

Wildcard DNS for previews

Netlify deploy previews got their own hostnames without any DNS work from the team. In Coolify, preview deployments use a default {{pr_id}}.{{domain}} pattern that needs a wildcard DNS record pointing at the server. Without it, previews fail to resolve even when the redirect rules are correct. Check that a test pull request yields a resolving hostname, and confirm that the rules you copied also apply on that preview host, since path rules written for the production domain may not match.

Certificates issued by the proxy

On Netlify, certificates were handled by the platform. On a self-hosted server, Coolify's proxy, which runs Traefik by default or Caddy, handles HTTPS automatically, while the Custom (None) option leaves routing and TLS certificates to your team. Choose the proxy deliberately, then confirm the certificate is issued for every production and alias domain before the DNS change. A redirect rule that forces HTTPS does nothing if the certificate is missing.

Form and function endpoints

Redirect files sometimes point at Netlify Forms or Netlify Functions paths. Those endpoints do not move with the site, so a rewrite to a function path will return errors after cutover. List every rule whose target is not a static file, decide which service will receive the request, and test each one with a real POST or call. Forms that capture submissions need a replacement backend that stores them under your control.

Pipeline reloads the proxy

Netlify applied a new _redirects file on every deploy. On a self-hosted server, the rules live in the proxy configuration or in the static container's NGINX config, so a deploy that rebuilds only the app can leave the old rules in place. Make rule files part of the source repository and confirm that each deploy reloads or rebuilds the proxy or container. Test by changing one redirect in a branch and verifying the change is live after deploy.

Headers across environments

Security headers set in netlify.toml often differ between production, previews and staging. When the proxy or NGINX config is shared, a header meant for production can reach preview hosts, or the reverse. Define header sets per environment in version control, then compare the response headers from production and one preview with a request tool. Confirm that cache rules for HTML, assets and redirect responses match what the old platform served.

Rollback and config backups

Coolify's guide for teams coming from managed platforms notes that a rollback can redeploy a retained application image, but it does not restore databases or persistent files. Proxy and rule config is not covered by an app rollback either, so a bad redirect can stay live after the site returns to its previous image. Keep the rule files in Git with tags for each release, and rehearse restoring the prior rule set once before go-live.

How DeployOpen scopes and delivers a redirect and header migration

DeployOpen plans, implements, hardens, documents and hands over self-hosted platforms inside your own infrastructure. For a Netlify redirect and header migration, we start by inventorying the rules you already rely on, then rebuild them at the proxy in front of your self-hosted site and test each one before cutover.

How we scope

  • Inventory every _redirects line and netlify.toml header or redirect rule currently serving production traffic
  • Agree in writing which proxy handles routing, such as Traefik or Caddy in Coolify, Traefik in Dokploy or NGINX in a static container
  • Confirm wildcard, placeholder and splat patterns, redirect volume and any rules that depend on Netlify-specific behavior

How we build

  • Translate rules into proxy configuration and keep the mapping from each original rule to its replacement
  • Test redirect chains, status codes, cache and security headers against staging before any DNS change
  • Check large redirect sets for loops, conflicting patterns and ordering problems that change behavior in production

How we hand over

  • Deliver a rule-by-rule document that shows the source rule, the new configuration and the test that verifies it
  • Provide version-controlled proxy configuration and a rollback procedure for the redirect layer
  • Walk your team through how to add, change and test redirects after the engagement closes

How we support

  • Support is available as a retainer for upgrades, configuration changes and proxy maintenance after go-live
  • Re-run the redirect and header test set after platform upgrades or new site releases
  • Confirm with us during scoping which compliance evidence, such as configuration records, your auditors will need

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.