> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Control access to the content with country, referrer, IP, and user agents policies

> Limit CDN resource requests with country, referrer, IP, and user agent access policies using allow or block by default modes.

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>Country, referrer, IP, and user agent policies limit which requests a CDN resource accepts. The list on each policy is the set of exceptions to the selected mode.</p>

    ## Access policies

    <p>**Allow by default** accepts every request except the listed values, while **Block by default** accepts only the listed values.</p>

    <Steps>
      <Step title="Open Access">
        In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **CDN**:

        1. Open the resource.
        2. Select **Access**.
      </Step>

      <Step title="Set the policy mode">
        Turn on the policy, then select **Allow by default** or **Block by default**.
      </Step>

      <Step title="Save the resource">
        Click **Save changes**.
      </Step>
    </Steps>

    ### Referrer

    <p>A referrer policy checks the domain that sent the request. Turn on **Enable referrer access policy**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-referrer-access-policy.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=d4e1f9111dcd160cb8a43639dde86b35" alt="Referrer access policy with Allow by default selected" width="1470" height="673" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-referrer-access-policy.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-referrer-access-policy-block.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=27001651a12d98a7d3e5163e8d586a80" alt="Referrer access policy with Block by default selected" width="1461" height="665" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-referrer-access-policy-block.png" />
    </Frame>

    <p>Enter a domain or a wildcard, with no scheme:</p>

    * `www.domain.com` matches that domain
    * `*.domain.com` matches every subdomain of domain.com

    ### Country

    <p>Unlike a referrer, a country policy checks where the request comes from. Turn on **Enable country access policy**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-country-access.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=cc8ad30336ce760b31a64db026674103" alt="Country access policy with Allow by default selected" width="1503" height="697" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-country-access.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-country-access-block.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=467ffc4de0e78209db31cd366ac6a58e" alt="Country access policy with Block by default selected" width="1486" height="692" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-country-access-block.png" />
    </Frame>

    <p>The **Choose a country** field takes a two-letter uppercase ISO 3166-1 alpha-2 code.</p>

    ### IP address

    <p>An IP policy checks the client address, and it accepts both IPv4 and IPv6. Turn on **Enable IP access policy**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-ip-access-policy.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=726e5637593d684dc16df31d17f581a7" alt="IP access policy with Allow by default selected" width="1472" height="832" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-ip-access-policy.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-ip-access-policy-block.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=0d2b2e816a3d6a757c94c295113a3576" alt="IP access policy with Block by default selected" width="1470" height="825" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-ip-access-policy-block.png" />
    </Frame>

    <p>Enter an address with a prefix in **IP with a subnet mask**. The CDN stores it as a network address, so `192.168.3.2` becomes `192.168.3.2/32`.</p>

    ### User agent

    <p>A user agent policy checks the User-Agent header, and it also accepts an empty value or a pattern. Turn on **Enable user agents policy**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-user-agents-policy.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=fe971a13fa7b7a96119995685590bf1c" alt="User agents policy with Block by default selected" width="1241" height="476" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-user-agents-policy.png" />
    </Frame>

    <p>The **User-Agent** field accepts an **Empty value**, an exact string of at most 220 characters, or a pattern. **Empty value** matches a request that sends no User-Agent header.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/-KfIdBsV7ok6Y4Qg/images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-user-agents-policy-empty.png?fit=max&auto=format&n=-KfIdBsV7ok6Y4Qg&q=85&s=d6698a82b07e112c65c993de32307b63" alt="Empty value in the User-Agent field" width="1236" height="512" data-path="images/docs/cdn/cdn-resource-options/security/control-access-to-the-content-with-country-referrer-ip-and-user-agents-policies/cdn-user-agents-policy-empty.png" />
    </Frame>

    <p>A pattern starts with `~` for case-sensitive matching, or with `~*` for case-insensitive matching. Select at least one entry, and allow 15 minutes for the change to take effect.</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>`country_acl`, `referrer_acl`, `ip_address_acl`, and `user_agent_acl` limit which requests a CDN resource accepts.</p>

    <p>When `policy_type` is `allow`, every request is accepted except the values in `excepted_values`, while `deny` accepts only those values.</p>

    <p>`allow` matches **Allow by default**, while `deny` matches **Block by default**.</p>

    <p>`policy_type` accepts `allow` or `deny`, and any other value, including `block`, returns HTTP 400.</p>

    <p>`enabled`, `policy_type`, and `excepted_values` are required. An empty `excepted_values` list returns HTTP 400.</p>

    <p>Omit a field to leave that policy unset.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required.
    </Info>

    <p>Export these variables. `CDN_RESOURCE_ID` is the `id` from [list CDN resources](/api-reference/cdn/cdn-resources/list-cdn-resources).</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export CDN_RESOURCE_ID="{YOUR_RESOURCE_ID}"
    ```

    ## Policy values

    <p>The four objects share `enabled`, `policy_type`, and `excepted_values`. Only the contents of `excepted_values` change.</p>

    ### Country codes

    <p>`excepted_values` takes two-letter uppercase country codes, so `DE` is stored, while `de` and `USA` return HTTP 400.</p>

    <p>Send `country_acl` with `policy_type` `allow` and `excepted_values` set to `DE`.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os

        from gcore import Gcore

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

        resource = client.cdn.cdn_resources.update(
            resource_id,
            options={
                "country_acl": {
                    "enabled": True,
                    "policy_type": "allow",
                    "excepted_values": ["DE"],
                },
            },
        )
        print(
            resource.options.country_acl.enabled,
            resource.options.country_acl.policy_type,
            resource.options.country_acl.excepted_values,
        )
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        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)
            }

            resource, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                Options: cdn.CDNResourceUpdateParamsOptions{
                    CountryACL: cdn.CDNResourceUpdateParamsOptionsCountryACL{
                        Enabled:        true,
                        PolicyType:     "allow",
                        ExceptedValues: []string{"DE"},
                    },
                },
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(resource.Options.CountryACL.Enabled, resource.Options.CountryACL.PolicyType, resource.Options.CountryACL.ExceptedValues)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "options": {
              "country_acl": {
                "enabled": true,
                "policy_type": "allow",
                "excepted_values": ["DE"]
              }
            }
          }'
        ```

        <p>The API returns HTTP 200:</p>

        ```json theme={null}
        {
          "id": 12345,
          "options": {
            "country_acl": {
              "enabled": true,
              "policy_type": "allow",
              "excepted_values": ["DE"]
            }
          }
        }
        ```
      </Tab>
    </Tabs>

    ### Referrer domains

    <p>Unlike a country code, a referrer value is a domain or a `*.` wildcard, with no URL scheme. A value that includes a scheme returns HTTP 400.</p>

    <p>`none` together with a domain is stored, while a list that contains only `none` returns HTTP 400.</p>

    <p>Send `referrer_acl` with `policy_type` `deny` and a wildcard in `excepted_values`.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os

        from gcore import Gcore

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

        resource = client.cdn.cdn_resources.update(
            resource_id,
            options={
                "referrer_acl": {
                    "enabled": True,
                    "policy_type": "deny",
                    "excepted_values": ["*.example.com"],
                },
            },
        )
        print(
            resource.options.referrer_acl.enabled,
            resource.options.referrer_acl.policy_type,
            resource.options.referrer_acl.excepted_values,
        )
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        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)
            }

            resource, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                Options: cdn.CDNResourceUpdateParamsOptions{
                    ReferrerACL: cdn.CDNResourceUpdateParamsOptionsReferrerACL{
                        Enabled:        true,
                        PolicyType:     "deny",
                        ExceptedValues: []string{"*.example.com"},
                    },
                },
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(resource.Options.ReferrerACL.Enabled, resource.Options.ReferrerACL.PolicyType, resource.Options.ReferrerACL.ExceptedValues)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "options": {
              "referrer_acl": {
                "enabled": true,
                "policy_type": "deny",
                "excepted_values": ["*.example.com"]
              }
            }
          }'
        ```

        <p>The API returns HTTP 200:</p>

        ```json theme={null}
        {
          "id": 12345,
          "options": {
            "referrer_acl": {
              "enabled": true,
              "policy_type": "deny",
              "excepted_values": ["*.example.com"]
            }
          }
        }
        ```
      </Tab>
    </Tabs>

    ### IP addresses

    <p>An IP value checks the client address rather than a name. `192.168.3.2/32`, `10.0.0.0/8`, and `2a03:d000:2980:7::8/128` are stored, while the host address `192.168.3.2` is stored as `192.168.3.2/32`.</p>

    <p>Send `ip_address_acl` with `policy_type` `allow` and `excepted_values` set to `192.168.3.2/32`.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os

        from gcore import Gcore

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

        resource = client.cdn.cdn_resources.update(
            resource_id,
            options={
                "ip_address_acl": {
                    "enabled": True,
                    "policy_type": "allow",
                    "excepted_values": ["192.168.3.2/32"],
                },
            },
        )
        print(
            resource.options.ip_address_acl.enabled,
            resource.options.ip_address_acl.policy_type,
            resource.options.ip_address_acl.excepted_values,
        )
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        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)
            }

            resource, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                Options: cdn.CDNResourceUpdateParamsOptions{
                    IPAddressACL: cdn.CDNResourceUpdateParamsOptionsIPAddressACL{
                        Enabled:        true,
                        PolicyType:     "allow",
                        ExceptedValues: []string{"192.168.3.2/32"},
                    },
                },
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(resource.Options.IPAddressACL.Enabled, resource.Options.IPAddressACL.PolicyType, resource.Options.IPAddressACL.ExceptedValues)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "options": {
              "ip_address_acl": {
                "enabled": true,
                "policy_type": "allow",
                "excepted_values": ["192.168.3.2/32"]
              }
            }
          }'
        ```

        <p>The API returns HTTP 200:</p>

        ```json theme={null}
        {
          "id": 12345,
          "options": {
            "ip_address_acl": {
              "enabled": true,
              "policy_type": "allow",
              "excepted_values": ["192.168.3.2/32"]
            }
          }
        }
        ```
      </Tab>
    </Tabs>

    ### User agent strings

    <p>A user agent value can be an exact string, an empty string, or a pattern, unlike the names and addresses above.</p>

    <p>A pattern starts with `~` for case-sensitive matching, or with `~*` for case-insensitive matching. Each value can contain at most 220 characters, so a value of 221 characters returns HTTP 400.</p>

    <p>Send `user_agent_acl` with `policy_type` `deny` and `excepted_values` set to an empty string and `~*mozilla.*`.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os

        from gcore import Gcore

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

        resource = client.cdn.cdn_resources.update(
            resource_id,
            options={
                "user_agent_acl": {
                    "enabled": True,
                    "policy_type": "deny",
                    "excepted_values": ["", "~*mozilla.*"],
                },
            },
        )
        print(
            resource.options.user_agent_acl.enabled,
            resource.options.user_agent_acl.policy_type,
            resource.options.user_agent_acl.excepted_values,
        )
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        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)
            }

            resource, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                Options: cdn.CDNResourceUpdateParamsOptions{
                    UserAgentACL: cdn.CDNResourceUpdateParamsOptionsUserAgentACL{
                        Enabled:        true,
                        PolicyType:     "deny",
                        ExceptedValues: []string{"", "~*mozilla.*"},
                    },
                },
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(resource.Options.UserAgentACL.Enabled, resource.Options.UserAgentACL.PolicyType, resource.Options.UserAgentACL.ExceptedValues)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "options": {
              "user_agent_acl": {
                "enabled": true,
                "policy_type": "deny",
                "excepted_values": ["", "~*mozilla.*"]
              }
            }
          }'
        ```

        <p>The API returns HTTP 200:</p>

        ```json theme={null}
        {
          "id": 12345,
          "options": {
            "user_agent_acl": {
              "enabled": true,
              "policy_type": "deny",
              "excepted_values": ["", "~*mozilla.*"]
            }
          }
        }
        ```
      </Tab>
    </Tabs>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>Limit which requests a CDN resource accepts with the [Terraform provider](/developer-tools/terraform/overview) v2. When `policy_type` is `allow`, every request is accepted except the values in `excepted_values`, while `deny` accepts only those values. An empty `excepted_values` list returns HTTP 400 and the message `This list may not be empty.` Run `terraform apply` after editing `options`.</p>

    ## Access policy values

    <p>The four objects use `enabled`, `policy_type`, and `excepted_values`. `country_acl` set to `allow` with `DE` accepts every country except `DE`, while `referrer_acl` set to `deny` accepts only the wildcard in `excepted_values`, and that value has no URL scheme. `ip_address_acl` set to `allow` with `192.168.3.2/32` accepts every address except that network, and a host address without a prefix is stored with `/32`, so `192.168.3.2` becomes `192.168.3.2/32`. `user_agent_acl` set to `deny` with an empty string and `~*mozilla.*` accepts a missing User-Agent header and a case-insensitive match of `mozilla.*`.</p>

    ```hcl theme={null}
    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 = {
        country_acl = {
          enabled         = true
          policy_type     = "allow"
          excepted_values = ["DE"]
        }

        referrer_acl = {
          enabled         = true
          policy_type     = "deny"
          excepted_values = ["*.example.com"]
        }

        ip_address_acl = {
          enabled         = true
          policy_type     = "allow"
          excepted_values = ["192.168.3.2/32"]
        }

        user_agent_acl = {
          enabled         = true
          policy_type     = "deny"
          excepted_values = ["", "~*mozilla.*"]
        }
      }
    }
    ```
  </MethodSection>
</MethodSwitch>
