Create AWS Lightsail CDN Distributions

The aws:lightsail/distribution:Distribution resource, part of the Pulumi AWS provider, defines a Lightsail CDN distribution that caches content at edge locations and routes requests to origin resources. This guide focuses on three capabilities: bucket origins for static content, instance origins for dynamic applications, and load balancer origins for high-availability services.

Distributions reference existing Lightsail resources and may require static IP or load balancer attachments to be in place first. The examples are intentionally small. Combine them with your own SSL certificates, custom cache behaviors, and monitoring.

Cache content from a Lightsail bucket

Most CDN deployments start by caching static assets stored in object storage, reducing latency for users worldwide.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.lightsail.Bucket("example", {
    name: "example-bucket",
    bundleId: "small_1_0",
});
const exampleDistribution = new aws.lightsail.Distribution("example", {
    name: "example-distribution",
    bundleId: "small_1_0",
    origin: {
        name: example.name,
        regionName: example.region,
    },
    defaultCacheBehavior: {
        behavior: "cache",
    },
    cacheBehaviorSettings: {
        allowedHttpMethods: "GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE",
        cachedHttpMethods: "GET,HEAD",
        defaultTtl: 86400,
        maximumTtl: 31536000,
        minimumTtl: 0,
        forwardedCookies: {
            option: "none",
        },
        forwardedHeaders: {
            option: "default",
        },
        forwardedQueryStrings: {
            option: false,
        },
    },
});
import pulumi
import pulumi_aws as aws

example = aws.lightsail.Bucket("example",
    name="example-bucket",
    bundle_id="small_1_0")
example_distribution = aws.lightsail.Distribution("example",
    name="example-distribution",
    bundle_id="small_1_0",
    origin={
        "name": example.name,
        "region_name": example.region,
    },
    default_cache_behavior={
        "behavior": "cache",
    },
    cache_behavior_settings={
        "allowed_http_methods": "GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE",
        "cached_http_methods": "GET,HEAD",
        "default_ttl": 86400,
        "maximum_ttl": 31536000,
        "minimum_ttl": 0,
        "forwarded_cookies": {
            "option": "none",
        },
        "forwarded_headers": {
            "option": "default",
        },
        "forwarded_query_strings": {
            "option": False,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := lightsail.NewBucket(ctx, "example", &lightsail.BucketArgs{
			Name:     pulumi.String("example-bucket"),
			BundleId: pulumi.String("small_1_0"),
		})
		if err != nil {
			return err
		}
		_, err = lightsail.NewDistribution(ctx, "example", &lightsail.DistributionArgs{
			Name:     pulumi.String("example-distribution"),
			BundleId: pulumi.String("small_1_0"),
			Origin: &lightsail.DistributionOriginArgs{
				Name:       example.Name,
				RegionName: example.Region,
			},
			DefaultCacheBehavior: &lightsail.DistributionDefaultCacheBehaviorArgs{
				Behavior: pulumi.String("cache"),
			},
			CacheBehaviorSettings: &lightsail.DistributionCacheBehaviorSettingsArgs{
				AllowedHttpMethods: pulumi.String("GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE"),
				CachedHttpMethods:  pulumi.String("GET,HEAD"),
				DefaultTtl:         pulumi.Int(86400),
				MaximumTtl:         pulumi.Int(31536000),
				MinimumTtl:         pulumi.Int(0),
				ForwardedCookies: &lightsail.DistributionCacheBehaviorSettingsForwardedCookiesArgs{
					Option: pulumi.String("none"),
				},
				ForwardedHeaders: &lightsail.DistributionCacheBehaviorSettingsForwardedHeadersArgs{
					Option: pulumi.String("default"),
				},
				ForwardedQueryStrings: &lightsail.DistributionCacheBehaviorSettingsForwardedQueryStringsArgs{
					Option: pulumi.Bool(false),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.LightSail.Bucket("example", new()
    {
        Name = "example-bucket",
        BundleId = "small_1_0",
    });

    var exampleDistribution = new Aws.LightSail.Distribution("example", new()
    {
        Name = "example-distribution",
        BundleId = "small_1_0",
        Origin = new Aws.LightSail.Inputs.DistributionOriginArgs
        {
            Name = example.Name,
            RegionName = example.Region,
        },
        DefaultCacheBehavior = new Aws.LightSail.Inputs.DistributionDefaultCacheBehaviorArgs
        {
            Behavior = "cache",
        },
        CacheBehaviorSettings = new Aws.LightSail.Inputs.DistributionCacheBehaviorSettingsArgs
        {
            AllowedHttpMethods = "GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE",
            CachedHttpMethods = "GET,HEAD",
            DefaultTtl = 86400,
            MaximumTtl = 31536000,
            MinimumTtl = 0,
            ForwardedCookies = new Aws.LightSail.Inputs.DistributionCacheBehaviorSettingsForwardedCookiesArgs
            {
                Option = "none",
            },
            ForwardedHeaders = new Aws.LightSail.Inputs.DistributionCacheBehaviorSettingsForwardedHeadersArgs
            {
                Option = "default",
            },
            ForwardedQueryStrings = new Aws.LightSail.Inputs.DistributionCacheBehaviorSettingsForwardedQueryStringsArgs
            {
                Option = false,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lightsail.Bucket;
import com.pulumi.aws.lightsail.BucketArgs;
import com.pulumi.aws.lightsail.Distribution;
import com.pulumi.aws.lightsail.DistributionArgs;
import com.pulumi.aws.lightsail.inputs.DistributionOriginArgs;
import com.pulumi.aws.lightsail.inputs.DistributionDefaultCacheBehaviorArgs;
import com.pulumi.aws.lightsail.inputs.DistributionCacheBehaviorSettingsArgs;
import com.pulumi.aws.lightsail.inputs.DistributionCacheBehaviorSettingsForwardedCookiesArgs;
import com.pulumi.aws.lightsail.inputs.DistributionCacheBehaviorSettingsForwardedHeadersArgs;
import com.pulumi.aws.lightsail.inputs.DistributionCacheBehaviorSettingsForwardedQueryStringsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Bucket("example", BucketArgs.builder()
            .name("example-bucket")
            .bundleId("small_1_0")
            .build());

        var exampleDistribution = new Distribution("exampleDistribution", DistributionArgs.builder()
            .name("example-distribution")
            .bundleId("small_1_0")
            .origin(DistributionOriginArgs.builder()
                .name(example.name())
                .regionName(example.region())
                .build())
            .defaultCacheBehavior(DistributionDefaultCacheBehaviorArgs.builder()
                .behavior("cache")
                .build())
            .cacheBehaviorSettings(DistributionCacheBehaviorSettingsArgs.builder()
                .allowedHttpMethods("GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE")
                .cachedHttpMethods("GET,HEAD")
                .defaultTtl(86400)
                .maximumTtl(31536000)
                .minimumTtl(0)
                .forwardedCookies(DistributionCacheBehaviorSettingsForwardedCookiesArgs.builder()
                    .option("none")
                    .build())
                .forwardedHeaders(DistributionCacheBehaviorSettingsForwardedHeadersArgs.builder()
                    .option("default")
                    .build())
                .forwardedQueryStrings(DistributionCacheBehaviorSettingsForwardedQueryStringsArgs.builder()
                    .option(false)
                    .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:lightsail:Bucket
    properties:
      name: example-bucket
      bundleId: small_1_0
  exampleDistribution:
    type: aws:lightsail:Distribution
    name: example
    properties:
      name: example-distribution
      bundleId: small_1_0
      origin:
        name: ${example.name}
        regionName: ${example.region}
      defaultCacheBehavior:
        behavior: cache
      cacheBehaviorSettings:
        allowedHttpMethods: GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE
        cachedHttpMethods: GET,HEAD
        defaultTtl: 86400
        maximumTtl: 3.1536e+07
        minimumTtl: 0
        forwardedCookies:
          option: none
        forwardedHeaders:
          option: default
        forwardedQueryStrings:
          option: false

The origin property points to your Lightsail bucket by name and region. The defaultCacheBehavior sets whether content is cached or passed through to the origin. The cacheBehaviorSettings block controls TTL values, HTTP methods, and what headers or cookies get forwarded to the origin. Here, GET and HEAD requests are cached for up to 24 hours (defaultTtl: 86400 seconds).

Distribute traffic from a Lightsail instance

Applications running on instances can serve dynamic content through a CDN to improve global performance.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const available = aws.getAvailabilityZones({
    state: "available",
    filters: [{
        name: "opt-in-status",
        values: ["opt-in-not-required"],
    }],
});
const exampleStaticIp = new aws.lightsail.StaticIp("example", {name: "example-static-ip"});
const exampleInstance = new aws.lightsail.Instance("example", {
    name: "example-instance",
    availabilityZone: available.then(available => available.names?.[0]),
    blueprintId: "amazon_linux_2",
    bundleId: "micro_1_0",
});
const example = new aws.lightsail.StaticIpAttachment("example", {
    staticIpName: exampleStaticIp.name,
    instanceName: exampleInstance.name,
});
const exampleDistribution = new aws.lightsail.Distribution("example", {
    name: "example-distribution",
    bundleId: "small_1_0",
    origin: {
        name: exampleInstance.name,
        regionName: available.then(available => available.id),
    },
    defaultCacheBehavior: {
        behavior: "cache",
    },
}, {
    dependsOn: [example],
});
import pulumi
import pulumi_aws as aws

available = aws.get_availability_zones(state="available",
    filters=[{
        "name": "opt-in-status",
        "values": ["opt-in-not-required"],
    }])
example_static_ip = aws.lightsail.StaticIp("example", name="example-static-ip")
example_instance = aws.lightsail.Instance("example",
    name="example-instance",
    availability_zone=available.names[0],
    blueprint_id="amazon_linux_2",
    bundle_id="micro_1_0")
example = aws.lightsail.StaticIpAttachment("example",
    static_ip_name=example_static_ip.name,
    instance_name=example_instance.name)
example_distribution = aws.lightsail.Distribution("example",
    name="example-distribution",
    bundle_id="small_1_0",
    origin={
        "name": example_instance.name,
        "region_name": available.id,
    },
    default_cache_behavior={
        "behavior": "cache",
    },
    opts = pulumi.ResourceOptions(depends_on=[example]))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		available, err := aws.GetAvailabilityZones(ctx, &aws.GetAvailabilityZonesArgs{
			State: pulumi.StringRef("available"),
			Filters: []aws.GetAvailabilityZonesFilter{
				{
					Name: "opt-in-status",
					Values: []string{
						"opt-in-not-required",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		exampleStaticIp, err := lightsail.NewStaticIp(ctx, "example", &lightsail.StaticIpArgs{
			Name: pulumi.String("example-static-ip"),
		})
		if err != nil {
			return err
		}
		exampleInstance, err := lightsail.NewInstance(ctx, "example", &lightsail.InstanceArgs{
			Name:             pulumi.String("example-instance"),
			AvailabilityZone: pulumi.String(available.Names[0]),
			BlueprintId:      pulumi.String("amazon_linux_2"),
			BundleId:         pulumi.String("micro_1_0"),
		})
		if err != nil {
			return err
		}
		example, err := lightsail.NewStaticIpAttachment(ctx, "example", &lightsail.StaticIpAttachmentArgs{
			StaticIpName: exampleStaticIp.Name,
			InstanceName: exampleInstance.Name,
		})
		if err != nil {
			return err
		}
		_, err = lightsail.NewDistribution(ctx, "example", &lightsail.DistributionArgs{
			Name:     pulumi.String("example-distribution"),
			BundleId: pulumi.String("small_1_0"),
			Origin: &lightsail.DistributionOriginArgs{
				Name:       exampleInstance.Name,
				RegionName: pulumi.String(available.Id),
			},
			DefaultCacheBehavior: &lightsail.DistributionDefaultCacheBehaviorArgs{
				Behavior: pulumi.String("cache"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			example,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var available = Aws.GetAvailabilityZones.Invoke(new()
    {
        State = "available",
        Filters = new[]
        {
            new Aws.Inputs.GetAvailabilityZonesFilterInputArgs
            {
                Name = "opt-in-status",
                Values = new[]
                {
                    "opt-in-not-required",
                },
            },
        },
    });

    var exampleStaticIp = new Aws.LightSail.StaticIp("example", new()
    {
        Name = "example-static-ip",
    });

    var exampleInstance = new Aws.LightSail.Instance("example", new()
    {
        Name = "example-instance",
        AvailabilityZone = available.Apply(getAvailabilityZonesResult => getAvailabilityZonesResult.Names[0]),
        BlueprintId = "amazon_linux_2",
        BundleId = "micro_1_0",
    });

    var example = new Aws.LightSail.StaticIpAttachment("example", new()
    {
        StaticIpName = exampleStaticIp.Name,
        InstanceName = exampleInstance.Name,
    });

    var exampleDistribution = new Aws.LightSail.Distribution("example", new()
    {
        Name = "example-distribution",
        BundleId = "small_1_0",
        Origin = new Aws.LightSail.Inputs.DistributionOriginArgs
        {
            Name = exampleInstance.Name,
            RegionName = available.Apply(getAvailabilityZonesResult => getAvailabilityZonesResult.Id),
        },
        DefaultCacheBehavior = new Aws.LightSail.Inputs.DistributionDefaultCacheBehaviorArgs
        {
            Behavior = "cache",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            example,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetAvailabilityZonesArgs;
import com.pulumi.aws.lightsail.StaticIp;
import com.pulumi.aws.lightsail.StaticIpArgs;
import com.pulumi.aws.lightsail.Instance;
import com.pulumi.aws.lightsail.InstanceArgs;
import com.pulumi.aws.lightsail.StaticIpAttachment;
import com.pulumi.aws.lightsail.StaticIpAttachmentArgs;
import com.pulumi.aws.lightsail.Distribution;
import com.pulumi.aws.lightsail.DistributionArgs;
import com.pulumi.aws.lightsail.inputs.DistributionOriginArgs;
import com.pulumi.aws.lightsail.inputs.DistributionDefaultCacheBehaviorArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var available = AwsFunctions.getAvailabilityZones(GetAvailabilityZonesArgs.builder()
            .state("available")
            .filters(GetAvailabilityZonesFilterArgs.builder()
                .name("opt-in-status")
                .values("opt-in-not-required")
                .build())
            .build());

        var exampleStaticIp = new StaticIp("exampleStaticIp", StaticIpArgs.builder()
            .name("example-static-ip")
            .build());

        var exampleInstance = new Instance("exampleInstance", InstanceArgs.builder()
            .name("example-instance")
            .availabilityZone(available.names()[0])
            .blueprintId("amazon_linux_2")
            .bundleId("micro_1_0")
            .build());

        var example = new StaticIpAttachment("example", StaticIpAttachmentArgs.builder()
            .staticIpName(exampleStaticIp.name())
            .instanceName(exampleInstance.name())
            .build());

        var exampleDistribution = new Distribution("exampleDistribution", DistributionArgs.builder()
            .name("example-distribution")
            .bundleId("small_1_0")
            .origin(DistributionOriginArgs.builder()
                .name(exampleInstance.name())
                .regionName(available.id())
                .build())
            .defaultCacheBehavior(DistributionDefaultCacheBehaviorArgs.builder()
                .behavior("cache")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(example)
                .build());

    }
}
resources:
  example:
    type: aws:lightsail:StaticIpAttachment
    properties:
      staticIpName: ${exampleStaticIp.name}
      instanceName: ${exampleInstance.name}
  exampleStaticIp:
    type: aws:lightsail:StaticIp
    name: example
    properties:
      name: example-static-ip
  exampleInstance:
    type: aws:lightsail:Instance
    name: example
    properties:
      name: example-instance
      availabilityZone: ${available.names[0]}
      blueprintId: amazon_linux_2
      bundleId: micro_1_0
  exampleDistribution:
    type: aws:lightsail:Distribution
    name: example
    properties:
      name: example-distribution
      bundleId: small_1_0
      origin:
        name: ${exampleInstance.name}
        regionName: ${available.id}
      defaultCacheBehavior:
        behavior: cache
    options:
      dependsOn:
        - ${example}
variables:
  available:
    fn::invoke:
      function: aws:getAvailabilityZones
      arguments:
        state: available
        filters:
          - name: opt-in-status
            values:
              - opt-in-not-required

The origin property references the instance by name and region. The dependsOn ensures the static IP attachment completes before creating the distribution, since distributions require instances to have stable IP addresses. Without the static IP, the distribution cannot route traffic reliably.

Front a load balancer with edge caching

Load-balanced applications benefit from CDN caching to reduce backend load and improve response times.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const available = aws.getAvailabilityZones({
    state: "available",
    filters: [{
        name: "opt-in-status",
        values: ["opt-in-not-required"],
    }],
});
const example = new aws.lightsail.Lb("example", {
    name: "example-load-balancer",
    healthCheckPath: "/",
    instancePort: 80,
    tags: {
        foo: "bar",
    },
});
const exampleInstance = new aws.lightsail.Instance("example", {
    name: "example-instance",
    availabilityZone: available.then(available => available.names?.[0]),
    blueprintId: "amazon_linux_2",
    bundleId: "nano_3_0",
});
const exampleLbAttachment = new aws.lightsail.LbAttachment("example", {
    lbName: example.name,
    instanceName: exampleInstance.name,
});
const exampleDistribution = new aws.lightsail.Distribution("example", {
    name: "example-distribution",
    bundleId: "small_1_0",
    origin: {
        name: example.name,
        regionName: available.then(available => available.id),
    },
    defaultCacheBehavior: {
        behavior: "cache",
    },
}, {
    dependsOn: [exampleLbAttachment],
});
import pulumi
import pulumi_aws as aws

available = aws.get_availability_zones(state="available",
    filters=[{
        "name": "opt-in-status",
        "values": ["opt-in-not-required"],
    }])
example = aws.lightsail.Lb("example",
    name="example-load-balancer",
    health_check_path="/",
    instance_port=80,
    tags={
        "foo": "bar",
    })
example_instance = aws.lightsail.Instance("example",
    name="example-instance",
    availability_zone=available.names[0],
    blueprint_id="amazon_linux_2",
    bundle_id="nano_3_0")
example_lb_attachment = aws.lightsail.LbAttachment("example",
    lb_name=example.name,
    instance_name=example_instance.name)
example_distribution = aws.lightsail.Distribution("example",
    name="example-distribution",
    bundle_id="small_1_0",
    origin={
        "name": example.name,
        "region_name": available.id,
    },
    default_cache_behavior={
        "behavior": "cache",
    },
    opts = pulumi.ResourceOptions(depends_on=[example_lb_attachment]))
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lightsail"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		available, err := aws.GetAvailabilityZones(ctx, &aws.GetAvailabilityZonesArgs{
			State: pulumi.StringRef("available"),
			Filters: []aws.GetAvailabilityZonesFilter{
				{
					Name: "opt-in-status",
					Values: []string{
						"opt-in-not-required",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		example, err := lightsail.NewLb(ctx, "example", &lightsail.LbArgs{
			Name:            pulumi.String("example-load-balancer"),
			HealthCheckPath: pulumi.String("/"),
			InstancePort:    pulumi.Int(80),
			Tags: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		exampleInstance, err := lightsail.NewInstance(ctx, "example", &lightsail.InstanceArgs{
			Name:             pulumi.String("example-instance"),
			AvailabilityZone: pulumi.String(available.Names[0]),
			BlueprintId:      pulumi.String("amazon_linux_2"),
			BundleId:         pulumi.String("nano_3_0"),
		})
		if err != nil {
			return err
		}
		exampleLbAttachment, err := lightsail.NewLbAttachment(ctx, "example", &lightsail.LbAttachmentArgs{
			LbName:       example.Name,
			InstanceName: exampleInstance.Name,
		})
		if err != nil {
			return err
		}
		_, err = lightsail.NewDistribution(ctx, "example", &lightsail.DistributionArgs{
			Name:     pulumi.String("example-distribution"),
			BundleId: pulumi.String("small_1_0"),
			Origin: &lightsail.DistributionOriginArgs{
				Name:       example.Name,
				RegionName: pulumi.String(available.Id),
			},
			DefaultCacheBehavior: &lightsail.DistributionDefaultCacheBehaviorArgs{
				Behavior: pulumi.String("cache"),
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			exampleLbAttachment,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var available = Aws.GetAvailabilityZones.Invoke(new()
    {
        State = "available",
        Filters = new[]
        {
            new Aws.Inputs.GetAvailabilityZonesFilterInputArgs
            {
                Name = "opt-in-status",
                Values = new[]
                {
                    "opt-in-not-required",
                },
            },
        },
    });

    var example = new Aws.LightSail.Lb("example", new()
    {
        Name = "example-load-balancer",
        HealthCheckPath = "/",
        InstancePort = 80,
        Tags = 
        {
            { "foo", "bar" },
        },
    });

    var exampleInstance = new Aws.LightSail.Instance("example", new()
    {
        Name = "example-instance",
        AvailabilityZone = available.Apply(getAvailabilityZonesResult => getAvailabilityZonesResult.Names[0]),
        BlueprintId = "amazon_linux_2",
        BundleId = "nano_3_0",
    });

    var exampleLbAttachment = new Aws.LightSail.LbAttachment("example", new()
    {
        LbName = example.Name,
        InstanceName = exampleInstance.Name,
    });

    var exampleDistribution = new Aws.LightSail.Distribution("example", new()
    {
        Name = "example-distribution",
        BundleId = "small_1_0",
        Origin = new Aws.LightSail.Inputs.DistributionOriginArgs
        {
            Name = example.Name,
            RegionName = available.Apply(getAvailabilityZonesResult => getAvailabilityZonesResult.Id),
        },
        DefaultCacheBehavior = new Aws.LightSail.Inputs.DistributionDefaultCacheBehaviorArgs
        {
            Behavior = "cache",
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            exampleLbAttachment,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetAvailabilityZonesArgs;
import com.pulumi.aws.lightsail.Lb;
import com.pulumi.aws.lightsail.LbArgs;
import com.pulumi.aws.lightsail.Instance;
import com.pulumi.aws.lightsail.InstanceArgs;
import com.pulumi.aws.lightsail.LbAttachment;
import com.pulumi.aws.lightsail.LbAttachmentArgs;
import com.pulumi.aws.lightsail.Distribution;
import com.pulumi.aws.lightsail.DistributionArgs;
import com.pulumi.aws.lightsail.inputs.DistributionOriginArgs;
import com.pulumi.aws.lightsail.inputs.DistributionDefaultCacheBehaviorArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var available = AwsFunctions.getAvailabilityZones(GetAvailabilityZonesArgs.builder()
            .state("available")
            .filters(GetAvailabilityZonesFilterArgs.builder()
                .name("opt-in-status")
                .values("opt-in-not-required")
                .build())
            .build());

        var example = new Lb("example", LbArgs.builder()
            .name("example-load-balancer")
            .healthCheckPath("/")
            .instancePort(80)
            .tags(Map.of("foo", "bar"))
            .build());

        var exampleInstance = new Instance("exampleInstance", InstanceArgs.builder()
            .name("example-instance")
            .availabilityZone(available.names()[0])
            .blueprintId("amazon_linux_2")
            .bundleId("nano_3_0")
            .build());

        var exampleLbAttachment = new LbAttachment("exampleLbAttachment", LbAttachmentArgs.builder()
            .lbName(example.name())
            .instanceName(exampleInstance.name())
            .build());

        var exampleDistribution = new Distribution("exampleDistribution", DistributionArgs.builder()
            .name("example-distribution")
            .bundleId("small_1_0")
            .origin(DistributionOriginArgs.builder()
                .name(example.name())
                .regionName(available.id())
                .build())
            .defaultCacheBehavior(DistributionDefaultCacheBehaviorArgs.builder()
                .behavior("cache")
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(exampleLbAttachment)
                .build());

    }
}
resources:
  example:
    type: aws:lightsail:Lb
    properties:
      name: example-load-balancer
      healthCheckPath: /
      instancePort: '80'
      tags:
        foo: bar
  exampleInstance:
    type: aws:lightsail:Instance
    name: example
    properties:
      name: example-instance
      availabilityZone: ${available.names[0]}
      blueprintId: amazon_linux_2
      bundleId: nano_3_0
  exampleLbAttachment:
    type: aws:lightsail:LbAttachment
    name: example
    properties:
      lbName: ${example.name}
      instanceName: ${exampleInstance.name}
  exampleDistribution:
    type: aws:lightsail:Distribution
    name: example
    properties:
      name: example-distribution
      bundleId: small_1_0
      origin:
        name: ${example.name}
        regionName: ${available.id}
      defaultCacheBehavior:
        behavior: cache
    options:
      dependsOn:
        - ${exampleLbAttachment}
variables:
  available:
    fn::invoke:
      function: aws:getAvailabilityZones
      arguments:
        state: available
        filters:
          - name: opt-in-status
            values:
              - opt-in-not-required

The origin property references the load balancer by name and region. The dependsOn ensures instances are attached to the load balancer before creating the distribution. This ordering prevents the distribution from routing to an empty load balancer.

Beyond these examples

These snippets focus on specific distribution-level features: origin configuration (buckets, instances, load balancers) and cache behavior and TTL settings. They’re intentionally minimal rather than full CDN deployments.

The examples reference pre-existing infrastructure such as Lightsail buckets, instances, or load balancers, and static IP attachments or load balancer attachments. They focus on configuring the distribution rather than provisioning the origin resources.

To keep things focused, common distribution patterns are omitted, including:

  • Custom SSL/TLS certificates (certificateName)
  • Per-path cache behaviors (cacheBehaviors)
  • IP address type selection (ipAddressType)
  • Distribution enable/disable controls (isEnabled)

These omissions are intentional: the goal is to illustrate how each distribution feature is wired, not provide drop-in CDN modules. See the Lightsail Distribution resource reference for all available configuration options.

Let's create AWS Lightsail CDN Distributions

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Origins & Dependencies
What origin types can I use with a Lightsail distribution?
You can use three origin types: Lightsail buckets, instances (with static IP attachment), or load balancers. Configure the origin property with the resource’s name and regionName.
Why do I need dependsOn when using an instance or load balancer as the origin?
The distribution requires the origin attachment to be complete before creation. Use dependsOn to ensure StaticIpAttachment (for instances) or LbAttachment (for load balancers) finishes first.
What's required to create a distribution?
You must specify bundleId, name, origin (with name and regionName), and defaultCacheBehavior. The region property is also required but defaults to the provider’s region.
Caching Behavior
What's the difference between allowedHttpMethods and cachedHttpMethods?
allowedHttpMethods defines which HTTP methods the distribution accepts (e.g., GET, POST, DELETE), while cachedHttpMethods specifies which methods have their responses cached (typically just GET and HEAD).
How do I configure cache TTL settings?
Use cacheBehaviorSettings with defaultTtl, maximumTtl, and minimumTtl (all in seconds). For example, the schema shows defaultTtl: 86400 (1 day), maximumTtl: 31536000 (1 year), and minimumTtl: 0.
What forwarding options can I configure?
You can control forwarding of cookies (forwardedCookies), headers (forwardedHeaders), and query strings (forwardedQueryStrings). Each has an option field to specify behavior (e.g., “none”, “default”, true/false).
Network & Access
What are the default settings for ipAddressType and isEnabled?
Distributions default to ipAddressType: "dualstack" (supporting both IPv4 and IPv6) and isEnabled: true (distribution is active). You can override these by setting ipAddressType: "ipv4" or isEnabled: false.
How do I attach an SSL/TLS certificate to my distribution?
Set the certificateName property to the name of your Lightsail certificate. This is optional; distributions work without custom certificates.

Using a different cloud?

Explore networking guides for other cloud providers: