> ## 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.

# Configure a Let's Encrypt certificate

> Issue a free Let's Encrypt certificate for a CDN resource and fix an HTTP-01 failure.

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>On a CDN resource, a free Let's Encrypt certificate is the alternative to an uploaded certificate. Let's Encrypt certificates can only be issued for resources with a [custom domain](/cdn/cdn-resource-options/general/create-and-set-a-custom-domain-for-the-content-delivery-via-cdn).</p>

    <p>The certificate answers HTTPS requests to the CDN. [Origin SSL validation](/cdn/cdn-resource-options/general/enable-origin-ssl-validation) is a separate setting: the edge checks the certificate presented by the origin against an uploaded CA certificate.</p>

    ## Attach a Let's Encrypt certificate

    <p>A wildcard domain cannot be issued a certificate. A Let's Encrypt certificate can be issued only for an existing resource, and only one Let's Encrypt certificate can be issued per resource. Changing the custom domain starts a reissue. The warning says issuance takes up to 15 minutes, and the current certificate stays in use until the new certificate is ready.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/warning.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=fa550bf5e5d754f661fc4cea1538a77b" alt="Warning" width="479" height="266" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/warning.png" />
    </Frame>

    ### During resource creation

    <p>On the **Set up initial configuration** step, navigate to the **SSL** section, and turn on the toggle for **Enable HTTPS**. Then, select **Get free Let's Encrypt certificate**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-enable-https.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=8a300a88ef5fa99cd25d4a07bcf76ccf" alt="During resource creation" width="1239" height="555" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-enable-https.png" />
    </Frame>

    <p>The certificate issuance may take up to 30 minutes after the resource is created. During this time, please do not:</p>

    * disable the HTTPS option,
    * select another certificate,
    * interrupt the issuance of the current certificate.

    ### For created resource

    <p>1. Navigate to **CDN** and select the CDN resource to configure.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/cdn-resource.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=9ec14d7359467aa4eb40c5a1e5eac9de" alt="CDN resource" width="2988" height="610" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/cdn-resource.png" />
    </Frame>

    <p>2. In the navigation panel, under the **General** section, click **SSL**.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-menu.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=0fb67b110b6aee43e1534cd7c5a8a6a6" alt="General section" width="2007" height="784" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-menu.png" />
    </Frame>

    <p>3. In the **SSL** section, turn on the toggle for **Enable HTTPS**, select **Get free Let's Encrypt certificate**, and click **Save changes**. That button saves the SSL section. Issuing and revoking a Let's Encrypt certificate does not require a separate save of the rest of the resource settings.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-enable-https.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=8a300a88ef5fa99cd25d4a07bcf76ccf" alt="SSL section" width="1239" height="555" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-enable-https.png" />
    </Frame>

    <p>Issuance time depends on when the CDN resource was created. A certificate for a recently created resource can take up to 30 minutes, because the configuration has not yet propagated to all CDN servers. A resource whose configuration is already propagated usually finishes in a few minutes.</p>

    ## Check issuance status

    <p>After **Get free Let's Encrypt certificate** is selected, a correct CDN resource configuration shows the **Processing** status in the Customer Portal while the certificate is being issued.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-processing.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=72c370e5b5b8a75293fdaddfcd154c8e" alt="Processing status" width="674" height="296" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-processing.png" />
    </Frame>

    <p>An ACME challenge problem shows an issuance error. The error can appear while a CDN resource is still being created. The next attempt occurs in 15 minutes. Click **force retry** to start the next attempt sooner.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-force-retry.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=19e322caf7e816e6dafd26f81d5cc4b0" alt="Processing with issue status" width="685" height="417" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-force-retry.png" />
    </Frame>

    <p>A successful challenge shows the status **Success**. The certificate is visible only in the settings of the resource for which it is issued. A Let's Encrypt certificate stays off the SSL Certificates page, and the certificate selector stays out of the resource settings.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-revoke.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=7b5ecf72e3d63c67bf5c629b86ef4153" alt="Success status" width="678" height="303" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-revoke.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-certificates.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=c4b2244fe6b5182dd4b551d896b8b9e6" alt="Restrictions and features of the option" width="3432" height="695" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-certificates.png" />
    </Frame>

    <p>During initial issuance, the status changes to **Failed** after five unsuccessful attempts. An issuance error disables the Enable HTTPS toggle and sends a notification to the account email address. Click **Retry issue** to attempt issuance again. When the CDN resource domain cannot be ACME challenged, the message describes the issue and **Get SSL certificate** stays inactive.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-error.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=9f4479a107c1050e64d091847007e763" alt="Pre-validation failed status" width="887" height="573" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-error.png" />
    </Frame>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-failure-retry.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=8c31c5d2d5ae35dd0a81b8eb9932e7c4" alt="Failed status" width="979" height="557" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/ssl-failure-retry.png" />
    </Frame>

    ## Troubleshoot an HTTP-01 failure

    <Warning>
      Certificate issuance fails when either condition is missed:

      * The CNAME record for the resource must point to the value shown in the [setup guide](/cdn/cdn-resource-options/general/create-and-set-a-custom-domain-for-the-content-delivery-via-cdn).
      * No CDN rule may block requests to `/.well-known/acme-challenge/`. A catch-all rule `/**` or a broad regex pattern prevents Let's Encrypt from completing HTTP-01 validation.
    </Warning>

    <p>Let's Encrypt places a temporary file at `http://<CNAME>/.well-known/acme-challenge/<TOKEN>` and requests that file over HTTP. Before adding a Let's Encrypt certificate, confirm that the CDN resource has no rules that block these requests. Rules that block issuance include:</p>

    * **A rule with /**\*. This rule will catch any strings and override the hidden rule that is necessary to obtain a certificate.
    * **A rule with ((?!(jpeg|gif|png|pdf|jpg|css|js|woff|woff2|ttf)).)\*\$**. This rule will catch all non-static files.

    <p>Compare resource rules in [regex101](https://regex101.com/r/6BCT9Z/1). Delete or change a rule that blocks Let's Encrypt certificate issuance. The next Let's Encrypt request can then complete issuance. Issuance also fails when the origin source is not available. The same failure is covered in the [dedicated guide](/cdn/troubleshooting/content-is-unavailable-after-a-cdn-resource-creation-how-to-solve-the-issue#free-let’s-encrypt-certificate).</p>

    <p>With Cloudflare DNS, set **CNAME Flattening** to **Flatten CNAME at root**. **Flatten all CNAMEs** makes Cloudflare return an A record instead of a CNAME and blocks Let's Encrypt issuance.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/bZrXANf0oIZbUla2/images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/lets-encrypt-8.png?fit=max&auto=format&n=bZrXANf0oIZbUla2&q=85&s=9bbd07d53fa5549fe6b612795650b7be" alt="Status" width="1150" height="450" data-path="images/docs/cdn/ssl-certificates/configure-a-lets-encrypt-certificate/lets-encrypt-8.png" />
    </Frame>

    <p>When a multi-CDN balancer answers the hostname with an address outside Gcore, repeating the HTTP-01 checks does not issue the certificate. Enable `use_dns01_le_challenge` in [DNS-01 validation](/cdn/ssl-certificates/use-dns-01-for-a-lets-encrypt-certificate).</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Issue a free Let's Encrypt certificate for a CDN resource that already uses a [custom domain](/cdn/cdn-resource-options/general/create-and-set-a-custom-domain-for-the-content-delivery-via-cdn), then read issuance status or retry a failed attempt. A wildcard hostname cannot receive a Let's Encrypt certificate, and one certificate object attaches to only one CDN resource.</p>

    <p>Renewal and revocation stay in [certificate renewal](/cdn/ssl-certificates/renew-or-revoke-a-lets-encrypt-certificate).</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required. The CDN resource ID is visible under **CDN** → **CDN Resources**, or from the [resources list](/api-reference/cdn/cdn-resources/list-cdn-resources) call.
    </Info>

    <p>For HTTP-01, the hostname CNAME must point at the CDN edge hostname from the custom domain setup, and no CDN rule may block `/.well-known/acme-challenge/`. HTTP-01 is the default challenge. A newly created resource can take up to 30 minutes before the first attempt succeeds. A resource that is already propagated usually finishes in a few minutes. Gcore schedules the next attempt about 15 minutes after a failure. Leave HTTPS enabled and keep the same certificate attached while issuance is active.</p>

    <p>Open a terminal and export the required variables:</p>

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

    ## Issue a Let's Encrypt certificate

    <p>Issuance is four calls in order: create the certificate object, pre-validate the resource, attach the certificate, then read the status until issuance finishes.</p>

    ### 1. Create the certificate object

    <p>Create the certificate object before attaching it. `automated` must be `true`. The PEM fields stay null until issuance finishes. The Python and Go calls return no body, so the new ID comes from the certificate list filtered by name. The curl call returns the object, including `id`.</p>

    | Parameter | Required | Description |
    | - | - | - |
    | `name` | Yes | Unique label for the certificate object |
    | `automated` | Yes | `true` to issue the certificate through Let's Encrypt |

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

        client = Gcore()

        client.cdn.certificates.create(
            name="cdn-le-certificate",
            automated=True,
        )

        created = next(
            item
            for item in client.cdn.certificates.list(automated=True)
            if item.name == "cdn-le-certificate"
        )
        print(created.id, created.automated, created.has_related_resources)
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"

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

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            err := client.CDN.Certificates.New(ctx, cdn.CertificateNewParams{
                OfLetSEncryptCertificate: &cdn.CertificateNewParamsBodyLetSEncryptCertificate{
                    Name:      "cdn-le-certificate",
                    Automated: true,
                },
            })
            if err != nil {
                panic(err)
            }

            page, err := client.CDN.Certificates.List(ctx, cdn.CertificateListParams{
                Automated: gcore.Bool(true),
            })
            if err != nil {
                panic(err)
            }
            for _, item := range page.Results {
                if item.Name == "cdn-le-certificate" {
                    fmt.Println(item.ID, item.Automated, item.HasRelatedResources)
                }
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cdn/sslData" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "name": "cdn-le-certificate",
            "automated": true
          }'
        ```

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

        ```json theme={null}
        {
          "id": 192,
          "name": "cdn-le-certificate",
          "automated": true,
          "hasRelatedResources": false,
          "cert_issuer": null,
          "cert_subject_cn": null,
          "validity_not_before": null,
          "validity_not_after": null
        }
        ```
      </Tab>
    </Tabs>

    <p>The Python and Go calls print the certificate `id`. The curl response includes `id`. Export that value before the next call:</p>

    ```bash theme={null}
    export CDN_SSL_CERTIFICATE_ID="{YOUR_SSL_CERTIFICATE_ID}"
    ```

    ### 2. Pre-validate the resource

    <p>Check whether the hostname can be challenged before attaching the certificate. HTTP 201 with an empty object means the check passed. HTTP 400 returns an `errors` array describing the problem: a hostname that does not resolve, or an HTTP timeout on port 80. A failed check does not block the issue call. The status call then reports `ValidationIssue`.</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"])

        client.cdn.cdn_resources.prevalidate_ssl_le_certificate(resource_id)
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "os"
            "strconv"

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

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

            err = client.CDN.CDNResources.PrevalidateSslLeCertificate(ctx, resourceID)
            if err != nil {
                panic(err)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cdn/resources/$CDN_RESOURCE_ID/ssl/le/pre-validate" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

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

        ```json theme={null}
        {}
        ```
      </Tab>
    </Tabs>

    ### 3. Attach the certificate and start issuance

    <p>Set `sslEnabled` to `true` and `sslData` to the certificate ID. That PATCH starts issuance for every hostname on the resource. `hasRelatedResources` becomes `true` on the certificate object immediately, while `cert_issuer` and `cert_subject_cn` stay empty until the attempt reaches `DONE`. The default key type is ECDSA.</p>

    <p>When HTTP-01 cannot reach the hostname, enable `use_dns01_le_challenge` in [DNS-01 validation](/cdn/ssl-certificates/use-dns-01-for-a-lets-encrypt-certificate) before this attach call.</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"])
        certificate_id = int(os.environ["CDN_SSL_CERTIFICATE_ID"])

        updated = client.cdn.cdn_resources.update(
            resource_id,
            ssl_enabled=True,
            ssl_data=certificate_id,
        )
        print(updated.id, updated.ssl_enabled, updated.ssl_data)
        ```
      </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)
            }
            certificateID, err := strconv.ParseInt(os.Getenv("CDN_SSL_CERTIFICATE_ID"), 10, 64)
            if err != nil {
                panic(err)
            }

            updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                SslEnabled: gcore.Bool(true),
                SslData:    gcore.Int(certificateID),
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(updated.ID, updated.SslEnabled, updated.SslData)
        }
        ```
      </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 '{
            "sslEnabled": true,
            "sslData": '"$CDN_SSL_CERTIFICATE_ID"'
          }'
        ```

        <p>The API returns HTTP 200. The resource includes:</p>

        ```json theme={null}
        {
          "id": 101,
          "sslEnabled": true,
          "sslData": 192
        }
        ```
      </Tab>
    </Tabs>

    ### 4. Check issuance status

    <p>Poll the certificate status until `active` is `false`. The first read can return `latest_status` as `null` and `statuses` as an empty array. After the attempt is recorded, `latest_status.status` is `FAILED` or `DONE`. `finished` stays `null` while retries remain scheduled. `next_attempt_time` is the next automatic attempt.</p>

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

        from gcore import Gcore

        client = Gcore()
        certificate_id = int(os.environ["CDN_SSL_CERTIFICATE_ID"])

        issuing = client.cdn.certificates.get_status(certificate_id)
        print(issuing.active, issuing.attempts_count, issuing.finished)
        if issuing.latest_status is not None:
            print(issuing.latest_status.status, issuing.latest_status.error)
        ```
      </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()
            certificateID, err := strconv.ParseInt(os.Getenv("CDN_SSL_CERTIFICATE_ID"), 10, 64)
            if err != nil {
                panic(err)
            }

            issuing, err := client.CDN.Certificates.GetStatus(ctx, certificateID, cdn.CertificateGetStatusParams{})
            if err != nil {
                panic(err)
            }
            fmt.Println(issuing.Active, issuing.AttemptsCount, issuing.Finished)
            if issuing.JSON.LatestStatus.Valid() {
                fmt.Println(issuing.LatestStatus.Status, issuing.LatestStatus.Error)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl "https://api.gcore.com/cdn/sslData/$CDN_SSL_CERTIFICATE_ID/status" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        <p>The API returns HTTP 200 after the attempt is recorded:</p>

        ```json theme={null}
        {
          "id": 479318,
          "active": true,
          "attempts_count": 1,
          "started": "2026-09-24T10:01:40.804396Z",
          "finished": null,
          "next_attempt_time": "2026-09-24T10:16:41.146402Z",
          "resource": 101,
          "latest_status": {
            "status": "FAILED",
            "error": "ValidationIssue",
            "details": "Problem detected: Unable to resolve the domain name."
          }
        }
        ```
      </Tab>
    </Tabs>

    <p>A certificate that is not attached returns HTTP 400: `Certificate is not attached to a resource.`</p>

    ## Retry a failed attempt

    <p>Force the next attempt immediately instead of waiting for `next_attempt_time`. The call is valid while the latest attempt is `FAILED` and another attempt is already scheduled. The API returns HTTP 201 and an empty object.</p>

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

        from gcore import Gcore

        client = Gcore()
        certificate_id = int(os.environ["CDN_SSL_CERTIFICATE_ID"])

        client.cdn.certificates.force_retry(certificate_id)
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "os"
            "strconv"

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

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

            err = client.CDN.Certificates.ForceRetry(ctx, certificateID)
            if err != nil {
                panic(err)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST "https://api.gcore.com/cdn/sslData/$CDN_SSL_CERTIFICATE_ID/force-retry" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

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

        ```json theme={null}
        {}
        ```
      </Tab>
    </Tabs>

    ## Request an RSA certificate

    <p>The next issuance or renewal uses ECDSA unless `use_rsa_le_cert` is enabled first. Enable the option before Step 3 for the initial issuance, or before the renew call in [certificate renewal](/cdn/ssl-certificates/renew-or-revoke-a-lets-encrypt-certificate).</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"])

        updated = client.cdn.cdn_resources.update(
            resource_id,
            options={
                "use_rsa_le_cert": {"enabled": True, "value": True},
            },
        )
        print(updated.options.use_rsa_le_cert.enabled, updated.options.use_rsa_le_cert.value)
        ```
      </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)
            }

            updated, err := client.CDN.CDNResources.Update(ctx, resourceID, cdn.CDNResourceUpdateParams{
                Options: cdn.CDNResourceUpdateParamsOptions{
                    UseRsaLeCert: cdn.CDNResourceUpdateParamsOptionsUseRsaLeCert{
                        Enabled: true,
                        Value:   true,
                    },
                },
            })
            if err != nil {
                panic(err)
            }
            fmt.Println(updated.Options.UseRsaLeCert.Enabled, updated.Options.UseRsaLeCert.Value)
        }
        ```
      </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": {
              "use_rsa_le_cert": {
                "enabled": true,
                "value": true
              }
            }
          }'
        ```

        <p>The API returns HTTP 200. The saved option is:</p>

        ```json theme={null}
        {
          "enabled": true,
          "value": true
        }
        ```
      </Tab>
    </Tabs>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>Issue a Let's Encrypt certificate for a CDN resource with the [Terraform provider](/developer-tools/terraform/overview) v2.</p>

    <p>The resource uses a [custom domain](/cdn/cdn-resource-options/general/create-and-set-a-custom-domain-for-the-content-delivery-via-cdn). A wildcard hostname cannot receive a Let's Encrypt certificate, and one certificate object attaches to only one CDN resource. For HTTP-01, point the hostname CNAME at the CDN edge hostname, and keep `/.well-known/acme-challenge/` free of CDN rules. A newly created resource can take up to 30 minutes before the first attempt succeeds. When the HTTP-01 hostname does not point at the CDN, the attempt fails, and `cert_issuer` and `cert_subject_cn` stay empty. The next attempt is about 15 minutes later. A forced retry is the **force retry** control in the **SSL** section.</p>

    <p>When the hostname answers from an address outside Gcore, enable `use_dns01_le_challenge` in [DNS-01 validation](/cdn/ssl-certificates/use-dns-01-for-a-lets-encrypt-certificate) before apply. Renewal stays in [certificate renewal](/cdn/ssl-certificates/renew-or-revoke-a-lets-encrypt-certificate).</p>

    ## Issue the certificate

    <p>Create the certificate with `automated` set to `true`, and set `ssl_enabled` and `ssl_data` on the CDN resource. One `terraform apply` creates the certificate, attaches it, and starts issuance.</p>

    ```hcl theme={null}
    resource "gcore_cdn_origin_group" "example" {
      name = "my-origin-group"

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

    resource "gcore_cdn_certificate" "example" {
      name      = "cdn-le-certificate"
      automated = true
    }

    resource "gcore_cdn_resource" "example" {
      cname           = "le.mywebsite.com"
      origin_group    = gcore_cdn_origin_group.example.id
      origin_protocol = "HTTPS"
      ssl_enabled     = true
      ssl_data        = gcore_cdn_certificate.example.id
    }
    ```

    <p>After `terraform apply`, open the **SSL** section of the CDN resource and wait until the status is **Success**.</p>

    ## Request an RSA certificate

    <p>Set the option before apply so the next issuance uses an RSA key. Issuance uses an ECDSA key until this option is enabled.</p>

    ```hcl theme={null}
    resource "gcore_cdn_origin_group" "example" {
      name = "my-origin-group"

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

    resource "gcore_cdn_certificate" "example" {
      name      = "cdn-le-certificate"
      automated = true
    }

    resource "gcore_cdn_resource" "example" {
      cname           = "le.mywebsite.com"
      origin_group    = gcore_cdn_origin_group.example.id
      origin_protocol = "HTTPS"
      ssl_enabled     = true
      ssl_data        = gcore_cdn_certificate.example.id

      options = {
        use_rsa_le_cert = {
          enabled = true
          value   = true
        }
      }
    }
    ```
  </MethodSection>
</MethodSwitch>
