# `cloudfront-static-website`

Creates a static website hosted on S3 with CloudFront distribution, SSL certificate, and custom domain.

!!! note
    This stack might take a **long time** to both **apply** and **destroy** due to the CloudFront distribution. Deployment typically takes around 5 minutes, while destruction can take 5-6 minutes.

!!! note
    This template has a dependency on the [CloudFront data template](../cloudfront-static-website-data/) which creates the S3 buckets used for content and logging.

## Architecture

This template creates the CloudFront distribution and associated resources that work with the S3 buckets created by the [CloudFront data stack](../cloudfront-static-website-data/):

- **CloudFront Distribution** - CDN with custom domain, SSL, and SPA routing
- **Route53 Record** - DNS alias pointing to CloudFront
- **ACM Certificate** - SSL certificate for custom domain (us-east-1)
- **IAM Role** (optional) - GitHub OIDC role for CI/CD deployments

The S3 buckets (content and logs) are created separately in the [Data stack](../cloudfront-static-website-data/) to allow for independent lifecycle management.

## Features

- HTTPS-only with custom domain
- Client-side routing support (when `ClientSideRouting.Enable: true`) - 403 errors redirect to 200 `index.html` (similar to [react-cors-spa](https://github.com/aws-samples/react-cors-spa))
- Optional URL rewriting (when `DirectoryBehavior.AddToAllUrls: true`) - adds `index.html` to directory requests and URLs without extensions, based on [AWS CloudFront Functions sample](https://github.com/aws-samples/amazon-cloudfront-functions/tree/main/url-rewrite-single-page-apps)
- Configurable root and error objects via `DirectoryBehavior`
- GitHub Actions deployment permissions (when enabled)

## Configuration

This template uses variables defined in the boilerplate configuration. See the Variables section below for the complete list of available options.

## Usage

### With Boilerplate

1. Generate the [CloudFront data template](../cloudfront-static-website-data/) first (if not already done)
2. Generate this template with your `Name`
3. Update `config_override.tf` with your AWS account/environment details
4. Run `terraform apply`
5. Upload static files to the S3 bucket created by the data stack
6. Access your site at `https://{Name}.{environment}.oslo.systems`

### With `ok` and configuration files

Create the following files in your project directory (e.g., `monkey-web`):

`packages.yml`:

```yaml
Packages:
  - OutputFolder: .
    Ref: main
    Template: cloudfront-static-website
    VarFiles:
      - ../common-config.yml
      - package-config.yml
```

`package-config.yml`:

```yaml
StackName: "web-monkey"
cloudfront-static-website-data.StackName: "web-monkey-data"
Name: "monkey"
IamForCicd:
  Enable: true
  GitHubRepo: golden-path-iac
```

Then run:

1. `ok pkg install` - Terraform files will appear
2. `cd` to the data stack directory, apply that with `terraform apply`
3. Go back to the main directory (`web-monkey`) and apply with `terraform apply`
4. Upload static files to the S3 bucket created by the data stack
5. Access your site at `https://{Name}.{environment}.oslo.systems`

## Deployment

### Manual Deployment

Upload static files manually to the S3 bucket created by the [CloudFront data stack](../cloudfront-static-website-data/).

### Automated Deployment

For automated deployments, use the [CloudFront deploy workflow](../../github-actions/cloudfront-deploy/) template which:

- Builds your static site using Docker
- Syncs files to the S3 bucket
- Creates CloudFront cache invalidations

When `IamForCicd.Enable` is true, a GitHub OIDC role is created with permissions to:

- Upload files to S3 bucket
- Create CloudFront invalidations
- Deploy from GitHub Actions workflows

The role can be assumed by GitHub Actions in the specified repository.

<!-- BOILERPLATE BEGIN -->
<!-- Generated by running `make docs` from the `boilerplate` dir) -->
<!-- Updated automatically in release PRs -->

## Variables

|           Name           |                                                                                                            Description                                                                                                             |  Type  |                 Default                 |Required|
|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|-----------------------------------------|--------|
|`Name`                    |Website name. Used as the subdomain, exposing the site at `https://<Name>.<Environment>.oslo.systems`.                                                                                                                              |`string`|``n/a``                                  |yes     |
|`RedirectAllToIndex`      |Serve `RootObject` with status `200` for every request that does not match a file, instead of the `ErrorObject` error page. Needed for single-page apps with client-side routing.                                                   |`bool`  |``false``                                |no      |
|`RootObject`              |The object served when the site root (`/`) is requested. Also the object that `RedirectAllToIndex` and `AppendIndexToDirectories` rewrite requests to.                                                                              |`string`|``index.html``                           |no      |
|`ErrorObject`             |The object served with status `404` when a requested file does not exist. Not used when `RedirectAllToIndex` is enabled.                                                                                                            |`string`|``404.html``                             |no      |
|`AppendIndexToDirectories`|Rewrite requests ending in `/` or without a file extension to append `/<RootObject>`, so `/about` serves `about/index.html`. Useful for static site generators that output one `index.html` per directory.                          |`bool`  |``false``                                |no      |
|`DeploymentPipelineV2`    |Deploy the website with the next-generation deployment pipeline. Replaces `IamForCicd`.                                                                                                                                             |`map`   |``{"Enable": false}``                    |no      |
|`IamForCicd`              |Deprecated: use `DeploymentPipelineV2` instead. Lets GitHub Actions in the website's repository (`GitHubRepo`, under the `oslokommune` org) deploy the site. The workflow must run in the GitHub environment `<Environment>-<Name>`.|`map`   |``{"Enable": false, "GitHubRepo": null}``|no      |

<!-- BOILERPLATE END -->
