Report 20: URL Rewriting & Redirects Guide¶
Status: Reference — operational guide for content editors and developers
Overview¶
The v17 platform manages URL rewriting and redirects through two complementary systems:
- URL Rewrites — Database-driven regex rules via the
ProgressUrlRewritestable, managed through a custom backoffice dashboard - URL Redirects — Managed via the Skybrud.Umbraco.Redirects package with a full backoffice UI
Legacy IIS rewrite rules from v8 web.config files are automatically extracted and imported during migration.
Architecture¶
URL Rewrites (Server-Side — Browser URL Unchanged)¶
| Component | Purpose |
|---|---|
DynamicUrlRewriteMiddleware |
Processes DB-backed rewrite rules on every request |
ProgressUrlRewriteService |
CRUD operations for the ProgressUrlRewrites table |
ProgressUrlRewriteApiController |
REST API for the backoffice dashboard |
ProgressUrlRewrites table |
Stores regex pattern/replacement pairs with sort order and enabled flag |
How it works:
- On each request, the middleware loads enabled rules from the database (cached in memory for 5 minutes)
- The request path is matched against each rule's regex pattern in sort order
- First match wins — the path is rewritten server-side (the browser URL does not change)
- Static file extensions (.css, .js, .png, etc.) and
/umbracopaths are skipped automatically
URL Redirects (301/302 — Browser URL Changes)¶
Redirects are managed via Skybrud.Umbraco.Redirects, which provides:
- Full backoffice UI under the "Redirects" section
- Support for 301 (permanent) and 302 (temporary) redirects
- Regex pattern support
- Query string handling
SEO URL Rules (Built-In)¶
The SeoRedirectMiddleware enforces two canonical URL rules automatically via 301 redirects:
| Rule | Example | Notes |
|---|---|---|
| Trailing slash removal | /loans/ → /loans |
All paths except root / |
| Lowercase enforcement | /About-Us → /about-us |
Case-insensitive matching |
These rules are built-in, always active, and not configurable. Static file paths and /umbraco paths are excluded.
Migration from v8¶
During migration, legacy IIS rewrite rules from web.config are automatically handled:
| v8 Rule Type | v17 Destination | Import Method |
|---|---|---|
<action type="Rewrite"> |
ProgressUrlRewrites table |
Auto-imported via /api/progress-url-rewrite/import-webconfig |
<action type="Redirect"> |
Skybrud.Umbraco.Redirects | Not auto-imported (redirects managed separately) |
| Trailing slash / lowercase | SeoRedirectMiddleware |
Built-in, no migration needed |
| HTTP→HTTPS, WWW redirect | Infrastructure (reverse proxy) | Not application-level |
Disabled rules (enabled="false") |
Skipped | Not imported |
IIS capture group syntax ({R:1}) is automatically translated to .NET regex syntax ($1).
How to Add New Redirects (Content Editors)¶
- Log in to the Umbraco backoffice
- Navigate to the Redirects section (provided by Skybrud.Umbraco.Redirects)
- Click Add redirect
- Enter the original URL (the old path visitors might use)
- Select the destination (a content node or external URL)
- Choose the redirect type: 301 (permanent) or 302 (temporary)
- Save
The redirect takes effect immediately — no restart or cache clear needed.
How to Add New Rewrites (Content Editors / Developers)¶
Rewrites are managed via the custom backoffice dashboard or the REST API.
Via REST API¶
List all rules:
Add or update a rule:
POST /api/progress-url-rewrite/rules
Content-Type: application/json
{
"key": "00000000-0000-0000-0000-000000000000",
"name": "Legacy loans page",
"pattern": "^old-loans/?$",
"replacement": "loans",
"enabled": true,
"sortOrder": 10
}
Set key to 00000000-0000-0000-0000-000000000000 for new rules (a GUID will be auto-assigned).
Delete a rule:
Toggle enabled/disabled:
Test a URL against current rules:
Import v8 web.config rules:
POST /api/progress-url-rewrite/import-webconfig
Content-Type: application/json
{
"xml": "<configuration>...<rewrite><rules>...</rules></rewrite>...</configuration>",
"clearExisting": false
}
Cache Behaviour¶
- Rules are cached in memory for 5 minutes after first load
- All write operations (save, delete, toggle, import) automatically invalidate the cache
- Changes take effect on the next request after cache invalidation
Common Patterns¶
News Category Rewrite¶
v8 Web.config:
<rule name="Rewrite news category url" stopProcessing="true">
<match url="^news/category/(.*)/?$" />
<action type="Rewrite" url="news?newsCategory={R:1}" />
</rule>
v17 ProgressUrlRewrites table:
| Name | Pattern | Replacement |
|---|---|---|
| News category rewrite | ^news-events/category/(.*)/?$ |
news-events?newsCategory=$1 |
SPA History-Mode Routes¶
For single-page applications (e.g., loan enquiry form) that use client-side routing:
| Name | Pattern | Replacement |
|---|---|---|
| Loan enquiry SPA | ^(loan-enquiry)/(.+)$ |
$1 |
Simple Page Rename¶
| Name | Pattern | Replacement |
|---|---|---|
| Old services page | ^old-services/?$ |
services |
Rules That Don't Need Migration¶
| Rule | Reason |
|---|---|
| Remove trailing slash | Built-in (SeoRedirectMiddleware) |
| Lowercase URLs | Built-in (SeoRedirectMiddleware) |
| HTTP to HTTPS redirect | Infrastructure (reverse proxy / Azure) |
| WWW redirect | Infrastructure (reverse proxy / DNS) |
| Restrict access to install | Not applicable in v17 |
| Disabled rules | Skip entirely |