1. Docs
  2. Clouds
  3. AWS
  4. Get started
  5. Deploy changes

Pulumi & AWS: Deploy changes

    Now let’s deploy your changes.

    $ pulumi up
    

    Pulumi will run the preview step of the update, which computes the minimally disruptive change to achieve the desired state described by the program.

    Previewing update (dev):
    
         Type                    Name            Plan
         pulumi:pulumi:Stack     quickstart-dev
     +   └─ aws:s3:BucketObject  index.html      create
    
    Resources:
        + 1 to create
        2 unchanged
    
    Do you want to perform this update?
    > yes
      no
      details
    

    Choosing yes will proceed with the update and upload the index.html file to your bucket:

    Do you want to perform this update? yes
    Updating (dev):
    
         Type                    Name            Status
         pulumi:pulumi:Stack     quickstart-dev
     +   └─ aws:s3:BucketObject  index.html      created (0.98s)
    
    
    Outputs:
        bucketName: "my-bucket-58ce361"
    
    Resources:
        + 1 created
        2 unchanged
    
    Duration: 3s
    

    Once the update has completed, you can verify the object was created in your bucket by checking the AWS Console or by running the following AWS CLI command:

    $ aws s3 ls $(pulumi stack output bucketName)
    
    $ aws s3 ls $(pulumi stack output bucketName)
    
    $ aws s3 ls $(pulumi stack output bucket_name)
    
    $ aws s3 ls $(pulumi stack output bucketName)
    
    $ aws s3 ls $(pulumi stack output bucketName)
    
    $ aws s3 ls $(pulumi stack output bucketName)
    
    $ aws s3 ls $(pulumi stack output bucketName)
    

    Notice that your index.html file has been added to the bucket:

    2023-04-20 17:01:06        118 index.html
    

    Now that index.html is in the bucket, update the program to turn the bucket into a website.

    Update the program

    Update the Bucket declaration to add a website property and make index.html the home page of the website:

    const bucket = new aws.s3.Bucket("my-bucket", {
        website: {
            indexDocument: "index.html",
        },
    });
    
    bucket = s3.Bucket("my-bucket",
        website=s3.BucketWebsiteArgs(
            index_document="index.html",
        ),
    )
    
    bucket, err := s3.NewBucket(ctx, "my-bucket", &s3.BucketArgs{
        Website: &s3.BucketWebsiteArgs{
            IndexDocument: pulumi.String("index.html"),
        },
    })
    if err != nil {
        return err
    }
    
    using Pulumi.Aws.S3.Inputs;
    
    var bucket = new Bucket("my-bucket", new()
    {
        Website = new BucketWebsiteArgs
        {
            IndexDocument = "index.html",
        },
    });
    
    import com.pulumi.aws.s3.BucketArgs;
    import com.pulumi.aws.s3.inputs.BucketWebsiteArgs;
    
    var bucket = new Bucket("my-bucket", BucketArgs.builder()
        .website(BucketWebsiteArgs.builder()
            .indexDocument("index.html")
            .build())
        .build());
    
    my-bucket:
      type: aws:s3:Bucket
      properties:
        website:
          indexDocument: index.html
    

    Lastly, you’ll make a few adjustments to make these resources accessible on the Internet.

    For the bucket itself, you’ll need two new resources: a BucketOwnershipControls resource, to define the bucket’s file-ownership settings, and a BucketPublicAccessBlock resource to allow the bucket to be accessed publicly.

    For the BucketObject, you’ll need an access-control (ACL) setting of public-read to allow the page to be accessed anonymously (e.g., in a browser) and a content type of text/html to tell AWS to serve the file as a web page. Add the following lines to your program, updating the BucketObject in place:

    const ownershipControls = new aws.s3.BucketOwnershipControls("ownership-controls", {
        bucket: bucket.id,
        rule: {
            objectOwnership: "ObjectWriter"
        }
    });
    
    const publicAccessBlock = new aws.s3.BucketPublicAccessBlock("public-access-block", {
        bucket: bucket.id,
        blockPublicAcls: false,
    });
    
    const bucketObject = new aws.s3.BucketObject("index.html", {
        bucket: bucket.id,
        source: new pulumi.asset.FileAsset("./index.html"),
        contentType: "text/html",
        acl: "public-read",
    }, { dependsOn: [publicAccessBlock,ownershipControls] });
    
    ownership_controls = s3.BucketOwnershipControls(
        'ownership-controls',
        bucket=bucket.id,
        rule=s3.BucketOwnershipControlsRuleArgs(
            object_ownership='ObjectWriter',
        ),
    )
    
    public_access_block = s3.BucketPublicAccessBlock(
        'public-access-block', bucket=bucket.id, block_public_acls=False
    )
    
    bucket_object = s3.BucketObject(
        'index.html',
        bucket=bucket.id,
        source=pulumi.FileAsset('index.html'),
        content_type='text/html',
        acl='public-read',
        opts=pulumi.ResourceOptions(depends_on=[public_access_block, ownership_controls]),
    )
    
    import (
    	"fmt"
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/s3"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    ownershipControls, err := s3.NewBucketOwnershipControls(ctx, "ownership-controls", &s3.BucketOwnershipControlsArgs{
        Bucket: bucket.ID(),
        Rule: &s3.BucketOwnershipControlsRuleArgs{
            ObjectOwnership: pulumi.String("ObjectWriter"),
        },
    })
    if err != nil {
        return err
    }
    
    publicAccessBlock, err := s3.NewBucketPublicAccessBlock(ctx, "public-access-block", &s3.BucketPublicAccessBlockArgs{
        Bucket:          bucket.ID(),
        BlockPublicAcls: pulumi.Bool(false),
    })
    if err != nil {
        return err
    }
    
    _, err = s3.NewBucketObject(ctx, "index.html", &s3.BucketObjectArgs{
        Bucket:      bucket.ID(),
        Source:      pulumi.NewFileAsset("index.html"),
        ContentType: pulumi.String("text/html"),
        Acl:         pulumi.String("public-read"),
    }, pulumi.DependsOn([]pulumi.Resource{
    			publicAccessBlock,
    			ownershipControls,
    }))
    if err != nil {
        return err
    }
    
    var ownershipControls = new BucketOwnershipControls("ownership-controls", new()
    {
        Bucket = bucket.Id,
        Rule = new BucketOwnershipControlsRuleArgs
        {
            ObjectOwnership = "ObjectWriter",
        },
    });
    
    var publicAccessBlock = new BucketPublicAccessBlock("public-access-block", new()
    {
        Bucket = bucket.Id,
        BlockPublicAcls = false,
    });
    
    var indexHtml = new BucketObject("index.html", new()
    {
        Bucket = bucket.Id,
        Source = new FileAsset("./index.html"),
        ContentType = "text/html",
        Acl = "public-read",
    }, new CustomResourceOptions
    {
        DependsOn = new Resource[]
        {
            publicAccessBlock,
            ownershipControls,
        },
    });
    
    import com.pulumi.aws.s3.BucketOwnershipControls;
    import com.pulumi.aws.s3.BucketOwnershipControlsArgs;
    import com.pulumi.aws.s3.inputs.BucketOwnershipControlsRuleArgs;
    import com.pulumi.aws.s3.BucketPublicAccessBlock;
    import com.pulumi.aws.s3.BucketPublicAccessBlockArgs;
    import com.pulumi.resources.CustomResourceOptions;
    import com.pulumi.asset.FileAsset;
    
    var ownershipControls = new BucketOwnershipControls("ownershipControls", BucketOwnershipControlsArgs.builder()
        .bucket(bucket.id())
        .rule(BucketOwnershipControlsRuleArgs.builder()
            .objectOwnership("ObjectWriter")
            .build())
        .build());
    
    var publicAccessBlock = new BucketPublicAccessBlock("publicAccessBlock", BucketPublicAccessBlockArgs.builder()
        .bucket(bucket.id())
        .blockPublicAcls(false)
        .build());
    
    var indexHtml = new BucketObject("index.html", BucketObjectArgs.builder()
        .bucket(bucket.id())
        .source(new FileAsset("./index.html"))
        .contentType("text/html")
        .acl("public-read")
        .build(), CustomResourceOptions.builder()
            .dependsOn(
                publicAccessBlock,
                ownershipControls)
            .build());
    
    
    resources:
      # ...
    
      ownership-controls:
        type: aws:s3:BucketOwnershipControls
        properties:
          bucket: ${my-bucket.id}
          rule:
            objectOwnership: ObjectWriter
    
      public-access-block:
        type: aws:s3:BucketPublicAccessBlock
        properties:
          bucket: ${my-bucket.id}
          blockPublicAcls: false
    
      index.html:
        type: aws:s3:BucketObject
        properties:
          bucket: ${my-bucket.id}
          source:
            fn::fileAsset: ./index.html
          contentType: text/html
          acl: public-read
        options:
          dependsOn:
            - ${public-access-block}
            - ${ownership-controls}
    

    Note that the BucketObject also includes the Pulumi resource option dependsOn. This setting tells Pulumi that the BucketObject relies indirectly on the BucketPublicAccessBlock, which is responsible for enabling public access to its contents. If you omitted this setting, the attempt to grant public-read access to index.html would fail, as all S3 buckets and their objects are blocked from public access by default.

    Finally, at the end of the program, export the resulting bucket’s endpoint URL so you can browse to it easily:

    exports.bucketEndpoint = pulumi.interpolate`http://${bucket.websiteEndpoint}`;
    
    export const bucketEndpoint = pulumi.interpolate`http://${bucket.websiteEndpoint}`;
    
    pulumi.export('bucket_endpoint', pulumi.Output.concat('http://', bucket.website_endpoint))
    
    ctx.Export("bucketEndpoint", bucket.WebsiteEndpoint.ApplyT(func(websiteEndpoint string) (string, error) {
        return fmt.Sprintf("http://%v", websiteEndpoint), nil
    }).(pulumi.StringOutput))
    
    return new Dictionary<string, object?>
    {
        // ...
        ["bucketEndpoint"] = bucket.WebsiteEndpoint.Apply(websiteEndpoint => $"http://{websiteEndpoint}"),
    };
    
    // ...
    ctx.export("bucketEndpoint", bucket.websiteEndpoint().applyValue(websiteEndpoint -> String.format("http://%s", websiteEndpoint)));
    
    outputs:
      # ...
      bucketEndpoint: http://${my-bucket.websiteEndpoint}
    

    Deploy the website

    You may need to grant permissions to your S3 object, index.html. Ensure it has public read access if intended.

    Update your stack to deploy these changes to AWS:

    $ pulumi up
    

    Again, you’ll see a preview of the changes before they’re deployed:

    Previewing update (dev):
    
         Type                               Name                 Plan       Info
         pulumi:pulumi:Stack                quickstart-dev
     ~   ├─ aws:s3:Bucket                   my-bucket            update     [diff: +website]
     +   ├─ aws:s3:BucketOwnershipControls  ownership-controls   create
     +   ├─ aws:s3:BucketPublicAccessBlock  public-access-block  create
     ~   └─ aws:s3:BucketObject             index.html           update     [diff: ~acl,contentType]
    
    Outputs:
      + bucketEndpoint: output<string>
    
    Resources:
        + 2 to create
        ~ 2 to update
        4 changes. 1 unchanged
    
    Do you want to perform this update?
    > yes
      no
      details
    

    Choose yes to perform the deployment:

    Do you want to perform this update? yes
    Updating (dev):
    
         Type                               Name                 Status              Info
         pulumi:pulumi:Stack                quickstart-dev
     ~   ├─ aws:s3:Bucket                   my-bucket            updated (3s)        [diff: +website]
     +   ├─ aws:s3:BucketOwnershipControls  ownership-controls   created (0.84s)
     +   ├─ aws:s3:BucketPublicAccessBlock  public-access-block  created (1s)
     ~   └─ aws:s3:BucketObject             index.html           updated (0.53s)     [diff: ~acl,contentType]
    
    Outputs:
      + bucketEndpoint: "http://my-bucket-dfd6bd0.s3-website-us-east-1.amazonaws.com"
        bucketName    : "my-bucket-dfd6bd0"
    
    Resources:
        + 2 created
        ~ 2 updated
        4 changes. 1 unchanged
    
    Duration: 8s
    

    When the deployment completes, you can check out your new website at the URL in the Outputs section of your update or make a curl request and see the contents of index.html in your terminal:

    $ curl $(pulumi stack output bucketEndpoint)
    
    $ curl $(pulumi stack output bucketEndpoint)
    
    $ curl $(pulumi stack output bucket_endpoint)
    
    $ curl $(pulumi stack output bucketEndpoint)
    
    $ curl $(pulumi stack output bucketEndpoint)
    
    $ curl $(pulumi stack output bucketEndpoint)
    
    $ curl $(pulumi stack output bucketEndpoint)
    

    And you should see:

    <html>
        <body>
            <h1>Hello, Pulumi!</h1>
        </body>
    </html>
    

    Next, you’ll destroy the resources.

      Introducing Pulumi Copilot - Intelligent Cloud Management