Skip to content

Static file hosting options

Since Grove uses Tutor to deploy Open edX sites, by default your static files will be served by your LMS/CMS containers.

Grove provides configuration options to host your static files on S3-compatible storage or on Cloudfront.

S3/Digital Ocean Spaces

To host your files on S3, add the setting GROVE_ENABLE_S3_STATIC_FILES: true to your instance's config.yml and redeploy.

When enabled, Grove will upload your instance's static files to the /static/ folder on your S3 bucket and modify the STATIC_URL setting so that static files are fetched from your S3 bucket rather than from your LMS/CMS containers.

Note

MFE's do not support this feature at this stage.

Cloudfront

Currently, Grove supports adding the Cloudfront CDN when using the AWS provider.

To enable the CDN, add the setting GROVE_ENABLE_CLOUDFRONT: true to your instance's config.yml.

When enabled, Grove will generate CloudFront CDN's for the LMS and CMS and replace the STATIC_URL for each so that any requests for your instance's static files are routed through CloudFront instead of going to your instance directly.

MFE's

Because MFE's aren't served using standard Django mechanisms, there is more complex steps to setting MFE's behind a Cloudfront CDN. We do not going recommend this route unless your load characteristics require it as the implementation at this stage is filled with caveats.

To serve the static assets generated by Tutor's MFE container, we need to have two things in place:

  • The DNS records for the MFE domain (usually apps.your-domain) needs to point to Cloudfront's.
  • The MFE static assets need to be available under another public domain that Cloudfront will fetch them from.

With all that preamble out of the way, here are the steps to set up MFE's so that they are served by Cloudfront under Grove.

  1. Add the GROVE_MFE_CDN_ORIGIN to your instance's config.yml. Cloudfront will fetch static assets to cache from this domain. Eg. GROVE_MFE_CDN_ORIGIN: apps-static.mydomain.com

  2. Make sure the SHARED_COOKIE_DOMAIN setting is set correctly so that your cookies are available under your MFE and LMS domains.

    LMS_HOST: lms.mydomain.com
    MFE_HOST: apps.mydomain.com
    GROVE_LMS_ENV: |
       SHARED_COOKIE_DOMAIN: '.mydomain.com'
    
  3. Update your infrastructure by running ./tf plan && ./tf apply. At this stage you will get an error:

    ╷
    │ Error: creating CloudFront Distribution: InvalidViewerCertificate: The specified SSL certificate doesn't exist, isn't in us-east-1 region, isn't valid, or doesn't include a valid certificate chain.
    │       status code: 400, request id: 406163b8-b7d2-4e0e-b8e4-d86742c12f63
    │
    │   with module.cloudfront_mfe["one"].aws_cloudfront_distribution.cloudfront_distribution,
    │   on ../provider-modules/cdn-cloudfront/main.tf line 80, in resource "aws_cloudfront_distribution" "cloudfront_distribution":
    │   80: resource "aws_cloudfront_distribution" "cloudfront_distribution" {
    

    In order to provision an SSL certificate for apps.mydomain.com, Cloudfront needs to know that you are the owner of the domain. 4. Since the apply failed, you can get the required domain configuration by running ./tf refresh and getting the output:

    Outputs:
    
    cloudfront_cms_domains = {
      "[instance-name]" = "d2svxb5bathhem.cloudfront.net"
    }
    cloudfront_lms_domains = {
      "[instance-name]" = "d3hhftzv50rp5o.cloudfront.net"
    }
    cloudfront_mfe_domain_validation_options = {
      "[instance-name]" = toset([
        {
          "domain_name" = "apps.mydomain.com"
          "resource_record_name" = "_b5029d7409cc43292fa2fc0727669a39.apps.mydomain.com."
          "resource_record_type" = "CNAME"
          "resource_record_value" = "_42d174cface85416ff0a00721c0661c6.dnzkjbsjxj.acm-validations.aws."
        },
      ])
    }
    
  4. Add the CNAME records as generated by Cloudfront to your DNS provider. In the above case we set up a CNAME record from _b5029d7409cc43292fa2fc0727669a39.apps.mydomain.com. => _42d174cface85416ff0a00721c0661c6.dnzkjbsjxj.acm-validations.aws.

  5. Plan and apply your infrastructure again. This time it should complete without errors and the output will print your instance's new Cloudfront domain under the key cloudfront_mfe_domains.

    cloudfront_cms_domains = {
      "[instance-name]" = "d2svxb5bathhem.cloudfront.net"
    }
    cloudfront_lms_domains = {
      "[instance-name]" = "d3hhftzv50rp5o.cloudfront.net"
    }
    cloudfront_mfe_domain_validation_options = {
      "[instance-name]" = toset([
        {
          "domain_name" = "apps.mydomain.com"
          "resource_record_name" = "_b5029d7409cc43292fa2fc0727669a39.apps.mydomain.com."
          "resource_record_type" = "CNAME"
          "resource_record_value" = "_42d174cface85416ff0a00721c0661c6.dnzkjbsjxj.acm-validations.aws."
        },
      ])
    }
    cloudfront_mfe_domains = {
       "[instance-name]" = "d1cxhc3mkz88ug.cloudfront.net"
    }
    

    Info

    If you still get the above error, and your domain is set up correctly, wait ten minutes. Cloudfront needs to provision the SSL certificate which can sometimes take a while.

  6. Add a CNAME record for your MFE that points to the generated Cloudfront domain. In this case we'll set up apps.mydomain.com => d1cxhc3mkz88ug.cloudfront.net.

  7. Finally, redeploy your instance and test that your assets are being served correctly.

    Warning

    There is a circular dependency between the Cloudfront distribution and the SSL certificate created. Unfortunately it's not possible to update or destroy these dependencies automatically. Any Terraform plan will fail. To work past this, delete the resources first with a targeted destroy.

    ./tf destroy -target 'module.cloudfront_mfe["[instance-name]"]'