Website Component
Deploys a static website with a CDN in front of object storage. Suitable for single-page applications, static sites, and front-end assets. Multiple website components can be declared in the same configuration — for example, a public marketing site and a separate admin portal, each with its own domain.
Configuration Fields
Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | required | — | Must be "website" |
name | string | required | — | Unique component name. Becomes part of the globally unique resource name. |
domain | string | required | — | The full domain name for this website (e.g. www.example.com or app.prod.example.com). The base domain is derived automatically as the last two labels (e.g. example.com) and must already be registered and have a hosted zone configured in your cloud provider. The plugin provisions the DNS record and HTTPS certificate for the full domain. |
indexDocument | string | optional | "index.html" | The default document served for directory requests. |
errorDocument | string | optional | "index.html" | The document served for 404 errors. Set to your SPA entry point for client-side routing. |
httpsOnly | boolean | optional | true | Redirect HTTP to HTTPS. Strongly recommended. |
cacheMaxAgeSeconds | integer | optional | 86400 | CDN cache TTL in seconds. Set to 0 to disable caching. |
uploads | array | optional | — | List of Maven artifact upload definitions. Each entry deploys static content (HTML, CSS, JS) to the origin bucket at deploy time. Uses the same format as the Storage component's uploads field. See Storage component for full Upload Object documentation. |
references | array of strings | optional | — | Names of components this website references. Supported targets: api-gateway. The plugin infers the relationship type and configures CORS automatically. Prefer using the links array with full link objects instead. |
accessGate | object | optional | — | Puts an HTTP Basic username/password prompt in front of the whole site at the CDN edge. Credentials come from a secret (never inline). See Access Gate below. (AWS) |
edgeFunctions | array | optional | — | Associates a user-provided CloudFront Function with the distribution on the viewer-request event (e.g. an edge language router). See Edge Functions below. (AWS) |
The website component always provisions its own CDN-backed storage bucket for static assets. You do not need a separate storage component for website files — it is created automatically.
Initial Content Upload
Use the uploads field in providerSettings to deploy initial static content (HTML, CSS, JavaScript) to the origin bucket as part of the website deployment. This is especially useful for deploying pre-built frontend applications from Maven artifacts.
The upload format is identical to the Storage component's uploads field — including support for ${version} interpolation, inline classifier and extension in the artifact coordinate, and unpack: true for extracting archives.
{
"type": "website",
"name": "admin-tool",
"providerSettings": {
"domain": "admin.example.com",
"uploads": [
{
"artifact": "com.example:admin-ui:${version}:dist:zip",
"destination": "",
"unpack": true
}
]
},
"links": []
}
In this example, the artifact admin-ui-1.0.0-dist.zip is extracted and its contents are uploaded to the root of the origin bucket, making them immediately available via CloudFront.
Uploads run during the serverless:deploy phase, after the CloudFront distribution and bucket policy are configured. If the origin bucket already has content, uploads overwrite existing objects at the same path.
The base domain (last two labels of domain) must already be registered and have a hosted zone configured in your cloud provider — Route 53 (AWS), Azure DNS, or Cloud DNS (GCP). The plugin derives the base domain automatically: www.example.com → base example.com, app.prod.example.com → base example.com. It then provisions the full DNS record and an HTTPS certificate for the exact domain you specify.
Path-Based Storage Routing
Use WEBSITE_TO_STORAGE links with a path property to route specific URL paths to separate storage buckets. This is useful for serving large assets, user uploads, or media files from a dedicated bucket while keeping the main website content in the origin bucket.
{
"type": "website",
"name": "frontend",
"providerSettings": {
"domain": "www.example.com"
},
"links": [
{
"sourceComponent": "frontend",
"targetComponent": "asset-store",
"linkType": "WEBSITE_TO_STORAGE",
"path": "/assets"
},
{
"sourceComponent": "frontend",
"targetComponent": "media-bucket",
"linkType": "WEBSITE_TO_STORAGE",
"path": "/media"
}
]
}
In this example:
- Requests to /assets/* are served from the asset-store S3 bucket
- Requests to /media/* are served from the media-bucket S3 bucket
- All other requests are served from the website's own origin bucket
The path property is required on WEBSITE_TO_STORAGE links and must start with /. The target storage component must be defined in the configuration. The plugin automatically configures CloudFront cache behaviors and sets bucket policies on the target buckets for secure access.
Azure: each WEBSITE_TO_STORAGE path is derived into a Front Door route pointing at the linked Storage Account origin ({path}/* → the target account). Route derivation is applied during deployment; provisioning the Front Door profile itself requires the azure-resourcemanager-cdn module (pending) — until then the derived routes are logged and the Static Web App resource ID is returned.
Access Gate (edge HTTP Basic auth)
The optional accessGate setting puts a username/password prompt in front of the entire site at the CDN edge. When enabled, every viewer request must carry a valid Authorization: Basic header, or the CDN returns 401 Unauthorized with a WWW-Authenticate: Basic realm="…" challenge, so browsers show a login prompt. It is ideal for gating staging or pre-release environments without adding application-level auth.
On AWS this is implemented as a CloudFront Function (runtime cloudfront-js-2.0) associated with the distribution's default cache behavior on the viewer-request event. The function is named {derived-name}-site-gate.
Credentials are never stored in configuration. They live in an AWS Secrets Manager secret that you reference by name or ARN. At deploy time the plugin reads the secret, computes the base64 Basic tokens, and bakes those tokens (never the raw passwords) into the generated edge function. CloudFront Functions cannot make network calls at request time, so the accepted credential set is fixed at deploy — rotate the secret and redeploy the website to change credentials.
accessGate Fields
Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | boolean or string | optional | false | Whether the gate is active. Accepts a boolean or the string "true"/"false" so it can be driven per environment via ${variable} substitution. Absent means disabled. |
credentialsSecret | string | when enabled | — | The Secrets Manager secret name or ARN holding the credentials. Required whenever enabled is true. |
realm | string | optional | "Restricted" | The HTTP Basic realm shown in the browser prompt. |
Secret Payload Formats
The referenced secret may hold multiple credentials in any of these forms:
- A JSON array of objects: [ { "username": "alice", "password": "s3cret" } ]
- A JSON object mapping username to password: { "alice": "s3cret", "bob": "hunter2" }
- Newline-separated username:password lines (blank lines and # comments are ignored).
Example
{
"type": "website",
"name": "marketing-site",
"providerSettings": {
"domain": "www.example.com",
"accessGate": {
"enabled": "${siteGateEnabled}",
"credentialsSecret": "example/site-gate-credentials",
"realm": "Example Staging"
}
},
"links": []
}
Set siteGateEnabled to true in your staging variables and false in production to gate only pre-release environments. Disabling the gate and redeploying removes the function association; running serverless:undeploy deletes the CloudFront Function.
The access gate coexists with a WAF (WAF_TO_WEBSITE) association — only the default cache behavior's edge-function association is changed, so the distribution's WAF Web ACL is preserved on update.
Deploy permissions: enabling an access gate requires secretsmanager:GetSecretValue plus the CloudFront function actions (CreateFunction, UpdateFunction, PublishFunction, DescribeFunction, DeleteFunction) on the deploy identity — see Credentials.
Edge Functions (viewer-request)
The optional edgeFunctions setting associates a user-provided CloudFront Function with the distribution's default cache behavior on the viewer-request event. The function runs on every viewer request at the edge and can inspect or rewrite the request — for example, rewriting a bare path such as / to a localized document like /en/home.html based on a cookie or the Accept-Language header.
The function source is a project-relative JavaScript file, resolved against src/main/serverless (the same directory as config.json). It is read at deploy time, published as a cloudfront-js-2.0 function named {derived-name}-edge-viewer-request, and associated with the distribution. Redeploying updates the function code in place; serverless:undeploy deletes it after the distribution is removed.
edgeFunctions Fields (per entry)
Field | Type | Required | Default | Description |
|---|---|---|---|---|
event | string | required | — | The CloudFront event. Only "viewer-request" is currently supported. |
runtime | string | optional | "cloudfront-function" | The runtime discriminator. Only "cloudfront-function" is currently supported. |
source | string | required | — | Project-relative path to the function source JavaScript, resolved against src/main/serverless. Must stay within that directory — absolute paths and .. traversal are rejected by validation. |
variables | object | optional | — | Deploy-time ${key} substitutions applied to the source (string values). Unknown placeholders are left untouched, so sources may also be fully self-contained. |
Example
{
"type": "website",
"name": "marketing-site",
"providerSettings": {
"domain": "www.example.com",
"edgeFunctions": [
{
"event": "viewer-request",
"runtime": "cloudfront-function",
"source": "edge/language-router.js",
"variables": { "supportedLanguages": "['en','fr','de']" }
}
]
},
"links": []
}
Here src/main/serverless/edge/language-router.js is read at deploy time, any ${supportedLanguages} placeholder in it is replaced with ['en','fr','de'], and the result is published and associated on viewer-request.
One viewer-request function per website. CloudFront allows only one function association per event type per cache behavior. A viewer-request edge function and an enabled access gate (which also uses viewer-request) are therefore mutually exclusive — serverless:validate fails if both are declared on the same website. If you need both behaviors, fold the access check into your own edge function source and use only edgeFunctions.
Deploy permissions: edge functions require the CloudFront function actions (CreateFunction, UpdateFunction, PublishFunction, DescribeFunction, DeleteFunction) on the deploy identity — all covered by cloudfront:*. No Secrets Manager access is needed for edge functions.
Cloud Resources Created
- S3 Bucket — automatically created to store the website files. Named {derived-name}. Versioning disabled by default.
- CloudFront Distribution — CDN in front of the S3 bucket. Origin access control (OAC) restricts direct S3 access. HTTPS enforced. Compression is always enabled. Uses the AWS managed CachingOptimized cache policy (ID: 658327ea-f89d-4fab-a63d-7e88639e58f6) for optimal performance. Custom error responses are configured for 403 and 404 errors using errorDocument (defaults to index.html) with HTTP 200 status — this enables SPA client-side routing.
- S3 Bucket Policy — grants CloudFront OAC read access to the bucket.
- ACM Certificate — provisioned in us-east-1 for the configured domain. DNS-validated against the base domain's Route 53 hosted zone.
- Route 53 Record — ALIAS record for the domain pointing to the CloudFront distribution.
- CloudFront Function (only when accessGate.enabled) — a cloudfront-js-2.0 function named {derived-name}-site-gate that enforces HTTP Basic auth on the viewer-request event. Credentials are read from Secrets Manager at deploy time and baked in as base64 tokens. Removed on undeploy.
- CloudFront Function (only when an edgeFunctions viewer-request entry is declared) — a cloudfront-js-2.0 function named {derived-name}-edge-viewer-request, published from your source file and associated on the viewer-request event. Updated in place on redeploy; removed on undeploy.
Redeploy Behavior: When the CloudFront distribution already exists, the deployer updates it with the latest configuration (compress, cache policy, error responses, path-based storage origins) rather than skipping it.
Path Routing: Each WEBSITE_TO_STORAGE link with a path property adds an additional S3 origin and a cache behavior for that path pattern. The OAC is shared, and bucket policies are automatically set on target buckets.
Limitations: The base domain must have an existing Route 53 hosted zone. Certificate DNS validation may take a few minutes on first deploy.
- Azure Static Web Apps — managed hosting with built-in CDN and HTTPS.
- Managed Certificate — provisioned automatically for the configured domain.
- Custom Domain Binding — binds the domain to the Static Web App. Requires an existing Azure DNS zone for the base domain.
- Azure DNS Record — CNAME record for the domain pointing to the Static Web App endpoint.
Limitations: Free tier has bandwidth limits. The base domain must have an existing Azure DNS zone.
Path Routing: WEBSITE_TO_STORAGE links with path configure Azure Front Door with additional origin groups and routing rules pointing to the target Blob Storage accounts.
- Cloud Storage Bucket — automatically created to store website files.
- Cloud CDN + Load Balancer — global CDN backed by the storage bucket. HTTPS enforced.
- Backend Bucket — connects the load balancer to the storage bucket.
- Google-Managed SSL Certificate — provisioned for the configured domain.
- Cloud DNS Record — A record for the domain pointing to the load balancer. Requires an existing Cloud DNS zone for the base domain.
Limitations: Cloud CDN requires a global load balancer, which incurs a fixed monthly cost. The base domain must have an existing Cloud DNS zone.
Path Routing: WEBSITE_TO_STORAGE links with path are derived into URL map path matchers pointing at backend buckets for the target Cloud Storage buckets (real, tested derivation). The URL map itself is provisioned once the google-cloud-compute module is on the classpath; until then the derived routes are logged and the URL map resource ID is returned.
JSON Example
{
"type": "website",
"name": "frontend",
"providerSettings": {
"domain": "www.example.com",
"indexDocument": "index.html",
"errorDocument": "index.html",
"httpsOnly": true,
"cacheMaxAgeSeconds": 3600,
"uploads": [
{
"artifact": "com.example:frontend-dist:${version}:static:zip",
"destination": "",
"unpack": true
}
]
},
"links": [
{
"sourceComponent": "frontend",
"targetComponent": "main-api",
"linkType": "WEBSITE_TO_API_GATEWAY"
}
]
}
Links
Use the links array to declare which components this website connects to. The plugin infers the relationship type from the target component type and configures permissions automatically.