|
| 1 | +# Redirects and Rewrites |
| 2 | + |
| 3 | +Craft Cloud allows you to define any number of custom [redirect](#redirects) and [rewrite](#rewrites) rules via your [`craft-cloud.yml` config file](config.md). |
| 4 | + |
| 5 | +Both features use the flexible [`URLPattern` API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/exec) to match request URLs. These rules are evaluated on our gateway, _before_ we pass the request to your Craft application. |
| 6 | + |
| 7 | +## Redirects |
| 8 | + |
| 9 | +Redirection rules live in your `craft-cloud.yml` file, under a `redirects` key: |
| 10 | + |
| 11 | +```yml |
| 12 | +php-version: '8.2' |
| 13 | + |
| 14 | +# ... |
| 15 | + |
| 16 | +redirects: |
| 17 | + - pattern: |
| 18 | + hostname: 'legacy-domain.com' |
| 19 | + destination: 'https://new-domain.com/{request.uri}' |
| 20 | + status: 301 |
| 21 | +``` |
| 22 | +
|
| 23 | +Each rule’s `pattern` can be a string or an object; either way, it is passed verbatim to the [`new URLPattern(input)` constructor](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/URLPattern). In effect, you can match based on [parts of a URL](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/URLPattern#input), without using complex regular expressions. |
| 24 | + |
| 25 | +A pattern (or each of its components) can be a simple string, or include [wildcards and capture groups](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API#concepts_and_usage). |
| 26 | + |
| 27 | +The `destination` is a pseudo-template used to build a complete URL. It can be a static string or contain substitute information about the original request (`request`) or pattern (`matches`). Additionally, these variables are available to simplify constructing URLs to other Craft Cloud resources: |
| 28 | + |
| 29 | +- `cdnBaseUrl` — The Craft Cloud CDN domain, plus the requested environment’s identifier. |
| 30 | + <small>Example: `https://cdn.craft.cloud/4eca7d1f-8976-45e9-89fb-6b2e864d9407/`</small> |
| 31 | +- `assetBaseUrl` — Same as above, but pointing to the `assets/` subdirectory of the requested environment. |
| 32 | + <small>Example: `https://cdn.craft.cloud/4eca7d1f-8976-45e9-89fb-6b2e864d9407/assets/`</small> |
| 33 | +- `artifactBaseUrl` — The full URL to the current build’s [artifacts](builds.md) directory. |
| 34 | + <small>Example: `https://cdn.craft.cloud/4eca7d1f-8976-45e9-89fb-6b2e864d9407/builds/current/artifacts/`</small> |
| 35 | + |
| 36 | +The `matches` object is the return value of [`URLPattern.exec()`](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern/exec#return_value) for the requested URL. It contains all URL components with any captured groups from the supplied `pattern`. |
| 37 | + |
| 38 | +The `request` object contains these properties: |
| 39 | + |
| 40 | +- `url` — A [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object wrapping the original request’s full URL. |
| 41 | +- `uri` — Shorthand for everything after the origin in the original request, and similar to `$_SERVER['REQUEST_URI']` in PHP. It is equivalent to `{request.url.pathname}{request.url.search}{request.url.hash}`. |
| 42 | +- `method` — The request’s [HTTP verb](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods). |
| 43 | +- `headers` — A map of request headers and values. (Headers with dashes can be used in `destination` substitutions like any other property, e.g: `{request.headers.Content-Type}`) |
| 44 | + |
| 45 | +### HTTP Status Codes |
| 46 | + |
| 47 | +An optional `status` key in each rule determines what [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status) is sent with the redirection. If none is specified, we default to [302 Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) for a “temporary” redirection. |
| 48 | + |
| 49 | +Use [301 Moved Permanently](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) with caution! Some infrastructure and tools aggressively cache 301 responses, or completely replace records with the new URL, meaning it can be difficult or impossible to undo. |
| 50 | + |
| 51 | +### Examples |
| 52 | + |
| 53 | +A common problem solved with HTTP servers (or PHP itself) is normalization of “www” or “non-www” URLs. |
| 54 | + |
| 55 | +```yml |
| 56 | +redirects: |
| 57 | + - pattern: |
| 58 | + hostname: 'www.mydomain.com' |
| 59 | + destination: 'https://mydomain.com/{request.uri}' |
| 60 | +``` |
| 61 | + |
| 62 | +The opposite is also possible: |
| 63 | + |
| 64 | +```yml |
| 65 | +redirects: |
| 66 | + - pattern: |
| 67 | + hostname: 'mydomain.com' |
| 68 | + destination: 'https://www.mydomain.com/{request.uri}' |
| 69 | +``` |
| 70 | + |
| 71 | +For these rules to work, you must have both [domains](domains.md) pointed to the same Craft Cloud environment. Wildcards and/or regular expressions (including [negative lookaheads](https://www.regular-expressions.info/lookaround.html)) are required to create generic rules that match any domain. |
| 72 | + |
| 73 | +Enforcing (or trimming) trailing slashes is another common normalization—Craft even has a config setting ([`addTrailingSlashesToUrls`](/docs/5.x/reference/config/general.html#addtrailingslashestourls)) that handles it at the application level. An equivalent rule would look like this: |
| 74 | + |
| 75 | +```yml |
| 76 | +redirects: |
| 77 | + - pattern: |
| 78 | + pathname: '/:noSlashes+' |
| 79 | + destination: '/{matches.pathname.groups.noSlashes}/' |
| 80 | + status: 301 |
| 81 | +``` |
| 82 | + |
| 83 | +While this pattern appears to have only a single path segment, the `+` [modifies the capture group](https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API#group_modifiers), allowing it to repeat one or more times. Effectively this rule captures _all_ path segments, regardless of depth—from `/top-level` to `/a/deeply/nested/page`. The destination template simply appends a slash to that template. |
| 84 | + |
| 85 | +::: tip |
| 86 | +When the parsed `destination` begins with a slash (a _root-relative_ path), Craft Cloud uses the original request’s hostname and protocol as the base. |
| 87 | +::: |
| 88 | + |
| 89 | +## Rewrites |
| 90 | + |
| 91 | +Unlike a [redirect](#redirects), URL rewrites are used to create virtual resources at our gateway—effectively giving you a configurable proxy. This means that when a matching URL is requested, the corresponding origin’s response is sent back, verbatim, without an initial 300-level response. |
| 92 | + |
| 93 | +Rules follow essentially the same structure as redirects: the pattern-matching process and destination templates are identical. Rules are created under a `rewrites` key in your `craft-cloud.yml` config file. |
| 94 | + |
| 95 | +::: tip |
| 96 | +Using rewrites, you can avoid referencing `cdn.craft.cloud` or updating templates to use [`cloud.artifactUrl`](https://craftcms.com/knowledge-base/cloud-builds#artifact-uRLs)–any CDN requests can be served directly from your custom domain. |
| 97 | +::: |
| 98 | + |
| 99 | +### Examples |
| 100 | + |
| 101 | +You can emulate a local asset filesystem by rewriting a path to our CDN: |
| 102 | + |
| 103 | +```yml |
| 104 | +rewrites: |
| 105 | + - pattern: |
| 106 | + pathname: '/uploads/:assetPath+' |
| 107 | + destination: '{assetBaseUrl}/{matches.pathname.groups.assetPath}{request.url.search}' |
| 108 | +``` |
| 109 | + |
| 110 | +Similarly, you can serve user uploads from a secondary domain or subdomain: |
| 111 | + |
| 112 | +```yml |
| 113 | +rewrites: |
| 114 | + - pattern: |
| 115 | + hostname: 'cdn.mydomain.com' |
| 116 | + pathname: '/assets/:assetPath+' |
| 117 | + destination: '{assetBaseUrl}/{matches.pathname.groups.assetPath}{request.url.search}' |
| 118 | +``` |
| 119 | + |
| 120 | +With this strategy, your files are still stored on (and available from) our CDN—all we’ve done is create an alias for the canonical CDN URL. _Craft continues to generate canonical URLs for assets to ensure that they resolve, independent of rewrite configuration._ |
| 121 | + |
| 122 | +[Build artifacts](/knowledge-base/cloud-builds) (including static files from your web root) can also be proxied: |
| 123 | + |
| 124 | +```yml |
| 125 | +rewrites: |
| 126 | + - pattern: |
| 127 | + pathname: '/(favicon.ico|.well-known|dist)/*?' |
| 128 | + destination: '{artifactBaseUrl}/{request.uri}' |
| 129 | +``` |
0 commit comments