Skip to main content

Rewrite: redirect requests from the CDN to the origin

The Rewrite option changes the request path before the CDN fetches content from the origin. With the redirect or permanent flag, the CDN returns a redirect to the viewer. The option follows nginx rewrite rules.

To enable the option, open a CDN resource, navigate to the Options tab, then to the Content section. Toggle Enable rewrite. The same option can be set on a rule in the Rules section.

CDN resource Options tab with Rewrite enabled, showing the Rewrite body field and Rewrite flag dropdown

Rewrite body

The Rewrite body field pre-fills with /(.*) /$1. Replace it with two parts separated by a space:

1. A regular expression that matches the request path.

2. The replacement path.

To rewrite all request paths to the /media/ directory, use:

/(.*) /media/$1

where:

  • /(.*) — matches a request path that starts with /. The (.*) group captures everything that follows the slash.
  • /media/ — the directory on the origin where CDN servers look for content.
  • $1 — references the first capture group. Use $2 and $3 for the second and third groups.

In the Rewrite flag dropdown, select the nginx flag that controls how the rewrite is applied:

  • break (default) — stops processing further rewrite rules after this one.
  • last — stops processing rewrite rules and starts a new location search.
  • redirect — returns a 302 temporary redirect to the client.
  • permanent — returns a 301 permanent redirect to the client.

A path on the CDN hostname is not always the path stored on the origin. The rewrite option changes the path used to fetch the file from the origin, or returns a redirect to the viewer. The value follows nginx rewrite rules: a regular expression, a replacement, and a flag.

An API token is required. The CDN resource ID is the id from the resources list call.

export GCORE_API_KEY="{YOUR_API_KEY}"
export CDN_RESOURCE_ID="{YOUR_CDN_RESOURCE_ID}"

Set a rewrite

Orange's CDN fetches the file from another path on the origin, or returns a redirect to the viewer, instead of using the path in the CDN URL. A request for /photo.jpg rewritten with /(.*) /media/$1 is fetched as /media/photo.jpg.

body is two parts separated by a space: a regular expression that matches the request path, then the replacement. $1 inserts the first capture group, and $2 inserts the second. enabled and body are both required.

flag accepts break, last, redirect, or permanent. When flag is omitted, the API stores break. An invalid capture reference or an unsupported variable returns HTTP 400.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

updated = client.cdn.cdn_resources.update(
    resource_id,
    options={
        "rewrite": {
            "enabled": True,
            "body": "/(.*) /media/$1",
            "flag": "break",
        }
    },
)
print(updated.options.rewrite.enabled, updated.options.rewrite.body, updated.options.rewrite.flag)
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
        Options: cdn.CDNResourceUpdateParamsOptions{
            Rewrite: cdn.CDNResourceUpdateParamsOptionsRewrite{
                Enabled: true,
                Body:    "/(.*) /media/$1",
                Flag:    "break",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.Rewrite.Enabled, updated.Options.Rewrite.Body, updated.Options.Rewrite.Flag)
}
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "options": {
      "rewrite": {
        "enabled": true,
        "body": "/(.*) /media/$1",
        "flag": "break"
      }
    }
  }'

The API returns HTTP 200. The saved option is:

{
  "enabled": true,
  "body": "/(.*) /media/$1",
  "flag": "break"
}

Turn the rewrite off

Set enabled to false to keep the saved body and flag while Orange's CDN stops applying the rewrite.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

updated = client.cdn.cdn_resources.update(
    resource_id,
    options={
        "rewrite": {
            "enabled": False,
            "body": "/(.*) /media/$1",
            "flag": "break",
        }
    },
)
print(updated.options.rewrite.enabled, updated.options.rewrite.body, updated.options.rewrite.flag)
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
        Options: cdn.CDNResourceUpdateParamsOptions{
            Rewrite: cdn.CDNResourceUpdateParamsOptionsRewrite{
                Enabled: false,
                Body:    "/(.*) /media/$1",
                Flag:    "break",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.Rewrite.Enabled, updated.Options.Rewrite.Body, updated.Options.Rewrite.Flag)
}
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "options": {
      "rewrite": {
        "enabled": false,
        "body": "/(.*) /media/$1",
        "flag": "break"
      }
    }
  }'

The API returns HTTP 200. The saved option is:

{
  "enabled": false,
  "body": "/(.*) /media/$1",
  "flag": "break"
}

Remove the rewrite

Send rewrite as JSON null to remove the option. The next read returns null.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

updated = client.cdn.cdn_resources.update(
    resource_id,
    options={"rewrite": None},
)
print(updated.options.rewrite)
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    options := cdn.CDNResourceUpdateParamsOptions{}
    options.SetExtraFields(map[string]any{
        "rewrite": nil,
    })
    updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
        Options: options,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.Rewrite.RawJSON())
}
curl -X PATCH "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "options": {
      "rewrite": null
    }
  }'

The API returns HTTP 200. The saved option is:

null

Rewrite one path

The same option can be stored on a resource rule, so requests that match the rule are rewritten. ruleType 0 is a regular expression and must start with ^/ or /.

import os

from gcore import CDB

client = CDB()
resource_id = int(os.environ["CDN_RESOURCE_ID"])

rule = client.cdn.cdn_resources.rules.create(
    resource_id,
    name="rewrite-media",
    rule="^/assets/.*",
    rule_type=0,
    options={
        "rewrite": {
            "enabled": True,
            "body": "/assets/(.*) /media/$1",
            "flag": "break",
        }
    },
)
print(rule.id, rule.options.rewrite.body, rule.options.rewrite.flag)
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/cdn"
)

func main() {
    client := gcore.NewClient()
    ctx := context.Background()
    resourceID, err := strconv.ParseInt(os.Getenv("CDN_RESOURCE_ID"), 10, 64)
    if err != nil {
        panic(err)
    }

    rule, err := client.CDN.CDNResources.Rules.New(ctx, resourceID, cdn.CDNResourceRuleNewParams{
        Name:     "rewrite-media",
        Rule:     "^/assets/.*",
        RuleType: 0,
        Options: cdn.CDNResourceRuleNewParamsOptions{
            Rewrite: cdn.CDNResourceRuleNewParamsOptionsRewrite{
                Enabled: true,
                Body:    "/assets/(.*) /media/$1",
                Flag:    "break",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(rule.ID, rule.Options.Rewrite.Body, rule.Options.Rewrite.Flag)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/cdn/resources/$CDN_RESOURCE_ID/rules" \
  -H "Authorization: APIKey $GCORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rewrite-media",
    "rule": "^/assets/.*",
    "ruleType": 0,
    "options": {
      "rewrite": {
        "enabled": true,
        "body": "/assets/(.*) /media/$1",
        "flag": "break"
      }
    }
  }'

The API returns HTTP 201. The saved option is:

{
  "enabled": true,
  "body": "/assets/(.*) /media/$1",
  "flag": "break"
}

The Terraform provider v2 rewrites a request path before the CDN fetches the file from the origin, or returns a redirect to the viewer. A request for /photo.jpg rewritten with /(.*) /media/$1 is fetched as /media/photo.jpg. Run terraform apply after editing options.

Rewrite

The CDN fetches the file from the replacement path on the origin. Set enabled to true and body to a regular expression and a replacement, separated by a space. $1 inserts the first capture group. flag is break, last, redirect, or permanent. When flag is omitted, the saved option uses break.

break stops further rewrite rules, last starts a new location search, redirect returns 302, and permanent returns 301. Set enabled to false to keep the saved body and flag while Orange's CDN stops applying the rewrite. A resource created without this block leaves the rewrite unset.

resource "gcore_cdn_origin_group" "example" {
  name = "my-origin-group"

  sources = [
    {
      source  = "example.com"
      enabled = true
    }
  ]
}

resource "gcore_cdn_resource" "example" {
  cname           = "cdn.example.com"
  origin_group    = gcore_cdn_origin_group.example.id
  origin_protocol = "HTTPS"

  options = {
    rewrite = {
      enabled = true
      body    = "/(.*) /media/$1"
      flag    = "break"
    }
  }
}

Rewrite one path

Store rewrite on a resource rule so only requests that match the rule are rewritten. The resource block is the CDN resource the rule belongs to. rule_type 0 is a regular expression and must start with ^/ or /.

resource "gcore_cdn_origin_group" "example" {
  name = "my-origin-group"

  sources = [
    {
      source  = "example.com"
      enabled = true
    }
  ]
}

resource "gcore_cdn_resource" "example" {
  cname           = "cdn.example.com"
  origin_group    = gcore_cdn_origin_group.example.id
  origin_protocol = "HTTPS"

  options = {
    rewrite = {
      enabled = true
      body    = "/(.*) /media/$1"
      flag    = "break"
    }
  }
}

resource "gcore_cdn_resource_rule" "example" {
  resource_id = gcore_cdn_resource.example.id
  name        = "rewrite-media"
  rule        = "^/assets/.*"
  rule_type   = 0

  options = {
    rewrite = {
      enabled = true
      body    = "/assets/(.*) /media/$1"
      flag    = "break"
    }
  }
}