The web-server module supplies components to expose ECS services via an internet-facing ALB, using a fluent builder interface for easy assembly.
Use it when a workload needs package-standard public HTTP/HTTPS ingress, load-balancer security groups, target-group wiring, configurable health checks, and optional TLS/Route53 custom-domain support on top of EcsService.
import * as aws from '@pulumi/aws';
import * as studion from '@studion/infra-code-blocks';
const vpc = new studion.Vpc('app');
const cluster = new aws.ecs.Cluster('app-cluster', {});
const webServer = new studion.WebServerBuilder('app')
.withContainer('nginx:stable', 80)
.withEcsConfig({
cluster,
desiredCount: 1,
size: 'small',
autoscaling: { enabled: false },
})
.withVpc(vpc.vpc)
.build();
export const loadBalancerDns = webServer.lb.lb.dnsName;
export const serviceName = webServer.service.apply(
service => service.service.name,
);import * as aws from '@pulumi/aws';
import * as studion from '@studion/infra-code-blocks';
const hostedZone = aws.route53.getZoneOutput({
name: 'example.com',
privateZone: false,
});
const vpc = new studion.Vpc('platform');
const cluster = new aws.ecs.Cluster('platform-cluster', {});
const taskExecutionPolicy: aws.types.input.iam.RoleInlinePolicy = {
name: 'allow-parameter-read',
policy: JSON.stringify({
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['ssm:GetParameter'],
Resource: '*',
},
],
}),
};
const webServer = new studion.WebServer('platform-api', {
vpc: vpc.vpc,
cluster,
image: 'ghcr.io/example/platform-api:1.0.0',
port: 8080,
desiredCount: 2,
size: 'medium',
autoscaling: {
enabled: true,
minCount: 2,
maxCount: 4,
},
domain: 'api.example.com',
hostedZoneId: hostedZone.zoneId,
healthCheckPath: '/readyz',
healthCheckConfig: {
healthyThreshold: 5,
unhealthyThreshold: 3,
interval: 15,
timeout: 3,
},
loadBalancingAlgorithmType: 'round_robin',
taskExecutionRoleInlinePolicies: [taskExecutionPolicy],
volumes: [{ name: 'shared-data' }],
environment: [{ name: 'APP_ENV', value: 'prod' }],
mountPoints: [
{
sourceVolume: 'shared-data',
containerPath: '/var/lib/app',
},
],
initContainers: [
{
name: 'migrate',
image: 'ghcr.io/example/platform-api:1.0.0',
command: ['node', 'dist/migrate.js'],
mountPoints: [
{
sourceVolume: 'shared-data',
containerPath: '/var/lib/app',
},
],
},
],
sidecarContainers: [
{
name: 'config-reloader',
image: 'ghcr.io/example/config-reloader:1.0.0',
environment: [{ name: 'CONFIG_PATH', value: '/var/lib/app/config.json' }],
healthCheck: {
command: ['CMD-SHELL', 'test -f /tmp/healthy || exit 1'],
interval: 30,
timeout: 5,
retries: 3,
startPeriod: 10,
},
},
],
});
export const httpsListenerArn = webServer.lb.tlsListener?.arn;
export const ecsServiceArn = webServer.service.apply(
service => service.service.id,
);WebServerrequireshostedZoneIdwheneverdomainorcertificateis provided.- If
domainandhostedZoneIdare provided withoutcertificate,WebServercreates anAcmCertificatechild in the active AWS provider region and waits for validation before creating the HTTPS listener. - The main application container is always named after the component name, always gets exactly one TCP port mapping created from
EcsService.createTcpPortMapping(port), and is always markedessential: true. initContainersare always rewritten toessential: falsebefore the nested ECS service is created.sidecarContainersare always rewritten toessential: truebefore the nested ECS service is created.- If an
otelCollectoris provided,WebServerappends its config volume, config-writer init container, collector sidecar container, and task-role policy fragments into the final ECS service inputs. - When
otelCollectoris provided, collector task-role policy fragments are combined withtaskRoleInlinePoliciesand passed to the nestedEcsServiceas task-role inline policies.taskExecutionRoleInlinePoliciesare forwarded separately as execution-role inline policies. - The nested ECS service disables service discovery, sets
assignPublicIp: true, and registers the main container with the load balancer target group. WebServerLoadBalancercreates an internet-facing application load balancer in public subnets and defaultshealthCheckPathto'/healthcheck'.- Target-group health checks use
healthCheckPathforhealthCheck.pathand mergehealthCheckConfiginto the remaining target-group health-check settings. The component default config is{ healthyThreshold: 3, unhealthyThreshold: 2, interval: 60, timeout: 5 }. healthCheckConfigis shallow-merged through the component defaults; supplying it replaces the default health-check config object, so include every non-path health-check value you want to control explicitly.- If a certificate is provided to
WebServerLoadBalancer, port80redirects to HTTPS and a TLS listener on port443is created withELBSecurityPolicy-TLS13-1-2-2021-06. Without a certificate, port80forwards directly to the target group. - The load balancer security group always allows inbound TCP on ports
80and443from0.0.0.0/0and allows all outbound traffic. - The web-server service security group allows all protocols and ports from the load balancer security group and allows all outbound traffic.
- When custom-domain mode is enabled, Route53 alias records point at the ALB. If
domainis provided, only that alias is created; otherwise aliases are derived from the certificate domain name and subject alternative names. WebServerBuilder.build()throws unlesswithContainer(),withEcsConfig(), andwithVpc()have all been called first.
Signature
class WebServer extends pulumi.ComponentResource {
constructor(
name: string,
args: WebServer.Args,
opts?: pulumi.ComponentResourceOptions,
);
}Constructor Parameters
| Parameter | Description |
|---|---|
name*string |
Logical Pulumi component name. |
args*WebServer.Args |
Web-server and ECS service configuration object. |
optspulumi.ComponentResourceOptions |
Optional Pulumi component resource options. |
Configuration Options
Direct constructor input: args: WebServer.Args
| Property | Description |
|---|---|
image*pulumi.Input<string> |
Main application container image. |
port*pulumi.Input<number> |
Main application container port. |
environmentpulumi.Input<aws.ecs.KeyValuePair[]> |
Static environment variables for the main container. |
secretspulumi.Input<aws.ecs.Secret[]> |
ECS secret references for the main container. |
mountPointsEcsService.PersistentStorageMountPoint[] |
Persistent storage mounts for the main container. |
cluster*pulumi.Input<aws.ecs.Cluster> |
ECS cluster used by the nested EcsService. |
vpc*pulumi.Input<awsx.ec2.Vpc> |
Source of public subnets for the ALB and network data for ECS. |
volumespulumi.Input<pulumi.Input<EcsService.PersistentStorageVolume>[]> |
Logical ECS volumes passed into the nested EcsService. Default: []. |
namepulumi.Input<string> |
Optional ECS service name override forwarded to EcsService. Default: EcsService default. |
deploymentController'ECS' | 'CODE_DEPLOY' | 'EXTERNAL' |
Optional ECS deployment controller. Default: EcsService default. |
desiredCountpulumi.Input<number> |
Desired task count for the nested ECS service. Default: EcsService default. |
autoscalingpulumi.Input<{ enabled: pulumi.Input<boolean>; minCount?: pulumi.Input<number>; maxCount?: pulumi.Input<number> }> |
ECS target-tracking autoscaling configuration. Default: EcsService default. |
familypulumi.Input<string> |
Optional task definition family override. Default: EcsService default. |
sizepulumi.Input<TaskSize> |
ECS CPU/memory preset or explicit size object. Default: EcsService default. |
logGroupNamePrefixpulumi.Input<string> |
CloudWatch log group name prefix forwarded to EcsService. Default: EcsService default. |
taskExecutionRoleInlinePoliciespulumi.Input<pulumi.Input<EcsService.RoleInlinePolicy>[]> |
Extra execution-role inline policies forwarded to the nested EcsService. |
taskRoleInlinePoliciespulumi.Input<pulumi.Input<EcsService.RoleInlinePolicy>[]> |
Extra task-role inline policies combined with OTEL collector policy fragments, when configured, and forwarded to the nested EcsService. |
tagspulumi.Input<{ [key: string]: pulumi.Input<string> }> |
Extra tags forwarded to nested ECS resources. |
domainpulumi.Input<string> |
Custom DNS name for the ALB endpoint. |
certificatepulumi.Input<aws.acm.Certificate> |
Existing ACM certificate for TLS termination. |
hostedZoneIdpulumi.Input<string> |
Required: whenever domain or certificate is provided. |
healthCheckPathpulumi.Input<string> |
ALB target-group health-check path. Default: '/healthcheck'. |
healthCheckConfigOmit<aws.types.input.lb.TargetGroupHealthCheck, 'path'> |
Target-group health-check settings other than path; path is controlled by healthCheckPath. Default: { healthyThreshold: 3, unhealthyThreshold: 2, interval: 60, timeout: 5 }. |
loadBalancingAlgorithmTypepulumi.Input<string> |
Forwarded directly to the ALB target group. Default: AWS default. |
initContainerspulumi.Input<pulumi.Input<WebServer.InitContainer>[]> |
Additional init containers. Default: []. |
sidecarContainerspulumi.Input<pulumi.Input<WebServer.SidecarContainer>[]> |
Additional sidecars. Default: []. |
otelCollectorpulumi.Input<OtelCollector> |
Collector integration that contributes containers, volumes, and IAM policy fragments. |
Outputs
| Property | Description |
|---|---|
namestring |
Component name. |
containerWebServer.Container |
Main container definition before ECS-specific transformation. |
ecsConfigWebServer.EcsConfig |
ECS configuration object used to create the nested service. |
servicepulumi.Output<EcsService> |
Nested ECS service component. |
serviceSecurityGroupaws.ec2.SecurityGroup |
Security group attached to ECS tasks. |
lbWebServerLoadBalancer |
Nested load-balancer component. |
initContainerspulumi.Output<EcsService.Container[]> | undefined |
Final init containers after OTEL augmentation and essential: false rewriting. |
sidecarContainerspulumi.Output<EcsService.Container[]> | undefined |
Final sidecar containers after OTEL augmentation and essential: true rewriting. |
volumespulumi.Output<EcsService.PersistentStorageVolume[]> | undefined |
Final logical volumes after OTEL augmentation. |
acmCertificateAcmCertificate | undefined |
Automatically created certificate when domain is supplied without certificate. |
dnsRecordspulumi.Output<aws.route53.Record[]> | undefined |
Route53 alias records that point at the ALB in custom-domain mode. |
Supporting Types
WebServer.Container
type Container = Pick<
EcsService.Container,
'image' | 'environment' | 'secrets' | 'mountPoints'
> & {
port: pulumi.Input<number>;
};Used to define the main application container before ECS-specific transformation. Combined with WebServer.EcsConfig, WebServer.LoadBalancerConfig, and WebServer-specific fields to create the WebServer.Args intersection type.
WebServer.EcsConfig
type EcsConfig = Pick<
EcsService.Args,
| 'cluster'
| 'vpc'
| 'volumes'
| 'name'
| 'deploymentController'
| 'desiredCount'
| 'autoscaling'
| 'family'
| 'size'
| 'logGroupNamePrefix'
| 'taskExecutionRoleInlinePolicies'
| 'taskRoleInlinePolicies'
| 'tags'
>;Forwarded into the nested EcsService after the web-server-specific ALB wiring is added. Combined with WebServer.Container, WebServer.LoadBalancerConfig, and WebServer-specific fields to create the WebServer.Args intersection type.
WebServer.LoadBalancerConfig
type LoadBalancerConfig = Pick<
WebServerLoadBalancer.Args,
'healthCheckPath' | 'healthCheckConfig' | 'loadBalancingAlgorithmType'
>;Used to group the load-balancer-specific options that WebServer forwards into the nested WebServerLoadBalancer. Combined with WebServer.Container, WebServer.EcsConfig, and WebServer-specific fields to create the WebServer.Args intersection type.
WebServer.InitContainer
type InitContainer = Omit<EcsService.Container, 'essential'>;Init containers are always rewritten to essential: false before the nested ECS service is created.
WebServer.SidecarContainer
type SidecarContainer = Omit<
EcsService.Container,
'essential' | 'healthCheck'
> &
Required<Pick<EcsService.Container, 'healthCheck'>>;Sidecar containers are always rewritten to essential: true, and healthCheck is required.
Signature
class WebServerBuilder {
constructor(name: string);
}Constructor Parameters
| Parameter | Description |
|---|---|
name*string |
Base name used when build() constructs the WebServer. |
Builder Methods
| Method | Parameters | Description |
|---|---|---|
withContainer |
image: WebServer.Container['image'], port: WebServer.Container['port'], config: Omit<WebServer.Container, 'image' | 'port'> = {} |
Stores the main application container. |
withEcsConfig |
config: WebServerBuilder.EcsConfig |
Stores ECS cluster and service configuration. |
withVpc |
vpc: pulumi.Input<awsx.ec2.Vpc> |
Stores the required VPC. |
withVolume |
volume: EcsService.PersistentStorageVolume |
Adds one logical ECS volume. |
withCustomDomain |
domain: pulumi.Input<string>, hostedZoneId: pulumi.Input<string> |
Stores custom-domain settings and enables managed ACM flow. |
withCertificate |
certificate: WebServer.Args['certificate'], hostedZoneId: pulumi.Input<string>, domain?: pulumi.Input<string> |
Stores an existing certificate and hosted zone configuration. |
addInitContainer |
container: WebServer.InitContainer |
Adds one init container. |
addSidecarContainer |
container: WebServer.SidecarContainer |
Adds one sidecar container. |
withOtelCollector |
collector: OtelCollector |
Attaches collector-provided containers, volume, and IAM policy fragments. |
withHealthCheck |
path: WebServer.LoadBalancerConfig['healthCheckPath'], config?: WebServer.LoadBalancerConfig['healthCheckConfig'] |
Stores the ALB health-check path and optional target-group health-check settings. |
withLoadBalancingAlgorithm |
algorithm: WebServer.LoadBalancerConfig['loadBalancingAlgorithmType'] |
Stores the target-group load-balancing algorithm. |
build |
opts?: pulumi.ComponentResourceOptions |
Validates collected state and returns a WebServer. |
Build Result
build(opts?: pulumi.ComponentResourceOptions): WebServer| Return Type | Description |
|---|---|
WebServer |
Returns a WebServer assembled from the collected builder state and throws if required builder state is missing. |
Supporting Types
WebServerBuilder.EcsConfig
type EcsConfig = Omit<WebServer.EcsConfig, 'vpc' | 'volumes'>;Difference from WebServer.EcsConfig |
Description |
|---|---|
Omits vpc |
WebServerBuilder collects the VPC separately via withVpc(). |
Omits volumes |
WebServerBuilder collects volumes separately via withVolume(). |
Signature
class WebServerLoadBalancer extends pulumi.ComponentResource {
constructor(
name: string,
args: WebServerLoadBalancer.Args,
opts?: pulumi.ComponentResourceOptions,
);
}Constructor Parameters
| Parameter | Description |
|---|---|
name*string |
Logical Pulumi component name. |
args*WebServerLoadBalancer.Args |
Load-balancer configuration object. |
optspulumi.ComponentResourceOptions |
Optional Pulumi component resource options. |
Configuration Options
Direct constructor input: args: WebServerLoadBalancer.Args
| Property | Description |
|---|---|
vpc*pulumi.Input<awsx.ec2.Vpc> |
VPC whose public subnets host the ALB. |
port*pulumi.Input<number> |
Target-group port. |
certificatepulumi.Input<aws.acm.Certificate> |
Enables a TLS listener and HTTP-to-HTTPS redirect. |
healthCheckPathpulumi.Input<string> |
Target-group health-check path. Default: '/healthcheck'. |
healthCheckConfigOmit<aws.types.input.lb.TargetGroupHealthCheck, 'path'> |
Target-group health-check settings other than path. Default: { healthyThreshold: 3, unhealthyThreshold: 2, interval: 60, timeout: 5 }. |
loadBalancingAlgorithmTypepulumi.Input<string> |
Forwarded directly to the target group. Default: AWS default. |
Outputs
| Property | Description |
|---|---|
namestring |
Component name. |
lbaws.lb.LoadBalancer |
Internet-facing application load balancer. |
targetGroupaws.lb.TargetGroup |
IP target group for the ECS service. |
httpListeneraws.lb.Listener |
Port 80 listener. |
tlsListeneraws.lb.Listener | undefined |
Port 443 listener when a certificate is provided. |
securityGroupaws.ec2.SecurityGroup |
Load-balancer security group. |