2025-04-22 11:46:24 +02:00
AWSTemplateFormatVersion : 2010-09-09
Description : OpenVidu Pro - High Availability
Parameters :
DomainName :
Type : String
Description : Domain name for the OpenVidu High Availability cluster
AllowedPattern : ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
ConstraintDescription : The domain name does not have a valid domain name format
OpenViduCertificateARN :
Description : 'Amazon certificate arn resource to load into the LoadBalancer'
Type : String
AllowedPattern : '.+'
ConstraintDescription : The Load Balancer domain name must be defined
OpenViduLicense :
Description : "Visit https://openvidu.io/account"
Type : String
AllowedPattern : ^(?!\s*$).+$
NoEcho : true
ConstraintDescription : OpenVidu Pro License is mandatory
RTCEngine :
Description : "RTCEngine media engine to use"
Type : String
AllowedValues :
- pion
- mediasoup
Default : pion
MasterNodeInstanceType :
Description : "Specifies the EC2 instance type for your OpenVidu Master Node"
Type : String
Default : c6a.xlarge
AllowedValues :
2025-12-01 20:36:57 +01:00
- t3.nano
- t3.micro
- t3.small
2025-04-22 11:46:24 +02:00
- t3.medium
- t3.large
- t3.xlarge
- t3.2xlarge
2025-12-01 20:36:57 +01:00
- t3a.nano
- t3a.micro
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- t3a.2xlarge
- t4g.nano
- t4g.micro
- t4g.small
- t4g.medium
- t4g.large
- t4g.xlarge
- t4g.2xlarge
2025-04-22 11:46:24 +02:00
- c5.large
- c5.xlarge
- c5.2xlarge
- c5.4xlarge
- c5.9xlarge
- c5.12xlarge
- c5.18xlarge
- c5.24xlarge
2025-12-01 20:36:57 +01:00
- c5.metal
- c5a.large
- c5a.xlarge
- c5a.2xlarge
- c5a.4xlarge
- c5a.8xlarge
- c5a.12xlarge
- c5a.16xlarge
- c5a.24xlarge
- c5ad.large
- c5ad.xlarge
- c5ad.2xlarge
- c5ad.4xlarge
- c5ad.8xlarge
- c5ad.12xlarge
- c5ad.16xlarge
- c5ad.24xlarge
- c5d.large
- c5d.xlarge
- c5d.2xlarge
- c5d.4xlarge
- c5d.9xlarge
- c5d.12xlarge
- c5d.18xlarge
- c5d.24xlarge
- c5d.metal
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.9xlarge
- c5n.18xlarge
- c5n.metal
2025-04-22 11:46:24 +02:00
- c6a.large
- c6a.xlarge
- c6a.2xlarge
- c6a.4xlarge
- c6a.8xlarge
- c6a.12xlarge
- c6a.16xlarge
- c6a.24xlarge
- c6a.32xlarge
- c6a.48xlarge
- c6a.metal
2025-12-01 20:36:57 +01:00
- c6g.medium
- c6g.large
- c6g.xlarge
- c6g.2xlarge
- c6g.4xlarge
- c6g.8xlarge
- c6g.12xlarge
- c6g.16xlarge
- c6g.metal
- c6gd.medium
- c6gd.large
- c6gd.xlarge
- c6gd.2xlarge
- c6gd.4xlarge
- c6gd.8xlarge
- c6gd.12xlarge
- c6gd.16xlarge
- c6gd.metal
- c6gn.medium
- c6gn.large
- c6gn.xlarge
- c6gn.2xlarge
- c6gn.4xlarge
- c6gn.8xlarge
- c6gn.12xlarge
- c6gn.16xlarge
2025-04-22 11:46:24 +02:00
- c6i.large
- c6i.xlarge
- c6i.2xlarge
- c6i.4xlarge
- c6i.8xlarge
- c6i.12xlarge
- c6i.16xlarge
- c6i.24xlarge
- c6i.32xlarge
- c6i.metal
2025-12-01 20:36:57 +01:00
- c6id.large
- c6id.xlarge
- c6id.2xlarge
- c6id.4xlarge
- c6id.8xlarge
- c6id.12xlarge
- c6id.16xlarge
- c6id.24xlarge
- c6id.32xlarge
- c6id.metal
- c6in.large
- c6in.xlarge
- c6in.2xlarge
- c6in.4xlarge
- c6in.8xlarge
- c6in.12xlarge
- c6in.16xlarge
- c6in.24xlarge
- c6in.32xlarge
- c6in.metal
2025-04-22 11:46:24 +02:00
- c7a.medium
- c7a.large
- c7a.xlarge
- c7a.2xlarge
- c7a.4xlarge
- c7a.8xlarge
- c7a.12xlarge
- c7a.16xlarge
- c7a.24xlarge
- c7a.32xlarge
- c7a.48xlarge
- c7a.metal-48xl
2025-12-01 20:36:57 +01:00
- c7g.medium
- c7g.large
- c7g.xlarge
- c7g.2xlarge
- c7g.4xlarge
- c7g.8xlarge
- c7g.12xlarge
- c7g.16xlarge
- c7g.metal
- c7gd.medium
- c7gd.large
- c7gd.xlarge
- c7gd.2xlarge
- c7gd.4xlarge
- c7gd.8xlarge
- c7gd.12xlarge
- c7gd.16xlarge
- c7gd.metal
- c7gn.medium
- c7gn.large
- c7gn.xlarge
- c7gn.2xlarge
- c7gn.4xlarge
- c7gn.8xlarge
- c7gn.12xlarge
- c7gn.16xlarge
- c7gn.metal
- c7i-flex.large
- c7i-flex.xlarge
- c7i-flex.2xlarge
- c7i-flex.4xlarge
- c7i-flex.8xlarge
- c7i-flex.12xlarge
- c7i-flex.16xlarge
2025-04-22 11:46:24 +02:00
- c7i.large
- c7i.xlarge
- c7i.2xlarge
- c7i.4xlarge
- c7i.8xlarge
- c7i.12xlarge
- c7i.16xlarge
- c7i.24xlarge
- c7i.48xlarge
- c7i.metal-24xl
- c7i.metal-48xl
2025-12-01 20:36:57 +01:00
- c8g.medium
- c8g.large
- c8g.xlarge
- c8g.2xlarge
- c8g.4xlarge
- c8g.8xlarge
- c8g.12xlarge
- c8g.16xlarge
- c8g.24xlarge
- c8g.48xlarge
- c8g.metal-24xl
- c8g.metal-48xl
openvidu-deployment: Add missing instance types to AllowedValues in CloudFormation templates
Add Graviton families (c8gd, m8gd, r6g, r6gd, r7g, r7gd, r8g) and
GPU/Nvidia families (g4dn, g5, g5g, g6, g6e, g6f, g7e, gr6, gr6f,
p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200) that were
referenced in Conditions (IsGraviton/IsNvidia) but missing from the
AllowedValues parameter selectors.
2026-02-27 18:49:34 +01:00
- c8gd.medium
- c8gd.large
- c8gd.xlarge
- c8gd.2xlarge
- c8gd.4xlarge
- c8gd.8xlarge
- c8gd.12xlarge
- c8gd.16xlarge
- c8gd.24xlarge
- c8gd.48xlarge
- c8gd.metal-24xl
- c8gd.metal-48xl
- g4dn.xlarge
- g4dn.2xlarge
- g4dn.4xlarge
- g4dn.8xlarge
- g4dn.12xlarge
- g4dn.16xlarge
- g4dn.metal
- g5.xlarge
- g5.2xlarge
- g5.4xlarge
- g5.8xlarge
- g5.12xlarge
- g5.16xlarge
- g5.24xlarge
- g5.48xlarge
- g5g.xlarge
- g5g.2xlarge
- g5g.4xlarge
- g5g.8xlarge
- g5g.16xlarge
- g5g.metal
- g6.xlarge
- g6.2xlarge
- g6.4xlarge
- g6.8xlarge
- g6.12xlarge
- g6.16xlarge
- g6.24xlarge
- g6.48xlarge
- g6e.xlarge
- g6e.2xlarge
- g6e.4xlarge
- g6e.8xlarge
- g6e.12xlarge
- g6e.16xlarge
- g6e.24xlarge
- g6e.48xlarge
- g6f.large
- g6f.xlarge
- g6f.2xlarge
- g6f.4xlarge
- g7e.2xlarge
- g7e.4xlarge
- g7e.8xlarge
- g7e.12xlarge
- g7e.24xlarge
- g7e.48xlarge
- gr6.4xlarge
- gr6.8xlarge
- gr6f.4xlarge
2025-12-01 20:36:57 +01:00
- m6a.large
- m6a.xlarge
- m6a.2xlarge
- m6a.4xlarge
- m6a.8xlarge
- m6a.12xlarge
- m6a.16xlarge
- m6a.24xlarge
- m6a.32xlarge
- m6a.48xlarge
- m6a.metal
- m6g.medium
- m6g.large
- m6g.xlarge
- m6g.2xlarge
- m6g.4xlarge
- m6g.8xlarge
- m6g.12xlarge
- m6g.16xlarge
- m6g.metal
- m6gd.medium
- m6gd.large
- m6gd.xlarge
- m6gd.2xlarge
- m6gd.4xlarge
- m6gd.8xlarge
- m6gd.12xlarge
- m6gd.16xlarge
- m6gd.metal
- m6i.large
- m6i.xlarge
- m6i.2xlarge
- m6i.4xlarge
- m6i.8xlarge
- m6i.12xlarge
- m6i.16xlarge
- m6i.24xlarge
- m6i.32xlarge
- m6i.metal
- m6id.large
- m6id.xlarge
- m6id.2xlarge
- m6id.4xlarge
- m6id.8xlarge
- m6id.12xlarge
- m6id.16xlarge
- m6id.24xlarge
- m6id.32xlarge
- m6id.metal
- m6idn.large
- m6idn.xlarge
- m6idn.2xlarge
- m6idn.4xlarge
- m6idn.8xlarge
- m6idn.12xlarge
- m6idn.16xlarge
- m6idn.24xlarge
- m6idn.32xlarge
- m6idn.metal
2025-04-22 11:46:24 +02:00
- m6in.large
- m6in.xlarge
- m6in.2xlarge
- m6in.4xlarge
- m6in.8xlarge
- m6in.12xlarge
- m6in.16xlarge
- m6in.24xlarge
- m6in.32xlarge
2025-12-01 20:36:57 +01:00
- m6in.metal
- m7a.medium
- m7a.large
- m7a.xlarge
- m7a.2xlarge
- m7a.4xlarge
- m7a.8xlarge
- m7a.12xlarge
- m7a.16xlarge
- m7a.24xlarge
- m7a.32xlarge
- m7a.48xlarge
- m7a.metal-48xl
- m7g.medium
- m7g.large
- m7g.xlarge
- m7g.2xlarge
- m7g.4xlarge
- m7g.8xlarge
- m7g.12xlarge
- m7g.16xlarge
- m7g.metal
- m7gd.medium
- m7gd.large
- m7gd.xlarge
- m7gd.2xlarge
- m7gd.4xlarge
- m7gd.8xlarge
- m7gd.12xlarge
- m7gd.16xlarge
- m7gd.metal
- m7i-flex.large
- m7i-flex.xlarge
- m7i-flex.2xlarge
- m7i-flex.4xlarge
- m7i-flex.8xlarge
- m7i-flex.12xlarge
- m7i-flex.16xlarge
- m7i.large
- m7i.xlarge
- m7i.2xlarge
- m7i.4xlarge
- m7i.8xlarge
- m7i.12xlarge
- m7i.16xlarge
- m7i.24xlarge
- m7i.48xlarge
- m7i.metal-24xl
- m7i.metal-48xl
- m8g.medium
- m8g.large
- m8g.xlarge
- m8g.2xlarge
- m8g.4xlarge
- m8g.8xlarge
- m8g.12xlarge
- m8g.16xlarge
- m8g.24xlarge
- m8g.48xlarge
- m8g.metal-24xl
- m8g.metal-48xl
openvidu-deployment: Add missing instance types to AllowedValues in CloudFormation templates
Add Graviton families (c8gd, m8gd, r6g, r6gd, r7g, r7gd, r8g) and
GPU/Nvidia families (g4dn, g5, g5g, g6, g6e, g6f, g7e, gr6, gr6f,
p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200) that were
referenced in Conditions (IsGraviton/IsNvidia) but missing from the
AllowedValues parameter selectors.
2026-02-27 18:49:34 +01:00
- m8gd.medium
- m8gd.large
- m8gd.xlarge
- m8gd.2xlarge
- m8gd.4xlarge
- m8gd.8xlarge
- m8gd.12xlarge
- m8gd.16xlarge
- m8gd.24xlarge
- m8gd.48xlarge
- m8gd.metal-24xl
- m8gd.metal-48xl
- p4d.24xlarge
- p4de.24xlarge
- p5.4xlarge
- p5.48xlarge
- p5e.48xlarge
- p5en.48xlarge
- p6-b200.48xlarge
- p6-b300.48xlarge
- p6e-gb200.36xlarge
- r6g.medium
- r6g.large
- r6g.xlarge
- r6g.2xlarge
- r6g.4xlarge
- r6g.8xlarge
- r6g.12xlarge
- r6g.16xlarge
- r6g.metal
- r6gd.medium
- r6gd.large
- r6gd.xlarge
- r6gd.2xlarge
- r6gd.4xlarge
- r6gd.8xlarge
- r6gd.12xlarge
- r6gd.16xlarge
- r6gd.metal
- r7g.medium
- r7g.large
- r7g.xlarge
- r7g.2xlarge
- r7g.4xlarge
- r7g.8xlarge
- r7g.12xlarge
- r7g.16xlarge
- r7g.metal
- r7gd.medium
- r7gd.large
- r7gd.xlarge
- r7gd.2xlarge
- r7gd.4xlarge
- r7gd.8xlarge
- r7gd.12xlarge
- r7gd.16xlarge
- r7gd.metal
- r8g.medium
- r8g.large
- r8g.xlarge
- r8g.2xlarge
- r8g.4xlarge
- r8g.8xlarge
- r8g.12xlarge
- r8g.16xlarge
- r8g.24xlarge
- r8g.48xlarge
- r8g.metal-24xl
- r8g.metal-48xl
2025-04-22 11:46:24 +02:00
ConstraintDescription : "Must be a valid EC2 instance type"
MediaNodeInstanceType :
Description : "Specifies the EC2 instance type for your OpenVidu Media Nodes"
Type : String
Default : c6a.xlarge
AllowedValues :
2025-12-01 20:36:57 +01:00
- t3.nano
- t3.micro
- t3.small
2025-04-22 11:46:24 +02:00
- t3.medium
- t3.large
- t3.xlarge
- t3.2xlarge
2025-12-01 20:36:57 +01:00
- t3a.nano
- t3a.micro
- t3a.small
- t3a.medium
- t3a.large
- t3a.xlarge
- t3a.2xlarge
- t4g.nano
- t4g.micro
- t4g.small
- t4g.medium
- t4g.large
- t4g.xlarge
- t4g.2xlarge
2025-04-22 11:46:24 +02:00
- c5.large
- c5.xlarge
- c5.2xlarge
- c5.4xlarge
- c5.9xlarge
- c5.12xlarge
- c5.18xlarge
- c5.24xlarge
2025-12-01 20:36:57 +01:00
- c5.metal
- c5a.large
- c5a.xlarge
- c5a.2xlarge
- c5a.4xlarge
- c5a.8xlarge
- c5a.12xlarge
- c5a.16xlarge
- c5a.24xlarge
- c5ad.large
- c5ad.xlarge
- c5ad.2xlarge
- c5ad.4xlarge
- c5ad.8xlarge
- c5ad.12xlarge
- c5ad.16xlarge
- c5ad.24xlarge
- c5d.large
- c5d.xlarge
- c5d.2xlarge
- c5d.4xlarge
- c5d.9xlarge
- c5d.12xlarge
- c5d.18xlarge
- c5d.24xlarge
- c5d.metal
- c5n.large
- c5n.xlarge
- c5n.2xlarge
- c5n.4xlarge
- c5n.9xlarge
- c5n.18xlarge
- c5n.metal
2025-04-22 11:46:24 +02:00
- c6a.large
- c6a.xlarge
- c6a.2xlarge
- c6a.4xlarge
- c6a.8xlarge
- c6a.12xlarge
- c6a.16xlarge
- c6a.24xlarge
- c6a.32xlarge
- c6a.48xlarge
- c6a.metal
2025-12-01 20:36:57 +01:00
- c6g.medium
- c6g.large
- c6g.xlarge
- c6g.2xlarge
- c6g.4xlarge
- c6g.8xlarge
- c6g.12xlarge
- c6g.16xlarge
- c6g.metal
- c6gd.medium
- c6gd.large
- c6gd.xlarge
- c6gd.2xlarge
- c6gd.4xlarge
- c6gd.8xlarge
- c6gd.12xlarge
- c6gd.16xlarge
- c6gd.metal
- c6gn.medium
- c6gn.large
- c6gn.xlarge
- c6gn.2xlarge
- c6gn.4xlarge
- c6gn.8xlarge
- c6gn.12xlarge
- c6gn.16xlarge
2025-04-22 11:46:24 +02:00
- c6i.large
- c6i.xlarge
- c6i.2xlarge
- c6i.4xlarge
- c6i.8xlarge
- c6i.12xlarge
- c6i.16xlarge
- c6i.24xlarge
- c6i.32xlarge
- c6i.metal
2025-12-01 20:36:57 +01:00
- c6id.large
- c6id.xlarge
- c6id.2xlarge
- c6id.4xlarge
- c6id.8xlarge
- c6id.12xlarge
- c6id.16xlarge
- c6id.24xlarge
- c6id.32xlarge
- c6id.metal
- c6in.large
- c6in.xlarge
- c6in.2xlarge
- c6in.4xlarge
- c6in.8xlarge
- c6in.12xlarge
- c6in.16xlarge
- c6in.24xlarge
- c6in.32xlarge
- c6in.metal
2025-04-22 11:46:24 +02:00
- c7a.medium
- c7a.large
- c7a.xlarge
- c7a.2xlarge
- c7a.4xlarge
- c7a.8xlarge
- c7a.12xlarge
- c7a.16xlarge
- c7a.24xlarge
- c7a.32xlarge
- c7a.48xlarge
- c7a.metal-48xl
2025-12-01 20:36:57 +01:00
- c7g.medium
- c7g.large
- c7g.xlarge
- c7g.2xlarge
- c7g.4xlarge
- c7g.8xlarge
- c7g.12xlarge
- c7g.16xlarge
- c7g.metal
- c7gd.medium
- c7gd.large
- c7gd.xlarge
- c7gd.2xlarge
- c7gd.4xlarge
- c7gd.8xlarge
- c7gd.12xlarge
- c7gd.16xlarge
- c7gd.metal
- c7gn.medium
- c7gn.large
- c7gn.xlarge
- c7gn.2xlarge
- c7gn.4xlarge
- c7gn.8xlarge
- c7gn.12xlarge
- c7gn.16xlarge
- c7gn.metal
- c7i-flex.large
- c7i-flex.xlarge
- c7i-flex.2xlarge
- c7i-flex.4xlarge
- c7i-flex.8xlarge
- c7i-flex.12xlarge
- c7i-flex.16xlarge
2025-04-22 11:46:24 +02:00
- c7i.large
- c7i.xlarge
- c7i.2xlarge
- c7i.4xlarge
- c7i.8xlarge
- c7i.12xlarge
- c7i.16xlarge
- c7i.24xlarge
- c7i.48xlarge
- c7i.metal-24xl
- c7i.metal-48xl
2025-12-01 20:36:57 +01:00
- c8g.medium
- c8g.large
- c8g.xlarge
- c8g.2xlarge
- c8g.4xlarge
- c8g.8xlarge
- c8g.12xlarge
- c8g.16xlarge
- c8g.24xlarge
- c8g.48xlarge
- c8g.metal-24xl
- c8g.metal-48xl
openvidu-deployment: Add missing instance types to AllowedValues in CloudFormation templates
Add Graviton families (c8gd, m8gd, r6g, r6gd, r7g, r7gd, r8g) and
GPU/Nvidia families (g4dn, g5, g5g, g6, g6e, g6f, g7e, gr6, gr6f,
p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200) that were
referenced in Conditions (IsGraviton/IsNvidia) but missing from the
AllowedValues parameter selectors.
2026-02-27 18:49:34 +01:00
- c8gd.medium
- c8gd.large
- c8gd.xlarge
- c8gd.2xlarge
- c8gd.4xlarge
- c8gd.8xlarge
- c8gd.12xlarge
- c8gd.16xlarge
- c8gd.24xlarge
- c8gd.48xlarge
- c8gd.metal-24xl
- c8gd.metal-48xl
- g4dn.xlarge
- g4dn.2xlarge
- g4dn.4xlarge
- g4dn.8xlarge
- g4dn.12xlarge
- g4dn.16xlarge
- g4dn.metal
- g5.xlarge
- g5.2xlarge
- g5.4xlarge
- g5.8xlarge
- g5.12xlarge
- g5.16xlarge
- g5.24xlarge
- g5.48xlarge
- g5g.xlarge
- g5g.2xlarge
- g5g.4xlarge
- g5g.8xlarge
- g5g.16xlarge
- g5g.metal
- g6.xlarge
- g6.2xlarge
- g6.4xlarge
- g6.8xlarge
- g6.12xlarge
- g6.16xlarge
- g6.24xlarge
- g6.48xlarge
- g6e.xlarge
- g6e.2xlarge
- g6e.4xlarge
- g6e.8xlarge
- g6e.12xlarge
- g6e.16xlarge
- g6e.24xlarge
- g6e.48xlarge
- g6f.large
- g6f.xlarge
- g6f.2xlarge
- g6f.4xlarge
- g7e.2xlarge
- g7e.4xlarge
- g7e.8xlarge
- g7e.12xlarge
- g7e.24xlarge
- g7e.48xlarge
- gr6.4xlarge
- gr6.8xlarge
- gr6f.4xlarge
2025-12-01 20:36:57 +01:00
- m6a.large
- m6a.xlarge
- m6a.2xlarge
- m6a.4xlarge
- m6a.8xlarge
- m6a.12xlarge
- m6a.16xlarge
- m6a.24xlarge
- m6a.32xlarge
- m6a.48xlarge
- m6a.metal
- m6g.medium
- m6g.large
- m6g.xlarge
- m6g.2xlarge
- m6g.4xlarge
- m6g.8xlarge
- m6g.12xlarge
- m6g.16xlarge
- m6g.metal
- m6gd.medium
- m6gd.large
- m6gd.xlarge
- m6gd.2xlarge
- m6gd.4xlarge
- m6gd.8xlarge
- m6gd.12xlarge
- m6gd.16xlarge
- m6gd.metal
- m6i.large
- m6i.xlarge
- m6i.2xlarge
- m6i.4xlarge
- m6i.8xlarge
- m6i.12xlarge
- m6i.16xlarge
- m6i.24xlarge
- m6i.32xlarge
- m6i.metal
- m6id.large
- m6id.xlarge
- m6id.2xlarge
- m6id.4xlarge
- m6id.8xlarge
- m6id.12xlarge
- m6id.16xlarge
- m6id.24xlarge
- m6id.32xlarge
- m6id.metal
- m6idn.large
- m6idn.xlarge
- m6idn.2xlarge
- m6idn.4xlarge
- m6idn.8xlarge
- m6idn.12xlarge
- m6idn.16xlarge
- m6idn.24xlarge
- m6idn.32xlarge
- m6idn.metal
2025-04-22 11:46:24 +02:00
- m6in.large
- m6in.xlarge
- m6in.2xlarge
- m6in.4xlarge
- m6in.8xlarge
- m6in.12xlarge
- m6in.16xlarge
- m6in.24xlarge
- m6in.32xlarge
2025-12-01 20:36:57 +01:00
- m6in.metal
- m7a.medium
- m7a.large
- m7a.xlarge
- m7a.2xlarge
- m7a.4xlarge
- m7a.8xlarge
- m7a.12xlarge
- m7a.16xlarge
- m7a.24xlarge
- m7a.32xlarge
- m7a.48xlarge
- m7a.metal-48xl
- m7g.medium
- m7g.large
- m7g.xlarge
- m7g.2xlarge
- m7g.4xlarge
- m7g.8xlarge
- m7g.12xlarge
- m7g.16xlarge
- m7g.metal
- m7gd.medium
- m7gd.large
- m7gd.xlarge
- m7gd.2xlarge
- m7gd.4xlarge
- m7gd.8xlarge
- m7gd.12xlarge
- m7gd.16xlarge
- m7gd.metal
- m7i-flex.large
- m7i-flex.xlarge
- m7i-flex.2xlarge
- m7i-flex.4xlarge
- m7i-flex.8xlarge
- m7i-flex.12xlarge
- m7i-flex.16xlarge
- m7i.large
- m7i.xlarge
- m7i.2xlarge
- m7i.4xlarge
- m7i.8xlarge
- m7i.12xlarge
- m7i.16xlarge
- m7i.24xlarge
- m7i.48xlarge
- m7i.metal-24xl
- m7i.metal-48xl
- m8g.medium
- m8g.large
- m8g.xlarge
- m8g.2xlarge
- m8g.4xlarge
- m8g.8xlarge
- m8g.12xlarge
- m8g.16xlarge
- m8g.24xlarge
- m8g.48xlarge
- m8g.metal-24xl
- m8g.metal-48xl
openvidu-deployment: Add missing instance types to AllowedValues in CloudFormation templates
Add Graviton families (c8gd, m8gd, r6g, r6gd, r7g, r7gd, r8g) and
GPU/Nvidia families (g4dn, g5, g5g, g6, g6e, g6f, g7e, gr6, gr6f,
p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200) that were
referenced in Conditions (IsGraviton/IsNvidia) but missing from the
AllowedValues parameter selectors.
2026-02-27 18:49:34 +01:00
- m8gd.medium
- m8gd.large
- m8gd.xlarge
- m8gd.2xlarge
- m8gd.4xlarge
- m8gd.8xlarge
- m8gd.12xlarge
- m8gd.16xlarge
- m8gd.24xlarge
- m8gd.48xlarge
- m8gd.metal-24xl
- m8gd.metal-48xl
- p4d.24xlarge
- p4de.24xlarge
- p5.4xlarge
- p5.48xlarge
- p5e.48xlarge
- p5en.48xlarge
- p6-b200.48xlarge
- p6-b300.48xlarge
- p6e-gb200.36xlarge
- r6g.medium
- r6g.large
- r6g.xlarge
- r6g.2xlarge
- r6g.4xlarge
- r6g.8xlarge
- r6g.12xlarge
- r6g.16xlarge
- r6g.metal
- r6gd.medium
- r6gd.large
- r6gd.xlarge
- r6gd.2xlarge
- r6gd.4xlarge
- r6gd.8xlarge
- r6gd.12xlarge
- r6gd.16xlarge
- r6gd.metal
- r7g.medium
- r7g.large
- r7g.xlarge
- r7g.2xlarge
- r7g.4xlarge
- r7g.8xlarge
- r7g.12xlarge
- r7g.16xlarge
- r7g.metal
- r7gd.medium
- r7gd.large
- r7gd.xlarge
- r7gd.2xlarge
- r7gd.4xlarge
- r7gd.8xlarge
- r7gd.12xlarge
- r7gd.16xlarge
- r7gd.metal
- r8g.medium
- r8g.large
- r8g.xlarge
- r8g.2xlarge
- r8g.4xlarge
- r8g.8xlarge
- r8g.12xlarge
- r8g.16xlarge
- r8g.24xlarge
- r8g.48xlarge
- r8g.metal-24xl
- r8g.metal-48xl
2025-04-22 11:46:24 +02:00
ConstraintDescription : "Must be a valid EC2 instance type"
2025-09-15 13:40:58 +02:00
InitialMeetAdminPassword :
Description : 'Initial password for the "admin" user in OpenVidu Meet. If not provided, a random password will be generated.'
Type : String
2025-09-15 22:51:57 +02:00
NoEcho : true
2025-09-15 13:40:58 +02:00
Default : ''
# Only allow alphanumeric characters
2025-09-15 22:51:57 +02:00
AllowedPattern : '^[A-Za-z0-9_-]*$'
2025-09-15 13:40:58 +02:00
ConstraintDescription : 'Must contain only alphanumeric characters (A-Z, a-z, 0-9). Leave empty to generate a random password.'
InitialMeetApiKey :
Description : 'Initial API key for OpenVidu Meet. If not provided, no API key will be set and the user can set it later from Meet Console.'
Type : String
2025-09-15 22:51:57 +02:00
NoEcho : true
2025-09-15 13:40:58 +02:00
Default : ''
# Only allow alphanumeric characters
2025-09-15 22:51:57 +02:00
AllowedPattern : '^[A-Za-z0-9_-]*$'
2025-09-15 13:40:58 +02:00
ConstraintDescription : 'Must contain only alphanumeric characters (A-Z, a-z, 0-9). Leave empty to not set an initial API key.'
2025-04-22 11:46:24 +02:00
KeyName :
Type : AWS::EC2::KeyPair::KeyName
Description : Name of an existing EC2 KeyPair to enable SSH access to the instances
AllowedPattern : ^.+$
ConstraintDescription : must be the name of an existing EC2 KeyPair.
2025-12-01 20:36:57 +01:00
OperatingSystem :
2025-12-23 20:22:53 +01:00
Description : EC2 Operating System
2025-12-01 20:36:57 +01:00
Type : String
Default : "Ubuntu-24"
AllowedValues : [ 'Ubuntu-22' , 'Ubuntu-24' ]
2025-04-22 11:46:24 +02:00
InitialNumberOfMediaNodes :
Type : Number
Default : 1
Description : Number of initial media nodes to deploy
MinNumberOfMediaNodes :
Type : Number
Default : 1
Description : Minimum number of media nodes to deploy
MaxNumberOfMediaNodes :
Type : Number
Default : 5
Description : Maximum number of media nodes to deploy
ScaleTargetCPU :
Type : Number
Default : 50
Description : Target CPU percentage to scale up or down
S3AppDataBucketName :
Type : String
Description : Name of the S3 bucket to store data and recordings. If empty, a bucket will be created
S3ClusterDataBucketName :
Type : String
Description : Name of the S3 bucket to store cluster data. If empty, a bucket will be created
2025-06-13 19:19:53 +02:00
AdditionalInstallFlags :
Description : Additional optional flags to pass to the OpenVidu installer (comma-separated, e.g., "--flag1=value, --flag2").
Type : String
Default : ""
AllowedPattern : '^[A-Za-z0-9, =_.\-]*$' # Allows letters, numbers, comma, space, underscore, dot, equals, and hyphen
ConstraintDescription : Must be a comma-separated list of flags (for example, --flag=value, --bool-flag).
2025-04-22 11:46:24 +02:00
OpenViduVPC :
Description : "Dedicated VPC for OpenVidu cluster"
Type : AWS::EC2::VPC::Id
AllowedPattern : ^.+$
ConstraintDescription : You must specify a VPC ID
OpenViduMasterNodeSubnets :
Description : "Subnets for OpenVidu Master Node"
Type : List<AWS::EC2::Subnet::Id>
AllowedPattern : ^.+$
ConstraintDescription : You must specify a list of subnet IDs
OpenViduMediaNodeSubnets :
Description : "Subnets for OpenVidu Media Nodes"
Type : List<AWS::EC2::Subnet::Id>
AllowedPattern : ^.+$
ConstraintDescription : You must specify a list of subnet IDs
MasterNodesDiskSize :
Description : Size of the disk in GB
Type : Number
Default : 100
MinValue : 50
ConstraintDescription : The disk size must be at least 50 GB
Metadata :
'AWS::CloudFormation::Interface' :
ParameterGroups :
- Label :
default : Domain and Load Blancer configuration
Parameters :
- DomainName
- OpenViduCertificateARN
- Label :
default : OpenVidu High Availability configuration
Parameters :
- OpenViduLicense
- RTCEngine
2025-09-15 13:40:58 +02:00
- Label :
default : OpenVidu Meet configuration
Parameters :
- InitialMeetAdminPassword
- InitialMeetApiKey
2025-04-22 11:46:24 +02:00
- Label :
default : EC2 Instance configuration
Parameters :
- MasterNodeInstanceType
- MediaNodeInstanceType
- KeyName
2025-12-01 20:36:57 +01:00
- OperatingSystem
2025-04-22 11:46:24 +02:00
- Label :
default : Media Nodes Autoscaling Group configuration
Parameters :
- InitialNumberOfMediaNodes
- MinNumberOfMediaNodes
- MaxNumberOfMediaNodes
- ScaleTargetCPU
- Label :
default : S3 bucket for application data, cluster data and recordings
Parameters :
- S3AppDataBucketName
- S3ClusterDataBucketName
- Label :
default : VPC configuration
Parameters :
- OpenViduVPC
- OpenViduMasterNodeSubnets
- OpenViduMediaNodeSubnets
- Label :
default : Volumes configuration
Parameters :
- MasterNodesDiskSize
2025-06-13 19:19:53 +02:00
- Label :
default : "(Optional) Additional Installer Flags"
Parameters :
- AdditionalInstallFlags
2025-04-22 11:46:24 +02:00
Conditions :
CreateRecordingsBucket : !Equals [!Ref S3AppDataBucketName, ""]
CreateClusterDataBucket : !Equals [!Ref S3ClusterDataBucketName, ""]
2025-12-01 20:36:57 +01:00
IsMasterGraviton : !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 't4g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6g']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6gn']
2025-12-01 20:36:57 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7gd']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7gn']
2025-12-01 20:36:57 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c8g']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c8gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm6g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm7g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm7gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm8g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm8gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r6g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r7g']
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r7gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r8g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6e-gb200']
2025-12-01 20:36:57 +01:00
IsMediaGraviton : !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 't4g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6g']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6gn']
2025-12-01 20:36:57 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7gd']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7gn']
2025-12-01 20:36:57 +01:00
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c8g']
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c8gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm6g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm7g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm7gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm8g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm8gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r6g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r6gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r7g']
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r7gd']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r8g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6e-gb200']
IsMasterNodeNvidia : !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g4dn']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6e']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6f']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'gr6']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'gr6f']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g7e']
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p4d']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p4de']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5e']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5en']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6-b200']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6-b300']
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6e-gb200']
IsMediaNodeNvidia : !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g4dn']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5g']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6e']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6f']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'gr6']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'gr6f']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g7e']
- !Or
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p4d']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p4de']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5e']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5en']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6-b200']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6-b300']
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6e-gb200']
2025-04-22 11:46:24 +02:00
2025-12-01 20:36:57 +01:00
Mappings :
ArmImage :
# aws ssm get-parameters-by-path --path "/aws/service/canonical/ubuntu/" --recursive --query "Parameters[*].Name" > canonical-ami.txt
Ubuntu-22 :
ImageId : '{{resolve:ssm:/aws/service/canonical/ubuntu/server/jammy/stable/current/arm64/hvm/ebs-gp2/ami-id}}'
Ubuntu-24 :
ImageId : '{{resolve:ssm:/aws/service/canonical/ubuntu/server/noble/stable/current/arm64/hvm/ebs-gp3/ami-id}}'
AmdImage :
Ubuntu-22 :
ImageId : '{{resolve:ssm:/aws/service/canonical/ubuntu/server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id}}'
Ubuntu-24 :
ImageId : '{{resolve:ssm:/aws/service/canonical/ubuntu/server/noble/stable/current/amd64/hvm/ebs-gp3/ami-id}}'
2025-04-22 11:46:24 +02:00
Resources :
OpenViduSharedInfo :
Type : AWS::SecretsManager::Secret
UpdateReplacePolicy : Retain
DeletionPolicy : Delete
Properties :
Name : !Sub openvidu-ha-${AWS::Region}-${AWS::StackName}
Description : Secret for OpenVidu High Availability to store deployment info and seed secret
# All the values are initialized by one master node and shared with the rest of the nodes
SecretString : |
{
2025-09-15 22:51:57 +02:00
"OPENVIDU_URL": "none" ,
"MEET_INITIAL_ADMIN_USER": "none" ,
"MEET_INITIAL_ADMIN_PASSWORD": "none" ,
"MEET_INITIAL_API_KEY": "none" ,
"LIVEKIT_URL": "none" ,
"LIVEKIT_API_KEY": "none" ,
"LIVEKIT_API_SECRET": "none" ,
"DASHBOARD_URL": "none" ,
"GRAFANA_URL": "none" ,
"MINIO_URL": "none" ,
2025-04-22 11:46:24 +02:00
"DOMAIN_NAME": "none" ,
"OPENVIDU_PRO_LICENSE": "none" ,
"OPENVIDU_RTC_ENGINE": "none" ,
"REDIS_PASSWORD": "none" ,
"MONGO_ADMIN_USERNAME": "none" ,
"MONGO_ADMIN_PASSWORD": "none" ,
"MONGO_REPLICA_SET_KEY": "none" ,
"MINIO_ACCESS_KEY": "none" ,
"MINIO_SECRET_KEY": "none" ,
"DASHBOARD_ADMIN_USERNAME": "none" ,
"DASHBOARD_ADMIN_PASSWORD": "none" ,
"GRAFANA_ADMIN_USERNAME": "none" ,
"GRAFANA_ADMIN_PASSWORD": "none" ,
"ENABLED_MODULES": "none" ,
2025-09-15 22:51:57 +02:00
"OPENVIDU_VERSION": "none" ,
"ALL_SECRETS_GENERATED": "false"
2025-04-22 11:46:24 +02:00
}
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# One SSM parameter per master: atomic per-key writes
MasterNode1PrivateIpParameter :
Type : AWS::SSM::Parameter
Properties :
Name : !Sub /openvidu/${AWS::StackName}/master-node-1-private-ip
Type : String
Value : "none"
MasterNode2PrivateIpParameter :
Type : AWS::SSM::Parameter
Properties :
Name : !Sub /openvidu/${AWS::StackName}/master-node-2-private-ip
Type : String
Value : "none"
MasterNode3PrivateIpParameter :
Type : AWS::SSM::Parameter
Properties :
Name : !Sub /openvidu/${AWS::StackName}/master-node-3-private-ip
Type : String
Value : "none"
MasterNode4PrivateIpParameter :
Type : AWS::SSM::Parameter
Properties :
Name : !Sub /openvidu/${AWS::StackName}/master-node-4-private-ip
Type : String
Value : "none"
2025-04-22 11:46:24 +02:00
S3AppDataBucketResource :
Type : 'AWS::S3::Bucket'
Properties :
### Unique bucket name using Stack ID
BucketName : !Join ["-" , [ 'openvidu-appdata', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
AccessControl : Private
PublicAccessBlockConfiguration :
BlockPublicAcls : true
BlockPublicPolicy : true
IgnorePublicAcls : true
RestrictPublicBuckets : true
DeletionPolicy : Retain
UpdateReplacePolicy : Retain
Condition : CreateRecordingsBucket
S3ClusterDataBucketResource :
Type : 'AWS::S3::Bucket'
Properties :
### Unique bucket name using Stack ID
BucketName : !Join ["-" , [ 'openvidu-clusterdata', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
AccessControl : Private
PublicAccessBlockConfiguration :
BlockPublicAcls : true
BlockPublicPolicy : true
IgnorePublicAcls : true
RestrictPublicBuckets : true
DeletionPolicy : Retain
UpdateReplacePolicy : Retain
Condition : CreateClusterDataBucket
# -------------------------
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Normalize the master node subnet list to exactly 4 entries, one per OpenVidu Master Node
2025-04-22 11:46:24 +02:00
# -------------------------
SubnetProcessorFunction :
Type : AWS::Lambda::Function
Properties :
FunctionName : !Sub 'SubnetProcessor-${AWS::Region}-${AWS::StackName}'
Handler : index.lambda_handler
Role : !GetAtt LambdaExecutionRole.Arn
Code :
ZipFile : |
import cfnresponse
def lambda_handler(event, context) :
try :
# Process event data
subnets = event['ResourceProperties']['Subnets']
# Ensure we have at least four subnets by cycling through the available subnets
subnets = (subnets * 4)[:4] # Repeat the list to have at least 4 elements and then take the first 4
# Prepare the response
responseData = {
'Subnet1' : subnets[0],
'Subnet2' : subnets[1],
'Subnet3' : subnets[2],
'Subnet4' : subnets[3],
}
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
except Exception as e :
cfnresponse.send(event, context, cfnresponse.FAILED, {'Message': str(e)})
Runtime : python3.12
Timeout : 120
SubnetProcessor :
Type : Custom::SubnetProcessor
Properties :
ServiceToken : !GetAtt SubnetProcessorFunction.Arn
Subnets : !Ref OpenViduMasterNodeSubnets
LambdaLogGroup :
UpdateReplacePolicy : Retain
DeletionPolicy : Delete
Type : AWS::Logs::LogGroup
Properties :
LogGroupName : !Sub '/aws/lambda/SubnetProcessor-${AWS::Region}-${AWS::StackName}'
RetentionInDays : 7
LambdaExecutionRole :
Type : AWS::IAM::Role
Properties :
AssumeRolePolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Principal :
Service :
- lambda.amazonaws.com
Action : 'sts:AssumeRole'
Policies :
- PolicyName : LambdaLogsPolicy
PolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Action :
- logs:CreateLogStream
- logs:PutLogEvents
Resource : !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/SubnetProcessor-${AWS::Region}-${AWS::StackName}:*'
OpenViduMasterNodeRole :
Type : AWS::IAM::Role
Properties :
AssumeRolePolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Principal :
Service :
- ec2.amazonaws.com
Action :
- 'sts:AssumeRole'
Path : "/"
Policies :
- PolicyName : !Sub openvidu-master-policy-${AWS::Region}-${AWS::StackName}
PolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Action :
- autoscaling:SetInstanceHealth
Resource : '*'
Condition :
StringEquals :
'aws:ResourceTag/aws:cloudformation:stack-id' : !Ref 'AWS::StackId'
- Effect : Allow
Action :
- secretsmanager:GetSecretValue
- secretsmanager:UpdateSecret
Resource : !Ref OpenViduSharedInfo
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
- Effect : Allow
Action :
- ssm:GetParameter
- ssm:PutParameter
Resource : !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/openvidu/${AWS::StackName}/*
2025-04-22 11:46:24 +02:00
- Fn::If :
- CreateRecordingsBucket
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub ${S3AppDataBucketResource.Arn}/*
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}/*
- Fn::If :
- CreateRecordingsBucket
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !GetAtt S3AppDataBucketResource.Arn
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}
- Fn::If :
- CreateClusterDataBucket
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub ${S3ClusterDataBucketResource.Arn}/*
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub arn:${AWS::Partition}:s3:::${S3ClusterDataBucketName}/*
- Fn::If :
- CreateClusterDataBucket
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !GetAtt S3ClusterDataBucketResource.Arn
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !Sub arn:${AWS::Partition}:s3:::${S3ClusterDataBucketName}
RoleName :
Fn::Join :
# Generate a not too long and unique role name
# Getting a unique identifier from the stack id
- ''
- - openvidu-master-role-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
OpenViduMediaNodeRole :
Type : 'AWS::IAM::Role'
Properties :
AssumeRolePolicyDocument :
Version : 2012-10-17
Statement :
- Effect : Allow
Principal :
Service :
- ec2.amazonaws.com
Action :
- 'sts:AssumeRole'
Path : /
ManagedPolicyArns :
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore
Policies :
- PolicyName : !Sub openvidu-media-policy-${AWS::Region}-${AWS::StackName}
PolicyDocument :
Version : 2012-10-17
Statement :
- Effect : Allow
Action :
- secretsmanager:GetSecretValue
Resource : !Ref OpenViduSharedInfo
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
- Effect : Allow
Action :
- ssm:GetParameter
Resource : !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/openvidu/${AWS::StackName}/*
2025-04-22 11:46:24 +02:00
- Effect : Allow
Action :
- autoscaling:SetInstanceHealth
- autoscaling:CompleteLifecycleAction
- autoscaling:RecordLifecycleActionHeartbeat
Resource : '*'
Condition :
StringEquals :
'aws:ResourceTag/aws:cloudformation:stack-name' : !Ref 'AWS::StackName'
- Fn::If :
- CreateRecordingsBucket
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub ${S3AppDataBucketResource.Arn}/*
- Effect : Allow
Action :
- s3:DeleteObject
- s3:GetObject
- s3:PutObject
Resource : !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}/*
- Fn::If :
- CreateRecordingsBucket
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !GetAtt S3AppDataBucketResource.Arn
- Effect : Allow
Action :
- s3:ListBucket
- s3:GetBucketLocation
Resource : !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}
RoleName :
Fn::Join :
# Generate a not too long and unique role name
# Getting a unique identifier from the stack id
- ''
- - openvidu-media-role-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
OpenViduMasterInstanceProfile :
Type : AWS::IAM::InstanceProfile
Properties :
InstanceProfileName : !Sub OpenViduMasterInstanceProfile-${AWS::Region}-${AWS::StackName}
Roles :
- !Ref OpenViduMasterNodeRole
OpenViduMediaInstanceProfile :
Type : AWS::IAM::InstanceProfile
Properties :
InstanceProfileName : !Sub OpenViduMediaInstanceProfile-${AWS::Region}-${AWS::StackName}
Roles :
- !Ref OpenViduMediaNodeRole
OpenViduMasterLaunchTemplate :
Type : AWS::EC2::LaunchTemplate
Metadata :
Comment : Launch template for OpenVidu Master Node
AWS::CloudFormation::Init :
config :
files :
'/usr/local/bin/install.sh' :
content : !Sub |
#!/bin/bash -x
set -e
2026-07-09 12:53:05 +02:00
OPENVIDU_VERSION=main
2025-04-22 11:46:24 +02:00
DOMAIN=
2026-06-16 21:16:00 +02:00
YQ_VERSION=v4.53.3
2025-04-22 11:46:24 +02:00
# Install dependencies
apt-get update && apt-get install -y \
curl \
unzip \
jq \
wget
2025-09-07 03:56:21 +02:00
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
2025-04-22 11:46:24 +02:00
2026-06-16 21:16:00 +02:00
AWS_CLI_VERSION=2.35.5
2026-02-28 00:37:17 +01:00
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
2026-03-02 16:45:35 +01:00
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
2026-02-28 00:37:17 +01:00
unzip -qq awscliv2.zip
./aws/install
rm -rf awscliv2.zip aws
fi
2025-04-22 11:46:24 +02:00
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Signal to notify instance is waiting
2025-04-22 11:46:24 +02:00
SIGNAL_NAME="$1"
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Exported earlier in this instance's UserData
MASTER_NODE_NUM="${!MASTER_NODE_NUM}"
2025-04-22 11:46:24 +02:00
# Token for IMDSv2
TOKEN="$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")"
# Get own private IP
PRIVATE_IP="$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/local-ipv4)"
if [[ "$PRIVATE_IP" == "" ]]; then
echo "Error: Private IP not found"
exit 1
fi
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
aws ssm put-parameter \
--region ${AWS::Region} \
--name "/openvidu/${AWS::StackName}/master-node-${!MASTER_NODE_NUM}-private-ip" \
--value "${!PRIVATE_IP}" \
--type String \
--overwrite > /dev/null
2025-04-22 11:46:24 +02:00
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text)
ALL_SECRETS_GENERATED=$(echo "$SHARED_SECRET" | jq -r '.ALL_SECRETS_GENERATED')
# If the private IP is the same as the first master node, generate the secrets
if [[ $MASTER_NODE_NUM -eq 1 ]] && [[ "$ALL_SECRETS_GENERATED" == "false" ]]; then
DOMAIN="$(/usr/local/bin/store_secret.sh save DOMAIN_NAME "${DomainName}")"
2026-07-08 17:32:27 +02:00
# Publish access URLs early so other nodes can read them during phase 2
# (idempotent: after_install rewrites these same byte-identical values later)
/usr/local/bin/store_secret.sh save OPENVIDU_URL "https://${!DOMAIN}/"
/usr/local/bin/store_secret.sh save LIVEKIT_URL "wss://${!DOMAIN}/"
/usr/local/bin/store_secret.sh save DASHBOARD_URL "https://${!DOMAIN}/dashboard/"
/usr/local/bin/store_secret.sh save GRAFANA_URL "https://${!DOMAIN}/grafana/"
/usr/local/bin/store_secret.sh save MINIO_URL "https://${!DOMAIN}/minio-console/"
2025-04-22 11:46:24 +02:00
OPENVIDU_PRO_LICENSE="$(/usr/local/bin/store_secret.sh save OPENVIDU_PRO_LICENSE "${OpenViduLicense}")"
OPENVIDU_RTC_ENGINE="$(/usr/local/bin/store_secret.sh save OPENVIDU_RTC_ENGINE "${RTCEngine}")"
# Store version so media nodes can use it to install the same version
/usr/local/bin/store_secret.sh save OPENVIDU_VERSION "${!OPENVIDU_VERSION}"
2025-09-15 13:40:58 +02:00
# Meet initial admin user and password
MEET_INITIAL_ADMIN_USER="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_ADMIN_USER "admin")"
if [[ "${InitialMeetAdminPassword}" != '' ]]; then
MEET_INITIAL_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_ADMIN_PASSWORD "${InitialMeetAdminPassword}")"
else
MEET_INITIAL_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MEET_INITIAL_ADMIN_PASSWORD)"
fi
if [[ "${InitialMeetApiKey}" != '' ]]; then
MEET_INITIAL_API_KEY="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_API_KEY "${InitialMeetApiKey}")"
else
MEET_INITIAL_API_KEY="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_API_KEY "")"
fi
2025-04-22 11:46:24 +02:00
# Store usernames and generate random passwords
REDIS_PASSWORD="$(/usr/local/bin/store_secret.sh generate REDIS_PASSWORD)"
MONGO_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save MONGO_ADMIN_USERNAME "mongoadmin")"
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MONGO_ADMIN_PASSWORD)"
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/store_secret.sh generate MONGO_REPLICA_SET_KEY)"
MINIO_ACCESS_KEY="$(/usr/local/bin/store_secret.sh save MINIO_ACCESS_KEY "minioadmin")"
MINIO_SECRET_KEY="$(/usr/local/bin/store_secret.sh generate MINIO_SECRET_KEY)"
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DASHBOARD_ADMIN_USERNAME "dashboardadmin")"
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DASHBOARD_ADMIN_PASSWORD)"
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save GRAFANA_ADMIN_USERNAME "grafanaadmin")"
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate GRAFANA_ADMIN_PASSWORD)"
LIVEKIT_API_KEY="$(/usr/local/bin/store_secret.sh generate LIVEKIT_API_KEY "API" 12)"
LIVEKIT_API_SECRET="$(/usr/local/bin/store_secret.sh generate LIVEKIT_API_SECRET)"
2025-07-18 21:53:13 +02:00
ENABLED_MODULES="$(/usr/local/bin/store_secret.sh save ENABLED_MODULES "observability,v2compatibility,openviduMeet")"
2025-04-22 11:46:24 +02:00
ALL_SECRETS_GENERATED="$(/usr/local/bin/store_secret.sh save ALL_SECRETS_GENERATED "true")"
fi
2026-07-08 17:32:27 +02:00
# Fetch the shared secret again, waiting until master-1 has generated all secrets.
# Bounded (up to 900s at 5s): a genuinely stuck master-1 still surfaces after the deadline.
SECRETS_WAIT_ATTEMPTS=0
SECRETS_WAIT_MAX=180
while true; do
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text || echo 'none')
2025-04-22 11:46:24 +02:00
2026-07-08 17:32:27 +02:00
ALL_SECRETS_GENERATED=$(echo "$SHARED_SECRET" | jq -r '.ALL_SECRETS_GENERATED')
if [[ "${!ALL_SECRETS_GENERATED}" == "true" ]]; then
break
fi
SECRETS_WAIT_ATTEMPTS=$((SECRETS_WAIT_ATTEMPTS + 1))
if [[ $SECRETS_WAIT_ATTEMPTS -ge $SECRETS_WAIT_MAX ]]; then
echo "Error: Secrets not generated"
exit 1
fi
sleep 5
done
2025-04-22 11:46:24 +02:00
# sending the signal call
cfn-signal -e $? --stack ${AWS::StackId} --resource "$SIGNAL_NAME" --region ${AWS::Region}
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
IP_WAIT_ATTEMPTS=0
IP_WAIT_MAX=360
2025-04-22 11:46:24 +02:00
while true; do
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
MASTER_NODE_1_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_2_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_3_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_4_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
# Check if all master nodes have published their private IPs
if [[ "$MASTER_NODE_1_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_1_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_2_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_2_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_3_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_3_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_4_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_4_PRIVATE_IP" ]]; then
2025-04-22 11:46:24 +02:00
break
fi
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
IP_WAIT_ATTEMPTS=$((IP_WAIT_ATTEMPTS + 1))
if [[ $IP_WAIT_ATTEMPTS -ge $IP_WAIT_MAX ]]; then
echo "Error: timed out after 30 minutes waiting for all master nodes to publish their private IPs to SSM"
exit 1
fi
2025-04-22 11:46:24 +02:00
sleep 5
done
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Comma-separated 1-4: must match installer's --master-node-private-ip-list format
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
2026-07-25 00:46:02 +02:00
# Re-read: other (non-IP) values still come from the shared secret.
# GetSecretValue is eventually consistent: retry until a read returns the generated values
SECRET_READ_ATTEMPTS=0
while true; do
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text)
if echo "$SHARED_SECRET" | jq -e '(.ALL_SECRETS_GENERATED == "true") and ([.DOMAIN_NAME, .OPENVIDU_VERSION, .REDIS_PASSWORD, .MONGO_ADMIN_PASSWORD, .MONGO_REPLICA_SET_KEY, .MINIO_SECRET_KEY, .DASHBOARD_ADMIN_PASSWORD, .GRAFANA_ADMIN_PASSWORD, .LIVEKIT_API_KEY, .LIVEKIT_API_SECRET] | all(. != "none"))' > /dev/null; then
break
fi
SECRET_READ_ATTEMPTS=$((SECRET_READ_ATTEMPTS + 1))
if [[ $SECRET_READ_ATTEMPTS -ge 60 ]]; then
echo "Error: shared secret still incomplete after 5 minutes of stale reads"
exit 1
fi
sleep 5
done
2025-04-22 11:46:24 +02:00
DOMAIN=$(echo "$SHARED_SECRET" | jq -r '.DOMAIN_NAME')
OPENVIDU_PRO_LICENSE=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_PRO_LICENSE')
OPENVIDU_RTC_ENGINE=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_RTC_ENGINE')
REDIS_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.REDIS_PASSWORD')
MONGO_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.MONGO_ADMIN_USERNAME')
MONGO_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.MONGO_ADMIN_PASSWORD')
MONGO_REPLICA_SET_KEY=$(echo "$SHARED_SECRET" | jq -r '.MONGO_REPLICA_SET_KEY')
MINIO_ACCESS_KEY=$(echo "$SHARED_SECRET" | jq -r '.MINIO_ACCESS_KEY')
MINIO_SECRET_KEY=$(echo "$SHARED_SECRET" | jq -r '.MINIO_SECRET_KEY')
DASHBOARD_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.DASHBOARD_ADMIN_USERNAME')
DASHBOARD_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.DASHBOARD_ADMIN_PASSWORD')
GRAFANA_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.GRAFANA_ADMIN_USERNAME')
GRAFANA_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.GRAFANA_ADMIN_PASSWORD')
2025-08-28 13:58:03 +02:00
MEET_INITIAL_ADMIN_USER=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_ADMIN_USER')
MEET_INITIAL_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_ADMIN_PASSWORD')
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
MEET_INITIAL_API_KEY=""
2025-09-16 17:54:03 +02:00
if [[ "${InitialMeetApiKey}" != '' ]]; then
MEET_INITIAL_API_KEY=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_API_KEY')
fi
2025-04-22 11:46:24 +02:00
LIVEKIT_API_KEY=$(echo "$SHARED_SECRET" | jq -r '.LIVEKIT_API_KEY')
LIVEKIT_API_SECRET=$(echo "$SHARED_SECRET" | jq -r '.LIVEKIT_API_SECRET')
ENABLED_MODULES=$(echo "$SHARED_SECRET" | jq -r '.ENABLED_MODULES')
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure
INSTALLER_SCRIPT="/tmp/install_ov_master_node.sh"
curl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o "$INSTALLER_SCRIPT" "http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_master_node.sh"
if [ ! -s "$INSTALLER_SCRIPT" ]; then
echo "Downloaded OpenVidu master node installer is empty or missing" >&2
exit 1
fi
INSTALL_COMMAND="sh $INSTALLER_SCRIPT"
2025-04-22 11:46:24 +02:00
# Common arguments
COMMON_ARGS=(
"--no-tty"
"--install"
"--environment=aws"
"--deployment-type='ha'"
"--node-role='master-node'"
"--external-load-balancer"
"--master-node-private-ip-list='$MASTER_NODE_PRIVATE_IP_LIST'"
"--openvidu-pro-license='$OPENVIDU_PRO_LICENSE'"
"--domain-name='$DOMAIN'"
"--enabled-modules='$ENABLED_MODULES'"
"--rtc-engine=$OPENVIDU_RTC_ENGINE"
"--redis-password=$REDIS_PASSWORD"
"--mongo-admin-user=$MONGO_ADMIN_USERNAME"
"--mongo-admin-password=$MONGO_ADMIN_PASSWORD"
"--mongo-replica-set-key=$MONGO_REPLICA_SET_KEY"
"--minio-access-key=$MINIO_ACCESS_KEY"
"--minio-secret-key=$MINIO_SECRET_KEY"
"--dashboard-admin-user=$DASHBOARD_ADMIN_USERNAME"
"--dashboard-admin-password=$DASHBOARD_ADMIN_PASSWORD"
"--grafana-admin-user=$GRAFANA_ADMIN_USERNAME"
"--grafana-admin-password=$GRAFANA_ADMIN_PASSWORD"
2025-08-28 13:58:03 +02:00
"--meet-initial-admin-password=$MEET_INITIAL_ADMIN_PASSWORD"
"--meet-initial-api-key=$MEET_INITIAL_API_KEY"
2025-04-22 11:46:24 +02:00
"--livekit-api-key=$LIVEKIT_API_KEY"
"--livekit-api-secret=$LIVEKIT_API_SECRET"
)
2025-06-13 19:19:53 +02:00
# Include additional installer flags provided by the user
if [[ "${AdditionalInstallFlags}" != "" ]]; then
IFS=',' read -ra EXTRA_FLAGS <<< "${AdditionalInstallFlags}"
for extra_flag in "${!EXTRA_FLAGS[@]}"; do
# Trim whitespace around each flag
extra_flag="$(echo -e "${!extra_flag}" | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')"
if [[ "$extra_flag" != "" ]]; then
COMMON_ARGS+=("$extra_flag")
fi
done
fi
2025-04-22 11:46:24 +02:00
# Construct the final command
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${!COMMON_ARGS[@]}")"
# Install OpenVidu
exec bash -c "$FINAL_COMMAND"
mode : '000755'
owner : root
group : root
'/usr/local/bin/config_s3.sh' :
content : !Sub
- |
#!/bin/bash
set -e
# Install dir and config dir
INSTALL_DIR="/opt/openvidu"
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
# Config S3 bucket
EXTERNAL_S3_ENDPOINT="https://s3.${AWS::Region}.amazonaws.com"
EXTERNAL_S3_REGION="${AWS::Region}"
EXTERNAL_S3_PATH_STYLE_ACCESS="false"
EXTERNAL_S3_BUCKET_APP_DATA=${S3AppDataBucketResourceName}
EXTERNAL_S3_BUCKET_CLUSTER_DATA=${S3ClusterDataBucketResourceName}
sed -i "s|EXTERNAL_S3_ENDPOINT=.*|EXTERNAL_S3_ENDPOINT=$EXTERNAL_S3_ENDPOINT|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_REGION=.*|EXTERNAL_S3_REGION=$EXTERNAL_S3_REGION|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_PATH_STYLE_ACCESS=.*|EXTERNAL_S3_PATH_STYLE_ACCESS=$EXTERNAL_S3_PATH_STYLE_ACCESS|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_BUCKET_APP_DATA=.*|EXTERNAL_S3_BUCKET_APP_DATA=$EXTERNAL_S3_BUCKET_APP_DATA|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s|EXTERNAL_S3_BUCKET_CLUSTER_DATA=.*|EXTERNAL_S3_BUCKET_CLUSTER_DATA=$EXTERNAL_S3_BUCKET_CLUSTER_DATA|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
- S3AppDataBucketResourceName : !If
- CreateRecordingsBucket
- !Ref S3AppDataBucketResource
- !Ref S3AppDataBucketName
S3ClusterDataBucketResourceName : !If
- CreateClusterDataBucket
- !Ref S3ClusterDataBucketResource
- !Ref S3ClusterDataBucketName
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/after_install.sh' :
content : !Sub |
#!/bin/bash
set -e
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Only master 1 writes the shared secret, to avoid a lost-update race
if [[ "${!MASTER_NODE_NUM:-}" != "1" ]]; then
exit 0
fi
2025-04-22 11:46:24 +02:00
# Get current shared secret
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text)
# Save access URLs
DOMAIN=$(echo "$SHARED_SECRET" | jq -r '.DOMAIN_NAME')
2025-09-15 22:51:57 +02:00
OPENVIDU_URL="https://${!DOMAIN}/"
LIVEKIT_URL="wss://${!DOMAIN}/"
2025-04-22 11:46:24 +02:00
DASHBOARD_URL="https://${!DOMAIN}/dashboard/"
GRAFANA_URL="https://${!DOMAIN}/grafana/"
MINIO_URL="https://${!DOMAIN}/minio-console/"
# Update shared secret
2025-09-15 22:51:57 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_URL": "'"$OPENVIDU_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_URL": "'"$LIVEKIT_URL"'" }')"
2025-04-22 11:46:24 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$DOMAIN"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_URL": "'"$DASHBOARD_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_URL": "'"$GRAFANA_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_URL": "'"$MINIO_URL"'" }')"
# Update shared secret
aws secretsmanager update-secret \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--secret-string "$SHARED_SECRET"
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/update_config_from_secret.sh' :
content : !Sub |
#!/bin/bash
set -e
# Token for IMDSv2
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Get current shared secret
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text)
# Installation directory
INSTALL_DIR="/opt/openvidu"
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
MASTER_NODE_CONFIG_DIR="${!INSTALL_DIR}/config/node"
# Replace DOMAIN_NAME
export DOMAIN=$(echo $SHARED_SECRET | jq -r .DOMAIN_NAME)
if [[ -n "$DOMAIN" ]]; then
sed -i "s/DOMAIN_NAME=.*/DOMAIN_NAME=$DOMAIN/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
else
exit 1
fi
# Replace rest of the values
sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=$(echo $SHARED_SECRET | jq -r .REDIS_PASSWORD)/" "${!MASTER_NODE_CONFIG_DIR}/master_node.env"
sed -i "s/OPENVIDU_RTC_ENGINE=.*/OPENVIDU_RTC_ENGINE=$(echo $SHARED_SECRET | jq -r .OPENVIDU_RTC_ENGINE)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/OPENVIDU_PRO_LICENSE=.*/OPENVIDU_PRO_LICENSE=$(echo $SHARED_SECRET | jq -r .OPENVIDU_PRO_LICENSE)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_USERNAME=.*/MONGO_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .MONGO_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MONGO_ADMIN_PASSWORD=.*/MONGO_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .MONGO_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_USERNAME=.*/DASHBOARD_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .DASHBOARD_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/DASHBOARD_ADMIN_PASSWORD=.*/DASHBOARD_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .DASHBOARD_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_ACCESS_KEY=.*/MINIO_ACCESS_KEY=$(echo $SHARED_SECRET | jq -r .MINIO_ACCESS_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/MINIO_SECRET_KEY=.*/MINIO_SECRET_KEY=$(echo $SHARED_SECRET | jq -r .MINIO_SECRET_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_USERNAME=.*/GRAFANA_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .GRAFANA_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .GRAFANA_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_KEY=.*/LIVEKIT_API_KEY=$(echo $SHARED_SECRET | jq -r .LIVEKIT_API_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
sed -i "s/LIVEKIT_API_SECRET=.*/LIVEKIT_API_SECRET=$(echo $SHARED_SECRET | jq -r .LIVEKIT_API_SECRET)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
2025-08-28 13:58:03 +02:00
sed -i "s/MEET_INITIAL_ADMIN_USER=.*/MEET_INITIAL_ADMIN_USER=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_ADMIN_USER)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
sed -i "s/MEET_INITIAL_ADMIN_PASSWORD=.*/MEET_INITIAL_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
2025-09-15 22:51:57 +02:00
if [[ "${InitialMeetApiKey}" != '' ]]; then
sed -i "s/MEET_INITIAL_API_KEY=.*/MEET_INITIAL_API_KEY=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_API_KEY)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
fi
2025-04-22 11:46:24 +02:00
sed -i "s/ENABLED_MODULES=.*/ENABLED_MODULES=$(echo $SHARED_SECRET | jq -r .ENABLED_MODULES)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
# Update URLs in secret
2025-09-15 22:51:57 +02:00
OPENVIDU_URL="https://${!DOMAIN}/"
LIVEKIT_URL="wss://${!DOMAIN}/"
2025-04-22 11:46:24 +02:00
DASHBOARD_URL="https://${!DOMAIN}/dashboard/"
GRAFANA_URL="https://${!DOMAIN}/grafana/"
MINIO_URL="https://${!DOMAIN}/minio-console/"
2025-09-15 22:51:57 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_URL": "'"$OPENVIDU_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_URL": "'"$LIVEKIT_URL"'" }')"
2025-04-22 11:46:24 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$DOMAIN"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_URL": "'"$DASHBOARD_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_URL": "'"$GRAFANA_URL"'" }')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_URL": "'"$MINIO_URL"'" }')"
aws secretsmanager update-secret \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--secret-string "$SHARED_SECRET"
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/update_secret_from_config.sh' :
content : !Sub |
#!/bin/bash
set -e
# Get current shared secret
SHARED_SECRET=$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text)
# Installation directory
INSTALL_DIR="/opt/openvidu"
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
MASTER_NODE_CONFIG_DIR="${!INSTALL_DIR}/config/node"
# Update shared secret
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"REDIS_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh REDIS_PASSWORD "${!MASTER_NODE_CONFIG_DIR}/master_node.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$(/usr/local/bin/get_value_from_config.sh DOMAIN_NAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_RTC_ENGINE": "'"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_RTC_ENGINE "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_PRO_LICENSE": "'"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_PRO_LICENSE "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MONGO_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MONGO_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_ACCESS_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MINIO_ACCESS_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_SECRET_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MINIO_SECRET_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_API_KEY": "'"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_API_SECRET": "'"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_SECRET "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
2025-08-28 13:58:03 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_ADMIN_USER": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_ADMIN_USER "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
2025-09-15 22:51:57 +02:00
if [[ "${InitialMeetApiKey}" != '' ]]; then
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_API_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_API_KEY "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
fi
2025-04-22 11:46:24 +02:00
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"ENABLED_MODULES": "'"$(/usr/local/bin/get_value_from_config.sh ENABLED_MODULES "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
# Update shared secret
aws secretsmanager update-secret \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--secret-string "$SHARED_SECRET"
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/get_value_from_config.sh' :
content : |
#!/bin/bash
set -e
# Function to get the value of a given key from the environment file
get_value() {
local key="$1"
local file_path="$2"
# Use grep to find the line with the key, ignoring lines starting with #
# Use awk to split on '=' and print the second field, which is the value
local value=$(grep -E "^\s*$key\s*=" "$file_path" | awk -F= '{print $2}' | sed 's/#.*//; s/^\s*//; s/\s*$//')
# If the value is empty, return "none"
if [ -z "$value" ]; then
echo "none"
else
echo "$value"
fi
}
# Check if the correct number of arguments are supplied
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <key> <file_path>"
exit 1
fi
# Get the key and file path from the arguments
key="$1"
file_path="$2"
# Get and print the value
get_value "$key" "$file_path"
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/store_secret.sh' :
content : !Sub |
#!/bin/bash
set -e
# Modes: save, generate
# save mode: save the secret in the secret manager
# generate mode: generate a random password and save it in the secret manager
MODE="$1"
SHARED_SECRET="$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id ${OpenViduSharedInfo} \
--query SecretString --output text)"
if [[ "$MODE" == "generate" ]]; then
SECRET_KEY_NAME="$2"
PREFIX="${!3:-}"
LENGTH="${!4:-44}"
RANDOM_PASSWORD="$(openssl rand -base64 64 | tr -d '+/=\n' | cut -c -${!LENGTH})"
RANDOM_PASSWORD="${!PREFIX}${!RANDOM_PASSWORD}"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"'"$SECRET_KEY_NAME"'": "'"$RANDOM_PASSWORD"'"}')"
aws secretsmanager update-secret \
--region ${AWS::Region} \
--secret-id ${OpenViduSharedInfo} \
--secret-string "$SHARED_SECRET" > /dev/null 2>&1
echo "$RANDOM_PASSWORD"
elif [[ "$MODE" == "save" ]]; then
SECRET_KEY_NAME="$2"
SECRET_VALUE="$3"
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"'"$SECRET_KEY_NAME"'": "'"$SECRET_VALUE"'"}')"
aws secretsmanager update-secret \
--region ${AWS::Region} \
--secret-id ${OpenViduSharedInfo} \
--secret-string "$SHARED_SECRET" > /dev/null 2>&1
echo "$SECRET_VALUE"
else
exit 1
fi
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/restart.sh' :
content : |
#!/bin/bash
set -e
# Stop all services
systemctl stop openvidu
# Update config from secret
/usr/local/bin/update_config_from_secret.sh
# Start all services
systemctl start openvidu
mode : "000755"
owner : "root"
group : "root"
Properties :
LaunchTemplateName : !Sub 'openvidu-ha-master-${AWS::Region}-${AWS::StackName}'
LaunchTemplateData :
# Enable IMDSv2
MetadataOptions :
HttpEndpoint : enabled
HttpPutResponseHopLimit : 1
HttpTokens : required
IamInstanceProfile :
Name : !Ref OpenViduMasterInstanceProfile
2025-12-01 20:36:57 +01:00
ImageId : !If
- IsMasterGraviton
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !If
- IsMasterNodeNvidia
- '{{resolve:ssm:/aws/service/deeplearning/ami/arm64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
- !FindInMap [ArmImage, !Ref OperatingSystem, ImageId]
- !If
- IsMasterNodeNvidia
- '{{resolve:ssm:/aws/service/deeplearning/ami/x86_64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
- !FindInMap [AmdImage, !Ref OperatingSystem, ImageId]
2025-04-22 11:46:24 +02:00
InstanceType : !Ref MasterNodeInstanceType
KeyName : !Ref KeyName
SecurityGroupIds :
- !Ref OpenViduMasterNodeSG
BlockDeviceMappings :
- DeviceName : /dev/sda1
Ebs :
VolumeSize : !Ref MasterNodesDiskSize
VolumeType : gp3
DeleteOnTermination : true
OpenViduMasterNode1 :
Type : AWS::EC2::Instance
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Depends on its own SSM parameter so its put-parameter can't race the parameter's creation
DependsOn : MasterNode1PrivateIpParameter
2025-04-22 11:46:24 +02:00
Properties :
LaunchTemplate :
LaunchTemplateId : !Ref OpenViduMasterLaunchTemplate
Version : !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Master Node 1
SubnetId : !GetAtt SubnetProcessor.Subnet1
UserData :
Fn::Base64 : !Sub |
#!/bin/bash
set -eu -o pipefail
2025-12-16 12:49:34 +01:00
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
2025-04-22 11:46:24 +02:00
apt-get update && apt-get install -y \
python3-pip \
ec2-instance-connect
2025-09-06 20:41:39 +02:00
2026-06-16 21:16:00 +02:00
CFN_BOOTSTRAP_VERSION=2.0-39
2025-09-06 20:41:39 +02:00
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
2026-03-02 16:45:35 +01:00
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:41:39 +02:00
else
2026-03-02 16:45:35 +01:00
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:41:39 +02:00
fi
2025-04-22 11:46:24 +02:00
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
export MASTER_NODE_NUM=1
2025-04-22 11:46:24 +02:00
# Install OpenVidu
/usr/local/bin/install.sh "MasterNodesWaitCondition1" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
2026-07-08 17:32:27 +02:00
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
OPENVIDU_READY=false
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
if [ "$OPENVIDU_READY" != "true" ]; then
echo "[OpenVidu] not healthy after 300s, restarting once"
systemctl restart openvidu || true
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
fi
2025-04-22 11:46:24 +02:00
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
MasterNodesWaitCondition1 :
Type : 'AWS::CloudFormation::WaitCondition'
CreationPolicy :
ResourceSignal :
2025-12-01 21:54:57 +01:00
Timeout : PT20M
2025-04-22 11:46:24 +02:00
Count : '1'
OpenViduMasterNode2 :
Type : AWS::EC2::Instance
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
DependsOn : MasterNode2PrivateIpParameter
2025-04-22 11:46:24 +02:00
Properties :
LaunchTemplate :
LaunchTemplateId : !Ref OpenViduMasterLaunchTemplate
Version : !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Master Node 2
SubnetId : !GetAtt SubnetProcessor.Subnet2
UserData :
Fn::Base64 : !Sub |
#!/bin/bash
set -eu -o pipefail
2025-12-16 12:49:34 +01:00
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
2025-04-22 11:46:24 +02:00
apt-get update && apt-get install -y \
python3-pip \
ec2-instance-connect
2025-09-06 20:41:39 +02:00
2026-06-16 21:16:00 +02:00
CFN_BOOTSTRAP_VERSION=2.0-39
2025-09-06 20:41:39 +02:00
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
2026-03-02 16:45:35 +01:00
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:41:39 +02:00
else
2026-03-02 16:45:35 +01:00
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:41:39 +02:00
fi
2025-04-22 11:46:24 +02:00
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
export MASTER_NODE_NUM=2
2025-04-22 11:46:24 +02:00
# Install OpenVidu
/usr/local/bin/install.sh "MasterNodesWaitCondition2" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
2026-07-08 17:32:27 +02:00
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
OPENVIDU_READY=false
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
if [ "$OPENVIDU_READY" != "true" ]; then
echo "[OpenVidu] not healthy after 300s, restarting once"
systemctl restart openvidu || true
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
fi
2025-04-22 11:46:24 +02:00
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
MasterNodesWaitCondition2 :
Type : 'AWS::CloudFormation::WaitCondition'
CreationPolicy :
ResourceSignal :
2025-12-01 21:54:57 +01:00
Timeout : PT20M
2025-04-22 11:46:24 +02:00
Count : '1'
OpenViduMasterNode3 :
Type : AWS::EC2::Instance
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
DependsOn : MasterNode3PrivateIpParameter
2025-04-22 11:46:24 +02:00
Properties :
LaunchTemplate :
LaunchTemplateId : !Ref OpenViduMasterLaunchTemplate
Version : !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Master Node 3
SubnetId : !GetAtt SubnetProcessor.Subnet3
UserData :
Fn::Base64 : !Sub |
#!/bin/bash
set -eu -o pipefail
2025-12-16 12:49:34 +01:00
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
2025-04-22 11:46:24 +02:00
apt-get update && apt-get install -y \
python3-pip \
ec2-instance-connect
2025-09-06 20:44:36 +02:00
2026-06-16 21:16:00 +02:00
CFN_BOOTSTRAP_VERSION=2.0-39
2025-09-06 20:44:36 +02:00
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
2026-03-02 16:45:35 +01:00
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
else
2026-03-02 16:45:35 +01:00
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
fi
2025-04-22 11:46:24 +02:00
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
export MASTER_NODE_NUM=3
2025-04-22 11:46:24 +02:00
# Install OpenVidu
/usr/local/bin/install.sh "MasterNodesWaitCondition3" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
2026-07-08 17:32:27 +02:00
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
OPENVIDU_READY=false
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
if [ "$OPENVIDU_READY" != "true" ]; then
echo "[OpenVidu] not healthy after 300s, restarting once"
systemctl restart openvidu || true
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
fi
2025-04-22 11:46:24 +02:00
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
MasterNodesWaitCondition3 :
Type : 'AWS::CloudFormation::WaitCondition'
CreationPolicy :
ResourceSignal :
2025-12-01 21:54:57 +01:00
Timeout : PT20M
2025-04-22 11:46:24 +02:00
Count : '1'
OpenViduMasterNode4 :
Type : AWS::EC2::Instance
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
DependsOn : MasterNode4PrivateIpParameter
2025-04-22 11:46:24 +02:00
Properties :
LaunchTemplate :
LaunchTemplateId : !Ref OpenViduMasterLaunchTemplate
Version : !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Master Node 4
SubnetId : !GetAtt SubnetProcessor.Subnet4
UserData :
Fn::Base64 : !Sub |
#!/bin/bash
set -eu -o pipefail
2025-12-16 12:49:34 +01:00
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
2025-04-22 11:46:24 +02:00
apt-get update && apt-get install -y \
python3-pip \
ec2-instance-connect
2025-09-06 20:44:36 +02:00
2026-06-16 21:16:00 +02:00
CFN_BOOTSTRAP_VERSION=2.0-39
2025-09-06 20:44:36 +02:00
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
2026-03-02 16:45:35 +01:00
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
else
2026-03-02 16:45:35 +01:00
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
fi
2025-04-22 11:46:24 +02:00
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
export MASTER_NODE_NUM=4
2025-04-22 11:46:24 +02:00
# Install OpenVidu
/usr/local/bin/install.sh "MasterNodesWaitCondition4" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
2026-07-08 17:32:27 +02:00
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
OPENVIDU_READY=false
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
if [ "$OPENVIDU_READY" != "true" ]; then
echo "[OpenVidu] not healthy after 300s, restarting once"
systemctl restart openvidu || true
for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true
break
fi
sleep 5
done
fi
2025-04-22 11:46:24 +02:00
# Update shared secret
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Launch on reboot
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
MasterNodesWaitCondition4 :
Type : 'AWS::CloudFormation::WaitCondition'
CreationPolicy :
ResourceSignal :
2025-12-01 21:54:57 +01:00
Timeout : PT20M
2025-04-22 11:46:24 +02:00
Count : '1'
OpenViduMediaNodeLaunchTemplate :
Type : AWS::EC2::LaunchTemplate
Metadata :
Comment : Launch template for OpenVidu Media Node
AWS::CloudFormation::Init :
config :
files :
'/usr/local/bin/install.sh' :
content : !Sub |
#!/bin/bash
set -e
2026-06-16 21:16:00 +02:00
YQ_VERSION=v4.53.3
2025-04-22 11:46:24 +02:00
# Install dependencies
apt-get update && apt-get install -y \
curl \
unzip \
jq \
wget
2025-09-07 03:56:21 +02:00
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
2025-04-22 11:46:24 +02:00
2026-06-16 21:16:00 +02:00
AWS_CLI_VERSION=2.35.5
2026-02-28 00:37:17 +01:00
# Install aws-cli if not already installed
if ! command -v aws &> /dev/null; then
2026-03-02 16:45:35 +01:00
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
2026-02-28 00:37:17 +01:00
unzip -qq awscliv2.zip
./aws/install
rm -rf awscliv2.zip aws
fi
2025-04-22 11:46:24 +02:00
# Token for IMDSv2
TOKEN="$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")"
# Get own private IP
PRIVATE_IP="$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/local-ipv4)"
SHARED_SECRET="$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text || echo 'none')"
if [[ "$SHARED_SECRET" == "none" ]]; then
echo "Error: Shared secret not found"
exit 1
fi
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
SECRETS_WAIT_ATTEMPTS=0
SECRETS_WAIT_MAX=360
while true; do
2026-07-25 00:46:02 +02:00
# Validate content, not just the flag: stale eventually-consistent reads can return pre-generation values
if echo "$SHARED_SECRET" | jq -e '(.ALL_SECRETS_GENERATED == "true") and (.OPENVIDU_VERSION != "none") and (.REDIS_PASSWORD != "none")' > /dev/null; then
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
break
fi
SECRETS_WAIT_ATTEMPTS=$((SECRETS_WAIT_ATTEMPTS + 1))
if [[ $SECRETS_WAIT_ATTEMPTS -ge $SECRETS_WAIT_MAX ]]; then
echo "Error: timed out after 30 minutes waiting for shared secrets to be generated"
exit 1
fi
sleep 5
SHARED_SECRET="$(aws secretsmanager get-secret-value \
--region ${AWS::Region} \
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
--query SecretString --output text || echo 'none')"
done
2025-04-22 11:46:24 +02:00
# Get OpenVidu Media Nodes version to deploy
OPENVIDU_VERSION=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_VERSION')
if [[ "$OPENVIDU_VERSION" == "none" ]]; then
echo "OpenVidu version not found"
exit 1
fi
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
IP_WAIT_ATTEMPTS=0
IP_WAIT_MAX=360
while true; do
MASTER_NODE_1_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_2_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_3_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_NODE_4_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
if [[ "$MASTER_NODE_1_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_1_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_2_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_2_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_3_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_3_PRIVATE_IP" ]] &&
[ [ "$MASTER_NODE_4_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_4_PRIVATE_IP" ]]; then
break
fi
IP_WAIT_ATTEMPTS=$((IP_WAIT_ATTEMPTS + 1))
if [[ $IP_WAIT_ATTEMPTS -ge $IP_WAIT_MAX ]]; then
echo "Error: timed out after 30 minutes waiting for all master nodes to publish their private IPs to SSM"
exit 1
fi
sleep 5
done
2025-04-22 11:46:24 +02:00
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
REDIS_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.REDIS_PASSWORD')
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure
INSTALLER_SCRIPT="/tmp/install_ov_media_node.sh"
curl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o "$INSTALLER_SCRIPT" "http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh"
if [ ! -s "$INSTALLER_SCRIPT" ]; then
echo "Downloaded OpenVidu media node installer is empty or missing" >&2
exit 1
fi
INSTALL_COMMAND="sh $INSTALLER_SCRIPT"
2025-04-22 11:46:24 +02:00
# Common arguments
COMMON_ARGS=(
"--no-tty"
"--install"
"--environment=aws"
"--deployment-type='ha'"
"--node-role='media-node'"
"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST"
"--private-ip=$PRIVATE_IP"
"--redis-password=$REDIS_PASSWORD"
)
# Construct the final command with all arguments
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${!COMMON_ARGS[@]}")"
# Install OpenVidu
exec bash -c "$FINAL_COMMAND"
mode : '000755'
owner : root
group : root
'/usr/local/bin/set_as_unhealthy.sh' :
content : !Sub |
#!/bin/bash
set -e
# Token for IMDSv2
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Get own instance ID
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
# Set instance as unhealthy
aws autoscaling set-instance-health \
--region ${AWS::Region} \
--instance-id "$INSTANCE_ID" \
--health-status Unhealthy
mode : "000755"
owner : "root"
group : "root"
'/usr/local/bin/stop_media_node.sh' :
content : !Sub |
#!/bin/bash
set -e
# Token for IMDSv2
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Get own instance ID
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
ASG_NAME=openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
# Execute if docker is installed
if [ -x "$(command -v docker)" ]; then
echo "Stopping media node services and waiting for termination..."
docker container kill --signal=SIGQUIT openvidu || true
docker container kill --signal=SIGQUIT ingress || true
docker container kill --signal=SIGQUIT egress || true
2025-06-25 19:03:01 +02:00
for agent_container in $(docker ps --filter "label=openvidu-agent=true" --format '{{.Names}}'); do
docker container kill --signal=SIGQUIT "$agent_container"
done
2025-04-22 11:46:24 +02:00
TIME_PASSED=0
HEARTBEAT_MAX=1800
2025-06-25 19:03:01 +02:00
# Wait for running containers to not be openvidu, ingress, egress or an openvidu agent
while [ $(docker ps --filter "label=openvidu-agent=true" -q | wc -l) -gt 0 ] || \
[ $(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null) == "true" ] || \
2025-04-22 11:46:24 +02:00
[ $(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null) == "true" ] || \
[ $(docker inspect -f '{{.State.Running}}' egress 2>/dev/null) == "true" ]; do
echo "Waiting for containers to stop..."
sleep 5
TIME_PASSED=$((TIME_PASSED+5))
if [ $TIME_PASSED -ge $HEARTBEAT_MAX ]; then
echo "Increase lifecycle hook timeout to continue waiting for termination"
# Increase lifecycle hook timeout
aws autoscaling record-lifecycle-action-heartbeat \
--region ${AWS::Region} \
--lifecycle-hook-name StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName} \
--auto-scaling-group-name "$ASG_NAME" \
--instance-id "$INSTANCE_ID"
TIME_PASSED=0
fi
done
fi
aws autoscaling complete-lifecycle-action \
--region ${AWS::Region} \
--lifecycle-hook-name StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName} \
--auto-scaling-group-name "$ASG_NAME" \
--lifecycle-action-result CONTINUE \
--instance-id "$INSTANCE_ID"
mode : "000755"
owner : "root"
group : "root"
Properties :
LaunchTemplateName : !Sub 'openvidu-ha-media-${AWS::Region}-${AWS::StackName}'
LaunchTemplateData :
# Enable IMDSv2 by default
MetadataOptions :
HttpEndpoint : enabled
HttpPutResponseHopLimit : 1
HttpTokens : required
IamInstanceProfile :
Arn : !GetAtt OpenViduMediaInstanceProfile.Arn
SecurityGroupIds :
- !GetAtt OpenViduMediaNodeSG.GroupId
2025-12-01 20:36:57 +01:00
ImageId : !If
- IsMediaGraviton
openvidu-deployment: Add missing Graviton instances, Nvidia GPU instances, and Nvidia driver AMI selection
- Add missing Graviton/ARM instance families to CloudFormation conditions:
r6g, r6gd, r7g, r7gd, r8g, c8gd, m8gd
- Add Nvidia GPU instance detection conditions (IsNvidia/IsMasterNodeNvidia/
IsMediaNodeNvidia) for families: g4dn, g5, g5g, g6, g6e, g6f, gr6, gr6f,
g7e, p4d, p4de, p5, p5e, p5en, p6-b200, p6-b300, p6e-gb200
- Use Ubuntu Deep Learning AMIs with pre-installed Nvidia drivers when a
GPU instance type is selected, choosing arm64 or x86_64 variant based
on the Graviton condition
2026-02-27 18:12:59 +01:00
- !If
- IsMediaNodeNvidia
- '{{resolve:ssm:/aws/service/deeplearning/ami/arm64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
- !FindInMap [ArmImage, !Ref OperatingSystem, ImageId]
- !If
- IsMediaNodeNvidia
- '{{resolve:ssm:/aws/service/deeplearning/ami/x86_64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
- !FindInMap [AmdImage, !Ref OperatingSystem, ImageId]
2025-04-22 11:46:24 +02:00
KeyName : !Ref KeyName
InstanceType : !Ref MediaNodeInstanceType
UserData :
Fn::Base64 : !Sub |
#!/bin/bash
set -eu -o pipefail
2025-12-16 12:49:34 +01:00
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
2025-04-22 11:46:24 +02:00
apt-get update && apt-get install -y \
python3-pip \
ec2-instance-connect
2025-09-06 20:44:36 +02:00
2026-06-16 21:16:00 +02:00
CFN_BOOTSTRAP_VERSION=2.0-39
2025-09-06 20:44:36 +02:00
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
2026-03-02 16:45:35 +01:00
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
else
2026-03-02 16:45:35 +01:00
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
2025-09-06 20:44:36 +02:00
fi
2025-04-22 11:46:24 +02:00
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
cfn-init --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMediaNodeLaunchTemplate
2025-04-22 11:46:24 +02:00
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; /usr/local/bin/set_as_unhealthy.sh; exit 1; }
openvidu-deployment: optimize AWS HA deployment time
Parallel master creation: drop the MasterNodeN -> WaitConditionN-1
DependsOn chain. Each master gets a fixed MASTER_NODE_NUM via UserData
(replaces subnet-matching detection) and publishes its private IP to its
own SSM parameter (atomic per-key writes; the 4 parameters are stack
resources), removing the IP exchange through the shared Secrets Manager
JSON and its lost-update race. after_install.sh is now leader-only, so
the shared JSON keeps a single writer with parallel masters.
Ungate media nodes and the NLB from WaitCondition4: media wait for
secrets + the 4 SSM IPs (bounded polls) before the heavy install, and
for a healthy master (:7880/health/caddy) before starting the service.
Bounded timeout on the previously infinite IP wait, robust installer
fetch (curl --retry to file instead of sh <(curl)), SSM read/write IAM
statements, MEET_INITIAL_API_KEY dead-code fix, SubnetProcessor Lambda
cleanup (unused boto3 client and ec2:DescribeSubnets permission).
Validated with ov-cloud-tester (sc-deploy-destroy, ha, dev): PASS.
deploy 5m24s (baseline ~12m), ready 21m14s (wait-ready dominated by
external DNS propagation), destroy 7m39s.
2026-07-24 17:11:58 +02:00
MASTER_IP_1=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_IP_2=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_IP_3=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_IP_4=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
MASTER_HEALTHY=false
for i in $(seq 1 360); do
for MASTER_IP in "$MASTER_IP_1" "$MASTER_IP_2" "$MASTER_IP_3" "$MASTER_IP_4"; do
if [ "$MASTER_IP" != "none" ] && [ -n "$MASTER_IP" ] && curl -sf "http://$MASTER_IP:7880/health/caddy" >/dev/null 2>&1; then
MASTER_HEALTHY=true
break
fi
done
if [ "$MASTER_HEALTHY" = "true" ]; then
break
fi
sleep 5
done
if [ "$MASTER_HEALTHY" != "true" ]; then
echo "[OpenVidu] no master node became healthy after 30 minutes"
/usr/local/bin/set_as_unhealthy.sh
exit 1
fi
2025-04-22 11:46:24 +02:00
# Start OpenVidu
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; /usr/local/bin/set_as_unhealthy.sh; exit 1; }
# Wait for the app
# /usr/local/bin/check_app_ready.sh
BlockDeviceMappings :
- DeviceName : /dev/sda1
Ebs :
VolumeType : gp3
DeleteOnTermination : true
2026-02-27 23:25:28 +01:00
VolumeSize : !If [IsMediaNodeNvidia, 100, 50]
2025-04-22 11:46:24 +02:00
OpenViduMediaNodeASG :
DependsOn :
- OpenViduMediaInstanceProfile
- OpenViduMasterInstanceProfile
- StopMediaNodeCloudWatchEventRule
Type : AWS::AutoScaling::AutoScalingGroup
Properties :
AutoScalingGroupName : !Sub openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
LaunchTemplate :
LaunchTemplateId : !Ref OpenViduMediaNodeLaunchTemplate
Version : !GetAtt OpenViduMediaNodeLaunchTemplate.DefaultVersionNumber
TargetGroupARNs :
2026-01-27 16:37:20 +01:00
- !Ref OpenViduMediaNodeRTMPTG
2025-04-22 11:46:24 +02:00
MinSize : !Ref MinNumberOfMediaNodes
MaxSize : !Ref MaxNumberOfMediaNodes
DesiredCapacity : !Ref InitialNumberOfMediaNodes
VPCZoneIdentifier : !Ref OpenViduMediaNodeSubnets
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Media Node
PropagateAtLaunch : true
StopMediaNodeLifecycleHook :
Type : 'AWS::AutoScaling::LifecycleHook'
Properties :
LifecycleHookName : !Sub StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName}
AutoScalingGroupName : !Ref OpenViduMediaNodeASG
LifecycleTransition : 'autoscaling:EC2_INSTANCE_TERMINATING'
DefaultResult : 'CONTINUE'
HeartbeatTimeout : 3600
StopMediaNodeDocumentRole :
Type : AWS::IAM::Role
Properties :
AssumeRolePolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Principal :
Service :
- ssm.amazonaws.com
Action :
- sts:AssumeRole
Policies :
- PolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Action :
- ssm:DescribeInstanceInformation
- ssm:ListCommands
- ssm:ListCommandInvocations
Resource : "*"
- Effect : Allow
Action :
- ssm:SendCommand
Resource : !Sub arn:${AWS::Partition}:ssm:${AWS::Region}::document/AWS-RunShellScript
- Action :
- ssm:SendCommand
Resource : !Sub arn:${AWS::Partition}:ec2:*:*:instance/*
Condition :
StringEquals :
'aws:ResourceTag/aws:cloudformation:stack-name' : !Ref 'AWS::StackName'
Effect : Allow
PolicyName : SSM-Automation-Policy
StopMediaNodeAutomationDocument :
Type : AWS::SSM::Document
Properties :
Name :
Fn::Join :
# Generate a not too long and unique document name
# Getting a unique identifier from the stack id
- ''
- - 'StopMediaNodeAutomationDocument-'
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
DocumentType : Automation
Content :
schemaVersion : '0.3'
assumeRole : "{{automationAssumeRole}}"
description : This document stops the OpenVidu services in a Media Node and
terminates the instance. It stop the OpenVidu services without interrupting
the running sessions, ingress and egress running in the Media Node.
Also it sends a CONTINUE signal to the Auto Scaling Group to continue the
instance termination when the services are stopped.
parameters :
InstanceId :
type : String
automationAssumeRole :
type : String
default : !GetAtt StopMediaNodeDocumentRole.Arn
description : "(Required) The ARN of the role that allows Automation to
perform the actions."
mainSteps :
- name : RunCommand
action : aws:runCommand
inputs :
DocumentName : AWS-RunShellScript
InstanceIds :
- "{{ InstanceId }}"
Parameters :
# 24 hours as a timeout to wait for the instance to stop all services
executionTimeout : "60"
commands :
- nohup /usr/local/bin/stop_media_node.sh > /var/log/stop_media_node.log 2>&1 &
StopMediaNodeCloudWatchEventRole :
Type : AWS::IAM::Role
Properties :
AssumeRolePolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Principal :
Service :
- events.amazonaws.com
Action :
- sts:AssumeRole
Policies :
- PolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Action :
- ssm:StartAutomationExecution
2026-01-27 20:00:40 +01:00
Resource :
- !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-execution/*
- !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:document/${StopMediaNodeAutomationDocument}
2025-04-22 11:46:24 +02:00
PolicyName : !Sub StopMediaNodeCloudWatchEventPolicy-${AWS::Region}-${AWS::StackName}
- PolicyDocument :
Version : '2012-10-17'
Statement :
- Effect : Allow
Action :
- iam:PassRole
Resource : !GetAtt StopMediaNodeDocumentRole.Arn
PolicyName : Pass-Role-SSM-Automation-Policy
StopMediaNodeCloudWatchEventRule :
Type : AWS::Events::Rule
Properties :
Description : Rule to trigger the StopMediaNodeAutomationDocument when an instance is terminated
EventPattern :
source :
- aws.autoscaling
detail-type :
- EC2 Instance-terminate Lifecycle Action
detail :
AutoScalingGroupName :
- !Sub openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
Name :
Fn::Join :
# Generate a not too long and unique rule name
# Getting a unique identifier from the stack id
- ''
- - StopMediaNodeCloudWatchEventRule-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
Targets :
- Arn : !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${StopMediaNodeAutomationDocument}:$DEFAULT
RoleArn : !GetAtt StopMediaNodeCloudWatchEventRole.Arn
Id :
Fn::Join :
# Generate a not too long and unique target id
# Getting a unique identifier from the stack id
- ''
- - StopMediaNodeCloudWatchEventRule-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
InputTransformer :
InputPathsMap :
instanceid : "$.detail.EC2InstanceId"
InputTemplate : |
{
"InstanceId": [ <instanceid> ]
}
OpenViduMediaNodeASGScalingPolicy :
Type : AWS::AutoScaling::ScalingPolicy
Properties :
AutoScalingGroupName : !Ref OpenViduMediaNodeASG
PolicyType : TargetTrackingScaling
EstimatedInstanceWarmup : 120
TargetTrackingConfiguration :
PredefinedMetricSpecification :
PredefinedMetricType : ASGAverageCPUUtilization
TargetValue : !Ref ScaleTargetCPU
OpenViduMasterNodeSG :
Type : AWS::EC2::SecurityGroup
Properties :
GroupDescription : Security group for OpenVidu Master Node
GroupName : !Sub openvidu-ha-master-sg-${AWS::Region}-${AWS::StackName}
VpcId : !Ref OpenViduVPC
SecurityGroupIngress :
- IpProtocol : tcp
FromPort : 22
ToPort : 22
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 22
ToPort : 22
CidrIpv6 : : : /0
2025-09-15 22:51:57 +02:00
OpenViduLoadBalancerToMasterHTTPIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 80
ToPort : 80
SourceSecurityGroupId : !Ref OpenViduLoadBalancerSG
2025-04-22 11:46:24 +02:00
OpenViduLoadBalancerToMasterIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7880
ToPort : 7880
SourceSecurityGroupId : !Ref OpenViduLoadBalancerSG
OpenViduMasterToMasterRedisIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7000
ToPort : 7001
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
2025-10-10 14:51:55 +02:00
OpenViduMediaNodeToMasterNodeClusterPortIngress :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7880
ToPort : 7880
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
2025-04-22 11:46:24 +02:00
OpenViduMediaNodeToMasterRedisIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7000
ToPort : 7001
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
OpenViduMasterToMasterMinioIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9100
ToPort : 9100
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMasterMinioConsoleSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9101
ToPort : 9101
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMediaNodeToMasterMinioIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9100
ToPort : 9100
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
OpenViduMasterToMasterMongoIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 20000
ToPort : 20000
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMediaNodeToMasterMongoIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 20000
ToPort : 20000
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
OpenViduMasterToMasterMimirGrpcIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9095
ToPort : 9095
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMasterMimirGossipIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7946
ToPort : 7946
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMediaNodeToMasterHTTPMimirSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9009
ToPort : 9009
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
OpenViduMasterToMasterLokiGrpcIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 9096
ToPort : 9096
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMasterLokiGossipIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 7947
ToPort : 7947
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMasterDashboardsIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 5000
ToPort : 5000
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMasterGrafanaIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 3000
ToPort : 3000
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMediaNodeToMasterHTTPLokiSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 3100
ToPort : 3100
SourceSecurityGroupId : !Ref OpenViduMediaNodeSG
OpenViduMasterToMasterV2CompatibilityIngress :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 4443
ToPort : 4443
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMediaNodeToMasterV2CompatibilityWebhookIngress :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !GetAtt OpenViduMasterNodeSG.GroupId
IpProtocol : tcp
FromPort : 4443
ToPort : 4443
SourceSecurityGroupId : !GetAtt OpenViduMediaNodeSG.GroupId
2025-07-22 14:08:25 +02:00
OpenViduMasterToMasterMeetIngress :
2025-04-22 11:46:24 +02:00
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
2026-02-05 12:30:22 +01:00
FromPort : 9080
ToPort : 9080
2025-04-22 11:46:24 +02:00
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
2026-03-13 17:46:29 +01:00
OpenViduMasterToMasterCustomAppIngress :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 6080
ToPort : 6080
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
2025-07-22 14:08:25 +02:00
OpenViduMediaNodeToMasterMeetWebhookIngress :
2025-04-22 11:46:24 +02:00
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !GetAtt OpenViduMasterNodeSG.GroupId
IpProtocol : tcp
2026-02-05 12:30:22 +01:00
FromPort : 9080
ToPort : 9080
2025-04-22 11:46:24 +02:00
SourceSecurityGroupId : !GetAtt OpenViduMediaNodeSG.GroupId
2026-03-13 17:46:29 +01:00
OpenViduMediaNodeToMasterCustomAppIngress :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !GetAtt OpenViduMasterNodeSG.GroupId
IpProtocol : tcp
FromPort : 6080
ToPort : 6080
SourceSecurityGroupId : !GetAtt OpenViduMediaNodeSG.GroupId
2025-04-22 11:46:24 +02:00
OpenViduMediaNodeSG :
Type : AWS::EC2::SecurityGroup
Properties :
GroupDescription : Security group for OpenVidu Media Node
GroupName : !Sub openvidu-ha-media-sg-${AWS::Region}-${AWS::StackName}
VpcId : !Ref OpenViduVPC
SecurityGroupIngress :
- IpProtocol : tcp
FromPort : 22
ToPort : 22
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 22
ToPort : 22
CidrIpv6 : : : /0
- IpProtocol : udp
FromPort : 443
ToPort : 443
CidrIp : 0.0 .0 .0 /0
- IpProtocol : udp
FromPort : 443
ToPort : 443
CidrIpv6 : : : /0
2025-07-11 21:33:05 +02:00
- IpProtocol : tcp
FromPort : 7881
ToPort : 7881
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 7881
ToPort : 7881
CidrIpv6 : : : /0
2025-04-22 11:46:24 +02:00
- IpProtocol : udp
FromPort : 7885
ToPort : 7885
CidrIp : 0.0 .0 .0 /0
- IpProtocol : udp
FromPort : 7885
ToPort : 7885
CidrIpv6 : : : /0
- IpProtocol : udp
FromPort : 50000
ToPort : 60000
CidrIp : 0.0 .0 .0 /0
- IpProtocol : udp
FromPort : 50000
ToPort : 60000
CidrIpv6 : : : /0
2025-07-11 21:33:05 +02:00
- IpProtocol : tcp
FromPort : 50000
ToPort : 60000
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 50000
ToPort : 60000
CidrIpv6 : : : /0
2025-04-22 11:46:24 +02:00
OpenViduLoadBalancerToMediaNodeRTMPIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMediaNodeSG
IpProtocol : tcp
FromPort : 1945
ToPort : 1945
SourceSecurityGroupId : !Ref OpenViduLoadBalancerSG
OpenViduLoadBalancerToMediaNodeIngressHealthCheckSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMediaNodeSG
IpProtocol : tcp
FromPort : 9092
ToPort : 9092
SourceSecurityGroupId : !Ref OpenViduLoadBalancerSG
OpenViduMasterToMediaNodeServerIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMediaNodeSG
IpProtocol : tcp
FromPort : 7880
ToPort : 7880
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduMasterToMediaNodeClientIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMediaNodeSG
IpProtocol : tcp
FromPort : 8080
ToPort : 8080
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
2025-06-14 02:02:29 +02:00
OpenViduTurnTLSMasterNodeToMediaNodeIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMediaNodeSG
IpProtocol : tcp
FromPort : 5349
ToPort : 5349
SourceSecurityGroupId : !Ref OpenViduMasterNodeSG
OpenViduTurnTLSLoadBalancerToMediaNodeIngressSG :
Type : AWS::EC2::SecurityGroupIngress
Properties :
GroupId : !Ref OpenViduMasterNodeSG
IpProtocol : tcp
FromPort : 443
ToPort : 443
SourceSecurityGroupId : !Ref OpenViduLoadBalancerSG
2025-04-22 11:46:24 +02:00
OpenViduLoadBalancerSG :
Type : AWS::EC2::SecurityGroup
Properties :
GroupDescription : Security group for the Load Balancer
GroupName : !Sub openvidu-ha-lb-sg-${AWS::Region}-${AWS::StackName}
VpcId : !Ref OpenViduVPC
SecurityGroupIngress :
- IpProtocol : tcp
FromPort : 80
ToPort : 80
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 80
ToPort : 80
CidrIpv6 : : : /0
- IpProtocol : tcp
FromPort : 443
ToPort : 443
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 443
ToPort : 443
CidrIpv6 : : : /0
- IpProtocol : tcp
FromPort : 1935
ToPort : 1935
CidrIp : 0.0 .0 .0 /0
- IpProtocol : tcp
FromPort : 1935
ToPort : 1935
CidrIpv6 : : : /0
LoadBalancer :
Type : AWS::ElasticLoadBalancingV2::LoadBalancer
Properties :
Name :
Fn::Join :
# Generate a not too long and unique load balancer name
# Getting a unique identifier from the stack id
- ''
- - OpenViduHA-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
Subnets : !Ref OpenViduMasterNodeSubnets
SecurityGroups :
- !Ref OpenViduLoadBalancerSG
Type : network
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Load Balancer
2025-09-15 22:51:57 +02:00
OpenViduMasterNodeWithTurnTLSHTTPListener :
Type : 'AWS::ElasticLoadBalancingV2::Listener'
Properties :
DefaultActions :
- Type : forward
2026-03-12 21:19:15 +01:00
TargetGroupArn : !Ref OpenViduMasterNodeHTTPTG
2025-09-15 22:51:57 +02:00
LoadBalancerArn : !Ref LoadBalancer
Port : 80
Protocol : TCP
2025-06-14 02:02:29 +02:00
OpenViduMasterNodeWithTurnTLSListener :
Type : 'AWS::ElasticLoadBalancingV2::Listener'
Properties :
DefaultActions :
- Type : forward
TargetGroupArn : !Ref OpenViduMasterNodeWithTurnTLSTG
LoadBalancerArn : !Ref LoadBalancer
Port : 443
Protocol : TLS
Certificates :
- CertificateArn : !Ref OpenViduCertificateARN
2025-04-22 11:46:24 +02:00
OpenViduRTMPMediaNodeListener :
Type : 'AWS::ElasticLoadBalancingV2::Listener'
Properties :
DefaultActions :
- Type : forward
TargetGroupArn : !Ref OpenViduMediaNodeRTMPTG
LoadBalancerArn : !Ref LoadBalancer
Port : 1935
Protocol : TLS
Certificates :
- CertificateArn : !Ref OpenViduCertificateARN
2025-09-15 22:51:57 +02:00
OpenViduMasterNodeHTTPTG :
Type : AWS::ElasticLoadBalancingV2::TargetGroup
Properties :
Name :
Fn::Join :
# Generate a not too long and unique target id
# Getting a unique identifier from the stack id
- ''
- - OVHTTP-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
TargetType : instance
Targets :
- Id : !Ref OpenViduMasterNode1
- Id : !Ref OpenViduMasterNode2
- Id : !Ref OpenViduMasterNode3
- Id : !Ref OpenViduMasterNode4
VpcId : !Ref OpenViduVPC
Port : 80
Protocol : TCP
Matcher :
HttpCode : '200'
HealthCheckIntervalSeconds : 10
HealthCheckPath : /health/caddy
HealthCheckProtocol : HTTP
HealthCheckPort : '7880'
HealthCheckTimeoutSeconds : 5
HealthyThresholdCount : 3
UnhealthyThresholdCount : 4
TargetGroupAttributes :
- Key : deregistration_delay.timeout_seconds
Value : 60
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - Master HTTP Target Group
2025-06-14 02:02:29 +02:00
OpenViduMasterNodeWithTurnTLSTG :
Type : AWS::ElasticLoadBalancingV2::TargetGroup
Properties :
Name :
Fn::Join :
# Generate a not too long and unique target id
# Getting a unique identifier from the stack id
- ''
- - OVTurnTLSMaster-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
TargetType : instance
Targets :
- Id : !Ref OpenViduMasterNode1
- Id : !Ref OpenViduMasterNode2
- Id : !Ref OpenViduMasterNode3
- Id : !Ref OpenViduMasterNode4
VpcId : !Ref OpenViduVPC
Port : 443
Protocol : TCP
Matcher :
HttpCode : '200'
HealthCheckIntervalSeconds : 10
HealthCheckPath : /health/caddy
HealthCheckProtocol : HTTP
HealthCheckPort : '7880'
HealthCheckTimeoutSeconds : 5
HealthyThresholdCount : 3
UnhealthyThresholdCount : 4
TargetGroupAttributes :
- Key : deregistration_delay.timeout_seconds
Value : 60
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - TURN TLS Master Target Group
2025-04-22 11:46:24 +02:00
OpenViduMediaNodeRTMPTG :
Type : AWS::ElasticLoadBalancingV2::TargetGroup
Properties :
Name :
Fn::Join :
# Generate a not too long and unique target id
# Getting a unique identifier from the stack id
- ''
- - OVRTMP-
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
VpcId : !Ref OpenViduVPC
Port : 1945
Protocol : TCP
Matcher :
HttpCode : '200'
HealthCheckIntervalSeconds : 10
HealthCheckPath : /
HealthCheckProtocol : HTTP
# Ingress health check port
HealthCheckPort : '9092'
HealthCheckTimeoutSeconds : 5
HealthyThresholdCount : 3
UnhealthyThresholdCount : 4
TargetGroupAttributes :
- Key : deregistration_delay.timeout_seconds
Value : 60
Tags :
- Key : Name
Value : !Sub ${AWS::StackName} - OpenVidu HA - RTMP Target Group
Outputs :
ServicesAndCredentials :
Description : Services and credentials
Value : !Sub https://${AWS::Region}.console.aws.amazon.com/secretsmanager/home?region=${AWS::Region}#!/secret?name=openvidu-ha-${AWS::Region}-${AWS::StackName}