openvidu-deployment: AWS - wait for the Elastic IP before deriving the domain

NewEIP was created with InstanceId, so the Elastic IP was attached only
after the instance existed, racing with the boot scripts: the domain could
be derived from whatever public IP the instance had at that moment (the
subnet's ephemeral one, or none), and with no public IP there was no
Internet access for apt-get, cfn-init or the installer either.

In the CE single node, Pro single node and Pro elastic templates, NewEIP is
now allocated on its own and attached by a separate NewEIPAssociation, so
its address is known up front. UserData waits up to 10 minutes for the
instance to have that address before doing anything else, and install.sh
reads public-ipv4 instead of public-hostname (empty in VPCs without DNS
hostnames).


Assisted-by: claude-code - Anthropic - Claude Opus 5.5
media-node-health
cruizba 2026-10-06 16:00:49 +02:00
parent 3208097dd4
commit b372409ccf
3 changed files with 191 additions and 122 deletions

View File

@ -706,8 +706,7 @@ Resources:
# Configure Domain # Configure Domain
if [[ "${DomainName}" == '' ]]; then if [[ "${DomainName}" == '' ]]; then
PublicHostname=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname) DOMAIN=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4)
DOMAIN=$(echo "$PublicHostname" | cut -d'.' -f1 | sed 's/^ec2-//' | tr '-' '.')
else else
DOMAIN=${DomainName} DOMAIN=${DomainName}
fi fi
@ -1100,49 +1099,68 @@ Resources:
- Key: Name - Key: Name
Value: !Ref 'AWS::StackName' Value: !Ref 'AWS::StackName'
UserData: UserData:
Fn::Base64: !Sub | Fn::Base64: !Sub
#!/bin/bash -x - |
set -eu -o pipefail #!/bin/bash -x
set -eu -o pipefail
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout # Wait for the Elastic IP: CloudFormation associates it only after the instance
# is created, and until then the instance may have another public IP (or none,
# and no Internet access)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
CURRENT_PUBLIC_IP=""
for _ in $(seq 1 120); do
CURRENT_PUBLIC_IP=$(curl -sf -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4 || true)
if [[ "$CURRENT_PUBLIC_IP" == "${ExpectedPublicIp}" ]]; then
break
fi
sleep 5
done
if [[ "$CURRENT_PUBLIC_IP" != "${ExpectedPublicIp}" ]]; then
echo "[OpenVidu] Elastic IP ${ExpectedPublicIp} not attached after 10 minutes"
exit 1
fi
apt-get update && apt-get install -y \ echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
python3-pip \
ec2-instance-connect
CFN_BOOTSTRAP_VERSION=2.0-39 apt-get update && apt-get install -y \
# Detect Ubuntu version and install cfn-bootstrap accordingly python3-pip \
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1) ec2-instance-connect
if [ "$UBUNTU_VERSION" -ge 24 ]; then
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
else
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
fi
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer CFN_BOOTSTRAP_VERSION=2.0-39
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
else
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
fi
export HOME="/root" cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer
# Install OpenVidu export HOME="/root"
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket # Install OpenVidu
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; } /usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Start OpenVidu # Config S3 bucket
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; } /usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Update shared secret # Start OpenVidu
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; } systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
# Launch on reboot # Update shared secret
echo "@reboot /usr/local/bin/restart.sh" | crontab /usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Wait for the app # Launch on reboot
/usr/local/bin/check_app_ready.sh echo "@reboot /usr/local/bin/restart.sh" | crontab
# sending the finish call # Wait for the app
cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region} /usr/local/bin/check_app_ready.sh
# sending the finish call
cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}
- ExpectedPublicIp: !If [PublicElasticIPPresent, !Ref PublicElasticIP, !Ref NewEIP]
BlockDeviceMappings: BlockDeviceMappings:
- DeviceName: /dev/sda1 - DeviceName: /dev/sda1
@ -1161,8 +1179,13 @@ Resources:
NewEIP: NewEIP:
Type: 'AWS::EC2::EIP' Type: 'AWS::EC2::EIP'
Condition: PublicElasticIPAbsent Condition: PublicElasticIPAbsent
NewEIPAssociation:
Type: 'AWS::EC2::EIPAssociation'
Condition: PublicElasticIPAbsent
Properties: Properties:
InstanceId: !Ref OpenviduServer InstanceId: !Ref OpenviduServer
AllocationId: !GetAtt NewEIP.AllocationId
IMDSv2LaunchTemplate: IMDSv2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate Type: AWS::EC2::LaunchTemplate

View File

@ -1410,8 +1410,13 @@ Resources:
NewEIP: NewEIP:
Type: 'AWS::EC2::EIP' Type: 'AWS::EC2::EIP'
Condition: PublicElasticIPAbsent Condition: PublicElasticIPAbsent
NewEIPAssociation:
Type: 'AWS::EC2::EIPAssociation'
Condition: PublicElasticIPAbsent
Properties: Properties:
InstanceId: !Ref OpenViduMasterNode InstanceId: !Ref OpenViduMasterNode
AllocationId: !GetAtt NewEIP.AllocationId
IMDSv2LaunchTemplateMasterNode: IMDSv2LaunchTemplateMasterNode:
Type: AWS::EC2::LaunchTemplate Type: AWS::EC2::LaunchTemplate
@ -1469,8 +1474,7 @@ Resources:
# Configure Domain and other parameters # Configure Domain and other parameters
if [[ "${DomainName}" == '' ]]; then if [[ "${DomainName}" == '' ]]; then
PublicHostname=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname) DOMAIN=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4)
DOMAIN=$(echo "$PublicHostname" | cut -d'.' -f1 | sed 's/^ec2-//' | tr '-' '.')
else else
DOMAIN=${DomainName} DOMAIN=${DomainName}
fi fi
@ -1940,56 +1944,64 @@ Resources:
- Key: Name - Key: Name
Value: !Sub ${AWS::StackName} - OpenVidu Elastic - Master Node Value: !Sub ${AWS::StackName} - OpenVidu Elastic - Master Node
UserData: UserData:
Fn::Base64: !Sub | Fn::Base64: !Sub
#!/bin/bash - |
set -eu -o pipefail #!/bin/bash
set -eu -o pipefail
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout # Wait for the Elastic IP: CloudFormation associates it only after the instance
# is created, and until then the instance may have another public IP (or none,
apt-get update && apt-get install -y \ # and no Internet access)
python3-pip \ TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ec2-instance-connect CURRENT_PUBLIC_IP=""
for _ in $(seq 1 120); do
CFN_BOOTSTRAP_VERSION=2.0-39 CURRENT_PUBLIC_IP=$(curl -sf -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4 || true)
# Detect Ubuntu version and install cfn-bootstrap accordingly if [[ "$CURRENT_PUBLIC_IP" == "${ExpectedPublicIp}" ]]; then
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1) break
if [ "$UBUNTU_VERSION" -ge 24 ]; then fi
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz sleep 5
else done
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz if [[ "$CURRENT_PUBLIC_IP" != "${ExpectedPublicIp}" ]]; then
fi echo "[OpenVidu] Elastic IP ${ExpectedPublicIp} not attached after 10 minutes"
exit 1
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenViduMasterNode
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { 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; }
# 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
# 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 fi
sleep 5
done echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
if [ "$OPENVIDU_READY" != "true" ]; then
echo "[OpenVidu] not healthy after 300s, restarting once" apt-get update && apt-get install -y \
systemctl restart openvidu || true python3-pip \
ec2-instance-connect
CFN_BOOTSTRAP_VERSION=2.0-39
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
else
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
fi
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenViduMasterNode
export HOME="/root"
# Install OpenVidu
/usr/local/bin/install.sh || { 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; }
# 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
# 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 for i in $(seq 1 60); do
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
OPENVIDU_READY=true OPENVIDU_READY=true
@ -1997,14 +2009,25 @@ Resources:
fi fi
sleep 5 sleep 5
done done
fi 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
# Disable errexit so cfn-signal always runs and reports readiness via $? (fast-fail instead of a PT20M timeout) # Disable errexit so cfn-signal always runs and reports readiness via $? (fast-fail instead of a PT20M timeout)
set +e set +e
[ "$OPENVIDU_READY" = "true" ] [ "$OPENVIDU_READY" = "true" ]
# sending the finish call # sending the finish call
cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region} cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}
- ExpectedPublicIp: !If [PublicElasticIPPresent, !Ref PublicElasticIP, !Ref NewEIP]
BlockDeviceMappings: BlockDeviceMappings:
- DeviceName: /dev/sda1 - DeviceName: /dev/sda1

View File

@ -808,8 +808,7 @@ Resources:
# Configure Domain # Configure Domain
if [[ "${DomainName}" == '' ]]; then if [[ "${DomainName}" == '' ]]; then
PublicHostname=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname) DOMAIN=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4)
DOMAIN=$(echo "$PublicHostname" | cut -d'.' -f1 | sed 's/^ec2-//' | tr '-' '.')
else else
DOMAIN=${DomainName} DOMAIN=${DomainName}
fi fi
@ -1217,49 +1216,68 @@ Resources:
- Key: Name - Key: Name
Value: !Ref 'AWS::StackName' Value: !Ref 'AWS::StackName'
UserData: UserData:
Fn::Base64: !Sub | Fn::Base64: !Sub
#!/bin/bash -x - |
set -eu -o pipefail #!/bin/bash -x
set -eu -o pipefail
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout # Wait for the Elastic IP: CloudFormation associates it only after the instance
# is created, and until then the instance may have another public IP (or none,
# and no Internet access)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
CURRENT_PUBLIC_IP=""
for _ in $(seq 1 120); do
CURRENT_PUBLIC_IP=$(curl -sf -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-ipv4 || true)
if [[ "$CURRENT_PUBLIC_IP" == "${ExpectedPublicIp}" ]]; then
break
fi
sleep 5
done
if [[ "$CURRENT_PUBLIC_IP" != "${ExpectedPublicIp}" ]]; then
echo "[OpenVidu] Elastic IP ${ExpectedPublicIp} not attached after 10 minutes"
exit 1
fi
apt-get update && apt-get install -y \ echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
python3-pip \
ec2-instance-connect
CFN_BOOTSTRAP_VERSION=2.0-39 apt-get update && apt-get install -y \
# Detect Ubuntu version and install cfn-bootstrap accordingly python3-pip \
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1) ec2-instance-connect
if [ "$UBUNTU_VERSION" -ge 24 ]; then
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
else
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
fi
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer CFN_BOOTSTRAP_VERSION=2.0-39
# Detect Ubuntu version and install cfn-bootstrap accordingly
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
if [ "$UBUNTU_VERSION" -ge 24 ]; then
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
else
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
fi
export HOME="/root" cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenviduServer
# Install OpenVidu export HOME="/root"
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Config S3 bucket # Install OpenVidu
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; } /usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
# Start OpenVidu # Config S3 bucket
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; } /usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
# Update shared secret # Start OpenVidu
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; } systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
# Launch on reboot # Update shared secret
echo "@reboot /usr/local/bin/restart.sh" | crontab /usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
# Wait for the app # Launch on reboot
/usr/local/bin/check_app_ready.sh echo "@reboot /usr/local/bin/restart.sh" | crontab
# sending the finish call # Wait for the app
cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region} /usr/local/bin/check_app_ready.sh
# sending the finish call
cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}
- ExpectedPublicIp: !If [PublicElasticIPPresent, !Ref PublicElasticIP, !Ref NewEIP]
BlockDeviceMappings: BlockDeviceMappings:
- DeviceName: /dev/sda1 - DeviceName: /dev/sda1
@ -1278,8 +1296,13 @@ Resources:
NewEIP: NewEIP:
Type: 'AWS::EC2::EIP' Type: 'AWS::EC2::EIP'
Condition: PublicElasticIPAbsent Condition: PublicElasticIPAbsent
NewEIPAssociation:
Type: 'AWS::EC2::EIPAssociation'
Condition: PublicElasticIPAbsent
Properties: Properties:
InstanceId: !Ref OpenviduServer InstanceId: !Ref OpenviduServer
AllocationId: !GetAtt NewEIP.AllocationId
IMDSv2LaunchTemplate: IMDSv2LaunchTemplate:
Type: AWS::EC2::LaunchTemplate Type: AWS::EC2::LaunchTemplate