You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform部署EC2时Bash变量无法写入Caddyfile的问题排查

问题根源与解决方案

你的问题主要由两个原因导致:

  1. Terraform对$符号的提前解析:你使用的<<-EOF是不转义的 heredoc 格式,Terraform会把脚本中的$public_ip当成自身的变量处理,而你没有定义这个Terraform变量,所以最终传递给EC2的脚本里该变量被替换为空。
  2. EIP绑定时机滞后:如果是Terraform自动关联EIP到EC2实例,user-data执行时EIP可能还未完成绑定,sleep 20的等待时间可能不足,导致curl获取的是实例的临时公网IP而非EIP(甚至获取失败)。

解决方法1:转义脚本中的$符号,避免Terraform解析

将脚本里所有的$前加上反斜杠\,让Terraform把$原封不动传递给EC2实例的shell执行,同时适当延长等待时间确保EIP绑定完成:

user_data = <<-EOF
    sudo su
    cd ~
    sleep 30
    public_ip=\$(curl -s http://checkip.amazonaws.com)
    sudo mkdir -p /var/log/caddy
    sudo touch /var/log/caddy/caddy_access.log
    echo -en "\$public_ip.nip.io { \nlog { \noutput file /var/log/caddy/caddy_access.log \n} \nreverse_proxy / localhost:3000 localhost:3001 { \nlb_policy round_robin \n}\n}" > Caddyfile
    sudo caddy start
EOF

注意:

  • 给echo的内容添加双引号,确保shell能正确解析$public_ip变量
  • 用curl -s减少冗余输出,避免干扰变量赋值
  • 新增mkdir -p确保日志目录存在,防止touch命令失败

解决方法2:直接通过Terraform传递EIP变量(更可靠)

如果是用Terraform创建并关联EIP,直接将EIP的公网地址注入到user-data中,完全避免等待和curl获取的问题:
假设你的EIP资源定义如下:

resource "aws_eip" "instance_eip" {
  instance = aws_instance.your_instance.id
  vpc      = true
}

修改user-data为:

user_data = <<-EOF
    sudo su
    cd ~
    sudo mkdir -p /var/log/caddy
    sudo touch /var/log/caddy/caddy_access.log
    echo -en "${aws_eip.instance_eip.public_ip}.nip.io { \nlog { \noutput file /var/log/caddy/caddy_access.log \n} \nreverse_proxy / localhost:3000 localhost:3001 { \nlb_policy round_robin \n}\n}" > Caddyfile
    sudo caddy start
EOF

这种方式下,Terraform会在EIP绑定完成后,将其公网IP值替换到user-data中,脚本执行时直接使用正确的EIP地址,无需等待。


额外优化建议

  • 无需先sudo su再重复使用sudo,可以直接用sudo执行所有命令,或者切换用户后去掉sudo:
    user_data = <<-EOF
        # 直接用sudo执行所有操作,避免切换用户的冗余步骤
        sleep 30
        public_ip=\$(curl -s http://checkip.amazonaws.com)
        sudo mkdir -p /var/log/caddy
        sudo touch /var/log/caddy/caddy_access.log
        sudo bash -c 'echo -en "$public_ip.nip.io { \nlog { \noutput file /var/log/caddy/caddy_access.log \n} \nreverse_proxy / localhost:3000 localhost:3001 { \nlb_policy round_robin \n}\n}" > /etc/caddy/Caddyfile'
        sudo caddy start
    EOF
    
  • 如果Caddy未预装在AMI中,建议在user-data开头添加Caddy的安装步骤,确保脚本执行完整。

内容的提问来源于stack exchange,提问作者Ahmed Rauf Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:25:16