Skip to main content

Configuring HTTP status codes for CDN-hosted content

The Set status code option returns a custom HTTP response for a CDN resource instead of the file from the origin. The response can be a short text or a redirect, and an Apply from and Until range limits the status to certain hours.

From 22:00 to 06:00, Orange's CDN can return 403 or redirect to another page, and deliver the original file outside that interval.

Status code

In the CDB Technical Web Portal, Resource settings return the status for every request on the CDN resource, and Rules return it only for requests that match the rule pattern.

  1. 1

    Open the CDN resource

    In the Customer Portal, navigate to CDN > CDN resources and click the CNAME of the CDN resource.

    CDN resources list
  2. 2

    Open Content

    Navigate to the OPTIONS tab. In the left menu, click Content.

  3. 3

    Enable Set status code

    Enable the Set status code toggle.

    Enable the Set status code option
  4. 4

    Enter the status code

    In the Status code field, enter the HTTP status code. The field defaults to 200.

    Caution

    Codes 408, 444, 477, 494, 495, 496, 497, and 499 are not accepted.

    • (Optional) In the URL or code text field, enter a redirect URL or the response text.
    • (Optional) Select Apply on schedule. In the expanded block, set Apply from, Until, and Timezone.
  5. 5

    Save the resource

    Click Save changes.

    Configure the Set status code option

    The custom code applies to all files delivered by the CDN resource.

  1. 1

    Open the CDN resource

    In the Customer Portal, navigate to CDN > CDN resources and click the CNAME of the CDN resource.

    CDN resources list
  2. 2

    Create a blank rule

    1. Navigate to the RULES tab.
    2. Click Create rule.
    3. Click Create blank rule.
    Open rules to set a custom code for specific files

    Set the rule pattern so the status code applies only to the matching files.

  3. 3

    Add the status code option

    1. At the end of the page, click Add option.
    Add an option in the rule
    1. Click Status code.
    2. Click Close.
    Status code option in the list
  4. 4

    Enter the status code

    Enable the Set status code toggle. In the Status code field, enter the HTTP status code. The field defaults to 200.

    Caution

    Codes 408, 444, 477, 494, 495, 496, 497, and 499 are not accepted.

    • (Optional) In the URL or code text field, enter a redirect URL or the response text.
    • (Optional) Select Apply on schedule. In the expanded block, set Apply from, Until, and Timezone.
  5. 5

    Create the rule

    Click Create rule.

    Configure the Set status code option in the rule

    The rule applies the custom status code to the specified files.

Orange's CDN can answer a request with a chosen HTTP status instead of the file from the origin. The option is force_return. The response can include a short text or send the viewer to another URL.

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}"

Return a status code

Answer every request with status 403 and the text Forbidden.

enabled, code, and body are required. body is text or a redirect URL, and a value longer than 255 characters returns HTTP 400. A code below 100, above 599, or one of 408, 444, 477, 494, 495, 496, 497, and 499 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={"force_return": {"enabled": True, "code": 403, "body": "Forbidden"}},
)
saved = updated.options.force_return
print(saved.enabled, saved.code, saved.body)
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{
            ForceReturn: cdn.CDNResourceUpdateParamsOptionsForceReturn{
                Enabled: true,
                Code:    403,
                Body:    "Forbidden",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.ForceReturn.Enabled, updated.Options.ForceReturn.Code, updated.Options.ForceReturn.Body)
}
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": {
      "force_return": {"enabled": true, "code": 403, "body": "Forbidden"}
    }
  }'

The API returns HTTP 200. The saved option is:

{
  "enabled": true,
  "code": 403,
  "body": "Forbidden"
}

Limit the status to certain hours

Return 403 with the text Forbidden only from 22:00 to 06:00 in Europe/Luxembourg. Times use HH:MM. When time_zone is omitted, the API stores UTC. Omitting time_interval, or sending it as null, stores no schedule.

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={
        "force_return": {
            "enabled": True,
            "code": 403,
            "body": "Forbidden",
            "time_interval": {
                "start_time": "22:00",
                "end_time": "06:00",
                "time_zone": "Europe/Luxembourg",
            },
        }
    },
)
saved = updated.options.force_return
print(saved.code, saved.time_interval.start_time, saved.time_interval.end_time, saved.time_interval.time_zone)
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{
            ForceReturn: cdn.CDNResourceUpdateParamsOptionsForceReturn{
                Enabled: true,
                Code:    403,
                Body:    "Forbidden",
                TimeInterval: cdn.CDNResourceUpdateParamsOptionsForceReturnTimeInterval{
                    StartTime: "22:00",
                    EndTime:   "06:00",
                    TimeZone:  gcore.String("Europe/Luxembourg"),
                },
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(
        updated.Options.ForceReturn.Code,
        updated.Options.ForceReturn.TimeInterval.StartTime,
        updated.Options.ForceReturn.TimeInterval.EndTime,
        updated.Options.ForceReturn.TimeInterval.TimeZone,
    )
}
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": {
      "force_return": {
        "enabled": true,
        "code": 403,
        "body": "Forbidden",
        "time_interval": {
          "start_time": "22:00",
          "end_time": "06:00",
          "time_zone": "Europe/Luxembourg"
        }
      }
    }
  }'

The API returns HTTP 200. The saved option is:

{
  "enabled": true,
  "code": 403,
  "body": "Forbidden",
  "time_interval": {
    "start_time": "22:00",
    "end_time": "06:00",
    "time_zone": "Europe/Luxembourg"
  }
}

Turn the status code off

Set enabled to false and send the same code and body. Orange's CDN keeps those values and stops answering with the custom status. enabled alone returns HTTP 400. A request that does not include time_interval clears the schedule.

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={"force_return": {"enabled": False, "code": 403, "body": "Forbidden"}},
)
saved = updated.options.force_return
print(saved.enabled, saved.code, saved.body)
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{
            ForceReturn: cdn.CDNResourceUpdateParamsOptionsForceReturn{
                Enabled: false,
                Code:    403,
                Body:    "Forbidden",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.ForceReturn.Enabled, updated.Options.ForceReturn.Code, updated.Options.ForceReturn.Body)
}
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": {
      "force_return": {"enabled": false, "code": 403, "body": "Forbidden"}
    }
  }'

The API returns HTTP 200. The saved option is:

{
  "enabled": false,
  "code": 403,
  "body": "Forbidden"
}

Remove the status code

Send force_return 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={"force_return": None},
)
print(updated.options.force_return)
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{
        "force_return": nil,
    })
    updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
        Options: options,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(updated.Options.ForceReturn.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": {
      "force_return": null
    }
  }'

The API returns HTTP 200. The saved option is:

null

Return the status for one path

A resource rule returns 403 for requests under /restricted/. 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="status-restricted",
    rule="^/restricted/.*",
    rule_type=0,
    options={"force_return": {"enabled": True, "code": 403, "body": "Forbidden"}},
)
print(rule.id, rule.options.force_return.code, rule.options.force_return.body)
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:     "status-restricted",
        Rule:     "^/restricted/.*",
        RuleType: 0,
        Options: cdn.CDNResourceRuleNewParamsOptions{
            ForceReturn: cdn.CDNResourceRuleNewParamsOptionsForceReturn{
                Enabled: true,
                Code:    403,
                Body:    "Forbidden",
            },
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(rule.ID, rule.Options.ForceReturn.Code, rule.Options.ForceReturn.Body)
}
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": "status-restricted",
    "rule": "^/restricted/.*",
    "ruleType": 0,
    "options": {
      "force_return": {"enabled": true, "code": 403, "body": "Forbidden"}
    }
  }'

The API returns HTTP 201. The saved option is:

{
  "enabled": true,
  "code": 403,
  "body": "Forbidden"
}

The Terraform provider v2 returns a chosen HTTP status instead of the file from the origin. body holds the response text or a URL. Run terraform apply after editing options.

Return a status code

Orange's CDN answers every request with status 403 and the text Forbidden. Set enabled to true. code and body are required. Codes 408, 444, 477, 494, 495, 496, 497, and 499 are not accepted.

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 = {
    force_return = {
      enabled = true
      code    = 403
      body    = "Forbidden"
    }
  }
}

Limit the status to certain hours

Return 403 with the text Forbidden from 22:00 to 06:00 in Europe/Luxembourg. Times use HH:MM. When time_zone is omitted, the saved schedule uses UTC. An apply that omits time_interval keeps a schedule that is already saved. An API request that omits time_interval clears the schedule.

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 = {
    force_return = {
      enabled = true
      code    = 403
      body    = "Forbidden"
      time_interval = {
        start_time = "22:00"
        end_time   = "06:00"
        time_zone  = "Europe/Luxembourg"
      }
    }
  }
}

Turn the status code off

Set enabled to false and keep the same code and body. Orange's CDN keeps those values and a saved schedule, and stops answering with the custom status. A resource created without this block leaves the status code 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 = {
    force_return = {
      enabled = false
      code    = 403
      body    = "Forbidden"
    }
  }
}

Return the status for one path

A resource rule returns 403 for requests under /restricted/. The resource block is the CDN resource the rule belongs to. rule_type 0 is a regular expression.

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"
}

resource "gcore_cdn_resource_rule" "example" {
  resource_id = gcore_cdn_resource.example.id
  name        = "status-restricted"
  rule        = "^/restricted/.*"
  rule_type   = 0

  options = {
    force_return = {
      enabled = true
      code    = 403
      body    = "Forbidden"
    }
  }
}