SHORT ANSWER
When the new site runs on Apache or nginx rather than a hosted platform, the redirect map becomes server configuration: a Redirect 301 line per row in .htaccess, or a map block in nginx that turns each old path into its target. Both are generated from the two-column csv with a single command, wildcard rows translate into a regular expression with $1, and the whole thing can be tested against the old url list before dns is switched.
Which file do I start from?
In Silentfrog, pick apache · .htaccess or nginx · map file under for in the export and the download is already this file: one RedirectMatch line or one map entry per redirect, anchored, dots escaped, exact rows first and directory rules last. Pages that kept their url, rows still unmatched and unverified needs-review rows are left out of it, so nothing gets imported that nobody looked at (the two downloads). The rest of this page says what is in the file and how the import behaves, and it works just as well for a two-column csv of path pairs from anywhere else.
The generic csv next to it is the audit trail: absolute urls, confidence, match type, the unmatched rows with an empty target. Keep it with the project, do not import it.
site settings → publishing → 301 redirects, or the data api
the two export buttons — webflow csv and generic csv — next to the option that includes needs-review matches.
Apache: .htaccess
For a path-pair csv from anywhere else, one awk call produces what Silentfrog’s apache format writes directly:
tail -n +2 redirects-webflow.csv \
| awk -F, '
$1 ~ /\(\.\*\)/ { t=$2; gsub(/%1/, "$1", t); print "RedirectMatch 301 ^" $1 "/?$ " t; next }
{ print "RedirectMatch 301 ^" $1 "/?$ " $2 }
' > redirects.confWhich produces:
RedirectMatch 301 ^/ueber-uns/?$ /unternehmen RedirectMatch 301 ^/produkte/seitenschneider/?$ /produkte/seitenschneider-vde RedirectMatch 301 ^/blog/(.*)/?$ /magazin/$1
RedirectMatch with ^ and /?$ is used for every row on purpose: it matches the path exactly, with or without a trailing slash, and it never matches a prefix by accident. Plain Redirect 301 /blog /magazin would also catch /blog-archive and rewrite everything under /blog/, which is sometimes what you want and usually not.
Order still matters between an exact rule and a wildcard for the same folder, because the first matching rule wins. Silentfrog writes wildcard rows first and leaves out the rows they cover, so for Apache reverse that: exact rows first, wildcards last. A path with a dot, such as /pricing.html, needs the dot escaped in the expression; add gsub(/\\./, "\\\\.", $1) before the print if you have them. Put the file’s contents above the # BEGIN WordPress block if there is one, or Include it from the virtual host, which is faster than .htaccess.
nginx: a map
nginx has no per-line redirect directive that scales; the idiom is a map from the request path to a target, and a single if that returns 301 when the map produced something. The map file is what Silentfrog’s nginx format writes; from any other csv, the same awk call makes it:
tail -n +2 redirects-webflow.csv \
| awk -F, '
$1 ~ /\(\.\*\)/ { t=$2; gsub(/%1/, "$1", t); print " ~^" $1 "/?$ " t ";"; next }
{ print " ~^" $1 "/?$ " $2 ";" }
' > redirects.map# in the http context
map $uri $redirect_target {
default "";
include /etc/nginx/redirects.map;
}
# in the server block, before other locations
if ($redirect_target) {
return 301 $redirect_target;
}Entries starting with ~ are regular expressions, evaluated in file order; keep exact rows above the wildcard rows for the same reason as on Apache. If none of your rows are wildcards, drop the ~^ and /?$ and let the map use plain string keys, which is faster and needs no escaping. The if is the one case where if in a server block is safe: it only returns.
The map matches $uri, which has no query string, so /old?utm_source=x is redirected like /old. Urls whose identity lived in the query, /page?id=417, need a rule on $request_uri instead.
Testing before dns moves
- Check the syntax:
apachectl configtestornginx -t. - Request one url of each kind against the new server with the old host name:
curl -sI -H "Host: www.example.com" http://NEW_SERVER_IP/ueber-uns/ | head -3
The first line should be301, theLocationheader the final https url, not an http one that then upgrades. - Crawl the whole old url list the same way: one 301, then 200, for every row. A second 301 is a chain; a 404 at the end is a target that does not exist.
- Keep the rules for at least a year after the switch.
EXAMPLE
the test crawl shows every url answering 301 to http://… and then a second 301 to https://…. The redirect target in the map is a path, and the server’s http listener answers first. Fix: make the redirects absolute with the https host, or terminate https before the redirect block.
In short
- Pick apache or nginx in the export; from any other csv, each row is one rule and the header is skipped.
- Apache: RedirectMatch with ^ and /?$ for every row, wildcards with (.*) and $1.
- nginx: a map from $uri to the target, included from a generated file, and one if that returns 301.
- Exact rules above wildcard rules; escape dots in paths.
- Test with curl and a Host header, then crawl the old list, before dns changes.