MacOS脚本scp文件夹至Ubuntu EC2实例遇连接拒绝求助
EC2 SCP连接被拒(脚本执行失败但手动操作正常)
问题背景
我通过Bash脚本结合Terraform创建Ubuntu EC2实例后,立刻执行scp传输本地文件夹,但脚本运行时始终提示Connection refused;手动执行相同的scp命令却完全正常。已确认安全组开放22端口,文件路径和密钥均无误。
脚本代码
#!/bin/bash # This block should parse instance DNS name from terraform output terraform apply -auto-approve | tee output.txt publicdns=$(grep 'instance_dns_name = "' output.txt | cut -b 26-) public_dns_name=${publicdns%?} echo $public_dns_name # I added this to show that DNS name in variable is correct scp -v -r -i ~/dev_folder/test_task_tf/tf_key.pem ~/dev_folder/test_task_tf/docker_dir ubuntu@$public_dns_name:~/
错误输出
ec2-xx-xx-xx-xxx.eu-central-1.compute.amazonaws.com Executing: program /usr/bin/ssh host ecx-xx-xx-xx-xxx.eu-central-1.compute.amazonaws.com, user ubuntu, command sftp OpenSSH_9.0p1, LibreSSL 3.3.6 debug1: Reading configuration data /Users/maxivanov/.ssh/config debug1: Reading configuration data /etc/ssh/ssh_config debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/\* matched no files debug1: /etc/ssh/ssh_config line 54: Applying options for \* debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling debug1: Connecting to ec2-xx-xx-xx-xxx.eu-central-1.compute.amazonaws.com port 22. ssh: connect to host ec2-xx-xx-xx-xxx.eu-central-1.compute.amazonaws.com port 22: Connection refused scp: Connection closed
问题原因
核心原因:实例未完全就绪
Terraform的apply命令执行完成仅代表EC2实例的云资源创建成功,但实例内部的操作系统初始化、SSH服务(sshd)启动需要额外时间。脚本在terraform apply结束后立刻发起scp连接,此时实例的22端口还未对外开放,导致连接被拒;手动执行时你已经等待了足够时间,实例SSH服务已正常运行,因此连接成功。次要原因:DNS解析方式不可靠
用grep+cut手动解析Terraform输出的方式容易受输出格式变化(如引号转义、字符位置变动)影响,虽然当前echo显示DNS正确,但这种方式存在潜在隐患。
解决方案
1. 改用Terraform官方命令获取实例DNS
使用terraform output命令直接提取输出值,-raw参数可获取纯文本格式的结果,无需处理转义字符或截取字符串:
public_dns_name=$(terraform output -raw instance_dns_name)
2. 添加SSH就绪等待逻辑
在scp前通过循环检查实例22端口是否开放,直到端口就绪再执行传输(最多等待5分钟,每10秒检查一次):
修改后的完整脚本
#!/bin/bash # 执行Terraform创建实例 terraform apply -auto-approve # 用terraform output直接获取实例DNS public_dns_name=$(terraform output -raw instance_dns_name) echo "实例DNS:$public_dns_name" # 等待SSH端口就绪 MAX_WAIT=300 WAIT_INTERVAL=10 elapsed=0 echo "等待实例SSH端口就绪..." while ! nc -z "$public_dns_name" 22; do if [ $elapsed -ge $MAX_WAIT ]; then echo "超时:实例SSH端口未在${MAX_WAIT}秒内就绪" exit 1 fi sleep $WAIT_INTERVAL elapsed=$((elapsed + WAIT_INTERVAL)) done # 执行scp传输 scp -v -r -i ~/dev_folder/test_task_tf/tf_key.pem ~/dev_folder/test_task_tf/docker_dir ubuntu@$public_dns_name:~/
额外检查点
- 如果本地没有
nc工具,可替换循环中的检查命令为:while ! ssh -o ConnectTimeout=2 ubuntu@$public_dns_name echo "SSH ready" 2>/dev/null; do - 检查DNS变量是否包含隐藏字符:执行
echo "$public_dns_name" | od -c,确保输出无多余换行符、空格或控制字符。
内容的提问来源于stack exchange,提问作者kavo
相关产品推荐
相关产品推荐

