Skip to content

Commit 006d27c

Browse files
authored
fix: align S3 static-website tutorial with sample, fix bucket name and output discrepancies (#495)
1 parent 3c3ee0f commit 006d27c

1 file changed

Lines changed: 37 additions & 40 deletions

File tree

src/content/docs/aws/tutorials/s3-static-website-terraform.mdx

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,15 @@ In this architecture:
5353
We will create a simple static website using plain HTML to get started.
5454
To create a static website deployed over S3, we need to create an index document and a custom error document.
5555
We will name our index document `index.html` and our error document `error.html`.
56-
Optionally, you can create a folder called `assets` to store images and other assets.
5756

58-
Let's create a directory named `s3-static-website-localstack` where we'll store our static website files.
59-
If you don't have an `index.html` file, you can use the following code to create one:
57+
Let's create a directory named `s3-static-website-localstack` where we'll store our project files, with a `www/` subdirectory that holds the website content:
58+
59+
```bash
60+
mkdir -p s3-static-website-localstack/www
61+
cd s3-static-website-localstack
62+
```
63+
64+
Inside `www/`, create an `index.html` file with the following content:
6065

6166
```html showLineNumbers
6267
<!DOCTYPE html>
@@ -74,7 +79,7 @@ If you don't have an `index.html` file, you can use the following code to create
7479

7580
S3 will serve this file when a user visits the root URL of your static website, serving as the default page.
7681
In a similar fashion, you can configure a custom error document that contains a user-friendly error message.
77-
Let's create a file named `error.html` and add the following code:
82+
Create a file named `error.html` next to `index.html` inside `www/` and add the following code:
7883

7984
```html showLineNumbers
8085
<!DOCTYPE html>
@@ -105,7 +110,7 @@ awslocal s3api create-bucket --bucket testwebsite
105110
```
106111

107112
With the bucket created, we can now attach a policy to it to allow public access and its contents.
108-
Let's create a file named `bucket_policy.json` in the root directory and add the following code:
113+
Let's create a file named `bucket_policy.json` in the project root (next to the `www/` folder) and add the following code:
109114

110115
```json showLineNumbers
111116
{
@@ -128,10 +133,10 @@ Let's now attach the policy to the bucket:
128133
awslocal s3api put-bucket-policy --bucket testwebsite --policy file://bucket_policy.json
129134
```
130135

131-
With the policy attached, we can now sync the contents of our root directory to the bucket:
136+
With the policy attached, we can now sync the contents of our `www/` directory to the bucket:
132137

133138
```bash
134-
awslocal s3 sync ./ s3://testwebsite
139+
awslocal s3 sync ./www/ s3://testwebsite
135140
```
136141

137142
We'll now enable static website hosting on the bucket and configure the index and error documents:
@@ -169,7 +174,7 @@ provider "aws" {
169174
We would also need to avoid issues with routing and authentication (as we do not need it).
170175
Therefore we need to supply some general parameters.
171176
Additionally, we have to point the individual services to LocalStack.
172-
We can do this by specifying the `endpoints` parameter for each service, that we intend to use.
177+
We can do this by specifying the `endpoints` parameter for each service that we intend to use.
173178
Our `provider.tf` file should look like this:
174179

175180
```hcl showLineNumbers
@@ -179,13 +184,14 @@ provider "aws" {
179184
region = "us-east-1"
180185
181186
# only required for non virtual hosted-style endpoint use case.
182-
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs#s3_force_path_style
187+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs#s3_use_path_style
183188
s3_use_path_style = false
184189
skip_credentials_validation = true
185190
skip_metadata_api_check = true
186191
187192
endpoints {
188-
s3 = "http://s3.localhost.localstack.cloud:4566"
193+
s3 = "http://s3.localhost.localstack.cloud:4566"
194+
s3control = "http://localhost.localstack.cloud:4566"
189195
}
190196
}
191197
```
@@ -197,6 +203,11 @@ We also publish an SSL certificate which is automatically used inside LocalStack
197203
For most of the other services, it is fine to use `localhost:4566`.
198204
:::
199205

206+
:::note
207+
The `s3control` endpoint is required because recent versions of the AWS Terraform provider use the S3 Control API to read bucket tags.
208+
We point it at `localhost.localstack.cloud` so the account-id-prefixed hostname (`<account-id>.localhost.localstack.cloud`) resolves to LocalStack.
209+
:::
210+
200211
With the provider configured, we can now configure the variables for our S3 bucket.
201212
Create a new file named `variables.tf` and add the following code:
202213

@@ -230,15 +241,18 @@ output "name" {
230241
231242
output "domain" {
232243
description = "Domain name of the bucket"
233-
value = aws_s3_bucket_website_configuration.s3_bucket.website_domain
244+
value = "s3-website.localhost.localstack.cloud:4566"
234245
}
235246
236247
output "website_endpoint" {
237-
value = aws_s3_bucket_website_configuration.s3_bucket.website_endpoint
248+
description = "Website endpoint URL"
249+
value = "http://${aws_s3_bucket.s3_bucket.id}.s3-website.localhost.localstack.cloud:4566"
238250
}
239251
```
240252

241-
The output variables are the ARN, name, domain name, and website endpoint of the bucket.
253+
The output variables are the ARN, name, LocalStack S3 website domain, and the full website endpoint URL of the bucket.
254+
We hardcode the `domain` and `website_endpoint` values to point at LocalStack so that the outputs surface a URL you can open directly.
255+
The native `aws_s3_bucket_website_configuration` attributes return the AWS-formatted endpoint (`<bucket>.s3-website-<region>.amazonaws.com`), which would be misleading in a LocalStack-only setup.
242256
With all the configuration files in place, we can now create the S3 bucket.
243257
Create a new file named `main.tf` and create the S3 bucket using the following code:
244258

@@ -305,7 +319,7 @@ Add the following code to the `main.tf` file:
305319
```hcl showLineNumbers
306320
resource "aws_s3_object" "object_www" {
307321
depends_on = [aws_s3_bucket.s3_bucket]
308-
for_each = fileset("${path.root}", "*.html")
322+
for_each = fileset("${path.root}", "www/*.html")
309323
bucket = var.bucket_name
310324
key = basename(each.value)
311325
source = each.value
@@ -315,22 +329,7 @@ resource "aws_s3_object" "object_www" {
315329
}
316330
```
317331

318-
The above code uploads all our html files to the bucket.
319-
We are also setting the ACL of the files to `public-read`.
320-
Optionally, if you have static assets like images, CSS, and JavaScript files, you can upload them to the bucket using the same `aws_s3_bucket_object` resource by adding the following code to the `main.tf` file:
321-
322-
```hcl showLineNumbers
323-
resource "aws_s3_object" "object_assets" {
324-
depends_on = [aws_s3_bucket.s3_bucket]
325-
for_each = fileset(path.module, "assets/*")
326-
bucket = var.bucket_name
327-
key = each.value
328-
source = "${each.value}"
329-
etag = filemd5("${each.value}")
330-
acl = "public-read"
331-
}
332-
```
333-
332+
The above code uploads every `.html` file under `www/` to the bucket and sets each object's ACL to `public-read`.
334333
With all the configuration files in place, we can now initialize the Terraform configuration.
335334
Run the following command to initialize the Terraform configuration:
336335

@@ -359,20 +358,18 @@ var.bucket_name
359358
Name of the s3 bucket.
360359
Must be unique.
361360

362-
Enter a value: testbucket
361+
Enter a value: testwebsite
363362
...
364-
arn = "arn:aws:s3:::testbucket"
365-
domain = "s3-website-us-east-1.amazonaws.com"
366-
name = "testbucket"
367-
website_endpoint = "testbucket.s3-website-us-east-1.amazonaws.com"
363+
arn = "arn:aws:s3:::testwebsite"
364+
domain = "s3-website.localhost.localstack.cloud:4566"
365+
name = "testwebsite"
366+
website_endpoint = "http://testwebsite.s3-website.localhost.localstack.cloud:4566"
368367
```
369368

370-
In the above command, we specified `testbucket` as the bucket name.
369+
In the above command, we specified `testwebsite` as the bucket name to keep it consistent with the `awslocal` flow above and the testing commands further down.
371370
You can specify any bucket name since LocalStack is ephemeral, and stopping your LocalStack container will delete all the created resources.
372-
The above command output includes the ARN, name, domain name, and website endpoint of the bucket.
373-
You can see the `website_endpoint` configured to use AWS S3 Website Endpoint.
374-
You can now access the website using the bucket name in the following format: `http://<BUCKET_NAME>.s3-website.localhost.localstack.cloud:4566`.
375-
Since the endpoint is configured to use `localhost.localstack.cloud`, no real AWS resources have been created.
371+
The above command output includes the ARN, name, LocalStack website domain, and the website endpoint URL of the bucket.
372+
You can navigate directly to the printed `website_endpoint` to view your site, since the endpoint uses `localhost.localstack.cloud`, no real AWS resources have been created.
376373

377374
You can optionally use the `tflocal` CLI as a drop-in replacement for the official Terraform CLI. `tflocal` uses the Terraform Override mechanism to create a temporary `localstack_providers_override.tf` file, which is deleted after the infrastructure is created.
378375
It mitigates the need to create the `provider.tf` file manually.

0 commit comments

Comments
 (0)