1. SSH 密钥认证:告别繁琐密码登录
1.1 为什么需要密钥登录?
想象一下,每次回家不用掏钥匙开门,而是要对着一把密码锁念咒语——这就是密码登录SSH的体验。密钥登录就像是指纹识别,安全又便捷。
1.2 生成SSH密钥对
创建代码文件:generate_ssh_keys.sh
#!/bin/bash
# 设置密钥保存目录
KEY_DIR="$HOME/.ssh"
mkdir -p $KEY_DIR
# 生成ED25519密钥对(推荐,更安全更快)
echo "正在生成ED25519密钥对..."
ssh-keygen -t ed25519 -C "你的邮箱@example.com" -f "${KEY_DIR}/id_ed25519" -N ""
# 或者生成RSA密钥对(兼容老系统)
echo "正在生成RSA密钥对..."
ssh-keygen -t rsa -b 4096 -C "你的邮箱@example.com" -f "${KEY_DIR}/id_rsa" -N ""
# 设置正确的权限
chmod 700 $KEY_DIR
chmod 600 $KEY_DIR/id_ed25519
chmod 644 $KEY_DIR/id_ed25519.pub
chmod 600 $KEY_DIR/id_rsa
chmod 644 $KEY_DIR/id_rsa.pub
echo "🎉 密钥生成完成!"
echo "公钥位置: ${KEY_DIR}/id_ed25519.pub"
echo "私钥位置: ${KEY_DIR}/id_ed25519"
运行这个脚本:
chmod +x generate_ssh_keys.sh
./generate_ssh_keys.sh
1.3 部署公钥到服务器
创建代码文件:deploy_key.sh
#!/bin/bash
# 配置参数
SERVER_IP="你的服务器IP"
SERVER_USER="你的用户名"
SSH_PORT="22"
PUBLIC_KEY_FILE="$HOME/.ssh/id_ed25519.pub"
# 检查公钥文件是否存在
if [ ! -f "$PUBLIC_KEY_FILE" ]; then
echo "❌ 公钥文件不存在: $PUBLIC_KEY_FILE"
exit 1
fi
# 方法1:使用ssh-copy-id(最简单)
echo "方法1: 使用ssh-copy-id部署公钥..."
ssh-copy-id -i "$PUBLIC_KEY_FILE" -p $SSH_PORT $SERVER_USER@$SERVER_IP
# 方法2:手动部署(当ssh-copy-id不可用时)
echo "方法2: 手动部署公钥..."
ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
cat "$PUBLIC_KEY_FILE" | ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP "cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
echo "✅ 公钥部署完成!现在可以尝试无密码登录:"
echo "ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP"
1.4 配置SSH客户端简化连接
创建代码文件:~/.ssh/config
# SSH全局配置
Host *
# 连接保持,防止超时断开
ServerAliveInterval 60
ServerAliveCountMax 3
# 连接复用,加速后续连接
ControlMaster auto
ControlPath ~/.ssh/control-%r@%h:%p
ControlPersist 4h
# 压缩数据传输
Compression yes
# 加密算法优先顺序
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# 密钥交换算法优先顺序
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
# 特定服务器配置
Host myserver
HostName 你的服务器IP
Port 22
User 你的用户名
IdentityFile ~/.ssh/id_ed25519
# 禁用密码认证,只使用密钥
PasswordAuthentication no
Host internal-server
HostName 192.168.1.100
Port 22
User admin
IdentityFile ~/.ssh/id_rsa
# 跳板机配置(后面会用到)
Host jumpbox
HostName 跳板机IP
Port 22
User jumpuser
IdentityFile ~/.ssh/id_ed25519
设置配置文件权限:
chmod 600 ~/.ssh/config
2. SSH端口转发:搭建安全隧道
2.1 本地端口转发(Local Port Forwarding)
场景:访问内网中无法直接连接的服务器
创建代码文件:local_forwarding.sh
#!/bin/bash
# 本地端口转发:将本地端口映射到远程服务器
# 语法:-L [本地IP:]本地端口:目标地址:目标端口
# 示例1:转发本地端口到远程数据库
echo "正在建立本地端口转发..."
ssh -L 3306:localhost:3306 -N -f myserver
# 示例2:转发到其他内网服务器
ssh -L 8080:192.168.1.100:80 -N -f jumpbox
# 示例3:多端口转发
ssh -L 3306:localhost:3306 -L 5432:localhost:5432 -L 8080:localhost:80 -N -f myserver
# 参数说明:
# -L: 本地端口转发
# -N: 不执行远程命令,只建立隧道
# -f: 后台运行
# -v: 详细输出(调试时使用)
echo "✅ 本地端口转发已建立"
echo "🔗 本地3306端口 -> 远程数据库"
echo "🔗 本地8080端口 -> 内网Web服务"
2.2 远程端口转发(Remote Port Forwarding)
场景:从外网访问内网服务
创建代码文件:remote_forwarding.sh
#!/bin/bash
# 远程端口转发:将远程端口映射到本地服务
# 语法:-R [远程IP:]远程端口:本地地址:本地端口
# 示例1:将本地Web服务暴露到远程服务器
echo "正在建立远程端口转发..."
ssh -R 8080:localhost:80 -N -f myserver
# 示例2:将本地开发服务器暴露出去
ssh -R 3000:localhost:3000 -R 5173:localhost:5173 -N -f myserver
# 示例3:允许其他机器访问转发的端口
ssh -R 0.0.0.0:8080:localhost:80 -N -f myserver
echo "✅ 远程端口转发已建立"
echo "🔗 远程8080端口 -> 本地Web服务"
2.3 动态端口转发(SOCKS代理)
创建代码文件:socks_proxy.sh
#!/bin/bash
# 动态端口转发:创建SOCKS代理服务器
# 语法:-D [本地IP:]本地端口
# 启动SOCKS5代理
echo "正在启动SOCKS5代理..."
ssh -D 1080 -N -f myserver
# 或者使用跳板机
ssh -D 1080 -N -f jumpbox
# 浏览器配置:
# 1. Firefox: 设置 -> 网络设置 -> 手动配置代理 -> SOCKS主机: localhost, 端口: 1080
# 2. Chrome: chrome --proxy-server="socks5://localhost:1080"
echo "✅ SOCKS5代理已启动"
echo "🌐 代理地址: socks5://localhost:1080"
echo "💡 提示:配置浏览器使用该代理即可科学上网"
3. 跳板机一键登录:穿透多层网络
3.1 传统跳板机登录方式
创建代码文件:jump_host_manual.sh
#!/bin/bash
# 方法1:多次SSH连接(繁琐)
echo "方法1: 传统跳板方式..."
ssh -t jumpbox ssh internal-server
# 方法2:使用ProxyJump(SSH 7.3+ 推荐)
echo "方法2: 使用ProxyJump..."
ssh -J jumpbox internal-server
# 方法3:多级跳板
ssh -J jumpbox1,jumpbox2,jumpbox3 target-server
echo "✅ 跳板机连接测试完成"
3.2 配置SSH config实现一键登录
编辑代码文件:~/.ssh/config(追加内容)
# 跳板机配置
Host jumpbox
HostName 跳板机IP
User jumpuser
Port 22
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
# 通过跳板机访问的内网服务器
Host internal-web
HostName 192.168.1.101
User webadmin
ProxyJump jumpbox
IdentityFile ~/.ssh/id_ed25519
Host internal-db
HostName 192.168.1.102
User dbadmin
ProxyJump jumpbox
IdentityFile ~/.ssh/id_ed25519
# 多级跳板配置
Host production-server
HostName 10.0.1.100
User produser
ProxyJump jumpbox1,jumpbox2
IdentityFile ~/.ssh/id_ed25519
现在可以直接连接:
ssh internal-web # 一键登录内网Web服务器
ssh internal-db # 一键登录内网数据库
3.3 高级跳板机脚本
创建代码文件:smart_jump.sh
#!/bin/bash
# 智能跳板机脚本
# 支持自动检测网络、多路径选择、连接测试
CONFIG_FILE="$HOME/.ssh/jump_hosts.conf"
LOG_FILE="$HOME/.ssh/ssh_jump.log"
# 创建配置文件
create_config() {
cat > $CONFIG_FILE << 'EOF'
# 跳板机配置格式:
# 名称|跳板机地址|跳板机用户|目标地址|目标用户|端口|密钥文件
# 开发环境
dev-web|192.168.1.10|jumpuser|172.16.1.100|webuser|22|~/.ssh/id_ed25519
dev-db|192.168.1.10|jumpuser|172.16.1.101|dbuser|22|~/.ssh/id_ed25519
# 生产环境
prod-web|10.0.1.10|prodjump|10.0.2.100|produser|2222|~/.ssh/prod_key
prod-db|10.0.1.10|prodjump|10.0.2.101|produser|2222|~/.ssh/prod_key
EOF
echo "📝 配置文件已创建: $CONFIG_FILE"
}
# 测试连接速度
test_connection() {
local host=$1
local port=$2
echo "测试连接 $host:$port ..."
if timeout 5 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null; then
echo "✅ $host:$port 可达"
return 0
else
echo "❌ $host:$port 不可达"
return 1
fi
}
# 显示可用的跳板目标
list_targets() {
echo "🔄 可用的跳板目标:"
awk -F'|' '{printf " %s -> %s@%s:%s\n", $1, $5, $4, $6}' $CONFIG_FILE | grep -v "^#"
}
# 主连接函数
connect_via_jump() {
local target_name=$1
if [[ -z "$target_name" ]]; then
echo "❌ 请指定目标名称"
list_targets
return 1
fi
# 从配置文件中查找目标
local config_line=$(grep "^$target_name|" $CONFIG_FILE)
if [[ -z "$config_line" ]]; then
echo "❌ 未找到目标: $target_name"
list_targets
return 1
fi
# 解析配置
IFS='|' read -r name jump_host jump_user target_host target_user target_port identity_file <<< "$config_line"
# 展开路径
identity_file=$(eval echo $identity_file)
echo "🚀 连接目标: $target_name"
echo "📍 路径: 本地 -> $jump_host -> $target_host"
# 测试跳板机连接
if ! test_connection $jump_host $target_port; then
echo "❌ 跳板机不可达"
return 1
fi
# 建立连接
echo "🔗 建立SSH连接..."
ssh -i "$identity_file" -J "$jump_user@$jump_host:$target_port" "$target_user@$target_host"
# 记录日志
echo "$(date): 连接 $target_name ($target_user@$target_host)" >> $LOG_FILE
}
# 菜单界面
show_menu() {
echo "
🤖 SSH跳板机管理工具
===================
1. 显示可用目标
2. 连接跳板目标
3. 测试所有连接
4. 查看连接日志
5. 编辑配置文件
6. 退出
"
}
# 主程序
main() {
# 检查配置文件
if [[ ! -f $CONFIG_FILE ]]; then
echo "⚠️ 配置文件不存在,创建中..."
create_config
fi
while true; do
show_menu
read -p "请选择操作 [1-6]: " choice
case $choice in
1) list_targets ;;
2)
list_targets
read -p "输入目标名称: " target
connect_via_jump $target
;;
3) test_all_connections ;;
4) cat $LOG_FILE ;;
5) ${EDITOR:-vim} $CONFIG_FILE ;;
6) echo "再见!"; exit 0 ;;
*) echo "❌ 无效选择" ;;
esac
echo
read -p "按回车键继续..."
done
}
# 测试所有连接
test_all_connections() {
echo "🧪 测试所有跳板机连接..."
grep -v "^#" $CONFIG_FILE | while IFS='|' read -r name jump_host jump_user target_host target_user target_port identity_file; do
echo "测试 $name ..."
if test_connection $jump_host $target_port; then
echo "✅ $name: 跳板机可达"
else
echo "❌ $name: 跳板机不可达"
fi
done
}
# 如果直接带参数运行,则直接连接
if [[ $# -gt 0 ]]; then
connect_via_jump $1
else
main
fi
设置脚本权限并运行:
chmod +x smart_jump.sh
./smart_jump.sh
3.4 连接流程可视化
下面通过流程图展示完整的SSH跳板机连接过程:
graph TD
A[本地客户端] --> B{选择连接方式}
B --> C[直接SSH连接]
B --> D[跳板机连接]
C --> E[目标服务器]
D --> F[跳板机验证]
F --> G[密钥认证]
F --> H[密码认证]
G --> I[建立隧道]
H --> I
I --> J[内网目标服务器]
subgraph 安全隧道
I[建立隧道]
end
E --> K[连接成功]
J --> K
style A fill:#4CAF50,color:white
style E fill:#2196F3,color:white
style J fill:#2196F3,color:white
style F fill:#FF9800,color:white
style I fill:#9C27B0,color:white
style K fill:#4CAF50,color:white
4. 实战案例:完整的企业级SSH方案
4.1 批量服务器管理脚本
创建代码文件:batch_ssh_manager.sh
#!/bin/bash
# 企业级批量SSH管理脚本
# 支持批量命令执行、文件传输、健康检查
SERVER_LIST="$HOME/.ssh/server_list.conf"
BATCH_LOG="$HOME/.ssh/batch_operation.log"
# 服务器列表格式
init_server_list() {
cat > $SERVER_LIST << 'EOF'
# 服务器列表格式:
# 服务器名称|SSH连接字符串|说明|标签
# Web服务器集群
web-01|webuser@192.168.1.101:22|主要Web服务器|web,production
web-02|webuser@192.168.1.102:22|备用Web服务器|web,production
# 数据库集群
db-master|dbadmin@192.168.1.201:22|主数据库|db,production,master
db-slave|dbadmin@192.168.1.202:22|从数据库|db,production,slave
# 测试环境
test-01|tester@192.168.2.101:22|测试服务器|web,test
EOF
echo "✅ 服务器列表初始化完成: $SERVER_LIST"
}
# 执行批量命令
batch_run_command() {
local command="$1"
local filter_tag="$2"
if [[ -z "$command" ]]; then
echo "❌ 请提供要执行的命令"
return 1
fi
echo "🚀 批量执行命令: $command"
echo "🏷️ 过滤标签: ${filter_tag:-所有服务器}"
echo "=" * 50
grep -v "^#" $SERVER_LIST | while IFS='|' read -r name connection description tags; do
# 标签过滤
if [[ -n "$filter_tag" && ! "$tags" =~ "$filter_tag" ]]; then
continue
fi
echo "🖥️ 服务器: $name ($description)"
echo "🔗 连接: $connection"
echo "📝 执行: $command"
# 执行远程命令
if ssh -o ConnectTimeout=10 -o BatchMode=yes $connection "$command"; then
echo "✅ $name: 执行成功"
status="成功"
else
echo "❌ $name: 执行失败"
status="失败"
fi
# 记录日志
echo "$(date) | $name | $connection | '$command' | $status" >> $BATCH_LOG
echo "-" * 40
done
echo "📊 批量操作完成!查看日志: $BATCH_LOG"
}
# 批量文件传输
batch_file_transfer() {
local local_file="$1"
local remote_path="$2"
local mode="$3" # upload or download
local filter_tag="$4"
if [[ -z "$local_file" || -z "$remote_path" ]]; then
echo "用法: batch_file_transfer <本地文件> <远程路径> <upload|download> [标签过滤]"
return 1
fi
if [[ "$mode" == "upload" ]]; then
echo "📤 批量上传文件: $local_file -> $remote_path"
else
echo "📥 批量下载文件: $remote_path -> $local_file"
fi
grep -v "^#" $SERVER_LIST | while IFS='|' read -r name connection description tags; do
# 标签过滤
if [[ -n "$filter_tag" && ! "$tags" =~ "$filter_tag" ]]; then
continue
fi
echo "🖥️ 处理: $name"
if [[ "$mode" == "upload" ]]; then
# 上传文件
if scp -o ConnectTimeout=10 "$local_file" "$connection:$remote_path"; then
echo "✅ $name: 上传成功"
else
echo "❌ $name: 上传失败"
fi
else
# 下载文件
local local_dest="${name}_$(basename $remote_path)"
if scp -o ConnectTimeout=10 "$connection:$remote_path" "$local_dest"; then
echo "✅ $name: 下载成功 -> $local_dest"
else
echo "❌ $name: 下载失败"
fi
fi
done
}
# 服务器健康检查
server_health_check() {
local filter_tag="$1"
echo "🏥 服务器健康检查"
echo "🏷️ 过滤标签: ${filter_tag:-所有服务器}"
echo "=" * 60
grep -v "^#" $SERVER_LIST | while IFS='|' read -r name connection description tags; do
# 标签过滤
if [[ -n "$filter_tag" && ! "$tags" =~ "$filter_tag" ]]; then
continue
fi
echo "🔍 检查: $name ($description)"
echo "📊 标签: $tags"
# 检查SSH连接
if ssh -o ConnectTimeout=5 -o BatchMode=yes $connection "echo 'SSH连接正常'" &>/dev/null; then
echo "✅ SSH连接: 正常"
# 获取系统信息
echo "📈 系统状态:"
ssh -o BatchMode=yes $connection "
echo ' 🖥️ 主机名: \$(hostname)'
echo ' 💻 负载: \$(uptime | awk -F'load average:' '{print \$2}')'
echo ' 🧠 内存: \$(free -h | grep Mem | awk \"{print \\\$3\\"/\\\"\\$2}\")'
echo ' 💾 磁盘: \$(df -h / | tail -1 | awk \"{print \\\$5\\\" used (\\\"\\$3\\\"/\\\"\\$2\\\")\"})'
echo ' ⏰ 运行时间: \$(uptime -p)'
" 2>/dev/null || echo " ❌ 无法获取详细状态"
else
echo "❌ SSH连接: 失败"
fi
echo "-" * 50
done
}
# 交互式菜单
show_batch_menu() {
echo "
🔧 批量SSH管理工具
=================
1. 初始化服务器列表
2. 批量执行命令
3. 批量上传文件
4. 批量下载文件
5. 服务器健康检查
6. 查看操作日志
7. 退出
"
}
# 主函数
batch_main() {
# 检查服务器列表
if [[ ! -f $SERVER_LIST ]]; then
echo "⚠️ 服务器列表不存在"
init_server_list
fi
while true; do
show_batch_menu
read -p "请选择操作 [1-7]: " choice
case $choice in
1) init_server_list ;;
2)
read -p "输入要执行的命令: " cmd
read -p "输入标签过滤(可选): " tag
batch_run_command "$cmd" "$tag"
;;
3)
read -p "输入本地文件路径: " local_file
read -p "输入远程目标路径: " remote_path
read -p "输入标签过滤(可选): " tag
batch_file_transfer "$local_file" "$remote_path" "upload" "$tag"
;;
4)
read -p "输入远程文件路径: " remote_file
read -p "输入本地保存路径: " local_path
read -p "输入标签过滤(可选): " tag
batch_file_transfer "$local_path" "$remote_file" "download" "$tag"
;;
5)
read -p "输入标签过滤(可选): " tag
server_health_check "$tag"
;;
6)
echo "📋 操作日志:"
cat $BATCH_LOG 2>/dev/null || echo "暂无日志"
;;
7) echo "再见!"; exit 0 ;;
*) echo "❌ 无效选择" ;;
esac
echo
read -p "按回车键继续..."
done
}
# 脚本入口
if [[ $# -eq 0 ]]; then
batch_main
else
case $1 in
"run")
batch_run_command "$2" "$3"
;;
"health")
server_health_check "$2"
;;
"upload")
batch_file_transfer "$2" "$3" "upload" "$4"
;;
"download")
batch_file_transfer "$2" "$3" "download" "$4"
;;
*)
echo "用法: $0 [run|health|upload|download] [参数]"
;;
esac
fi
4.2 使用示例
# 初始化脚本
chmod +x batch_ssh_manager.sh
# 交互式使用
./batch_ssh_manager.sh
# 或者命令行直接使用
./batch_ssh_manager.sh run "df -h" web
./batch_ssh_manager.sh health production
./batch_ssh_manager.sh upload ./app.tar.gz /tmp/ web
5. 安全加固和故障排除
5.1 SSH安全配置
创建代码文件:ssh_hardening.sh
#!/bin/bash
# SSH服务端安全加固脚本
# 在服务器上运行以增强SSH安全性
SSH_CONFIG="/etc/ssh/sshd_config"
BACKUP_DIR="/etc/ssh/backup"
echo "🔒 SSH安全加固开始..."
# 备份原配置
mkdir -p $BACKUP_DIR
cp $SSH_CONFIG "$BACKUP_DIR/sshd_config.$(date +%Y%m%d_%H%M%S).bak"
# 应用安全配置
echo "正在应用安全配置..."
# 禁用密码认证(只允许密钥)
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' $SSH_CONFIG
sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' $SSH_CONFIG
# 禁用root登录
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' $SSH_CONFIG
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' $SSH_CONFIG
# 更改默认端口
sed -i 's/#Port 22/Port 2222/' $SSH_CONFIG
# 限制用户登录
echo "AllowUsers 你的用户名" >> $SSH_CONFIG
# 配置空闲超时
echo "ClientAliveInterval 300" >> $SSH_CONFIG
echo "ClientAliveCountMax 2" >> $SSH_CONFIG
# 限制最大尝试次数
echo "MaxAuthTries 3" >> $SSH_CONFIG
# 禁用不安全的认证方法
echo "KbdInteractiveAuthentication no" >> $SSH_CONFIG
echo "ChallengeResponseAuthentication no" >> $SSH_CONFIG
# 配置加密算法
echo "Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" >> $SSH_CONFIG
echo "KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256" >> $SSH_CONFIG
echo "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com" >> $SSH_CONFIG
# 重启SSH服务
echo "🔄 重启SSH服务..."
if systemctl restart sshd; then
echo "✅ SSH服务重启成功"
else
service ssh restart
echo "✅ SSH服务重启成功"
fi
echo "🔐 安全加固完成!"
echo "⚠️ 注意:现在只能使用密钥在2222端口登录"
echo "📋 新连接命令: ssh -p 2222 你的用户名@服务器IP"
5.2 常见问题排查
创建代码文件:ssh_troubleshooting.sh
#!/bin/bash
# SSH连接问题排查工具
echo "🐛 SSH故障排查工具"
echo "=================="
check_ssh_connection() {
local host=$1
local port=${2:-22}
echo "🔍 检查SSH连接到 $host:$port"
# 检查网络连通性
echo "1. 检查网络连通性..."
if ping -c 3 -W 2 $host &>/dev/null; then
echo " ✅ 网络连通性: 正常"
else
echo " ❌ 网络连通性: 失败"
return 1
fi
# 检查端口是否开放
echo "2. 检查SSH端口..."
if nc -z -w 5 $host $port; then
echo " ✅ SSH端口 $port: 开放"
else
echo " ❌ SSH端口 $port: 关闭或阻塞"
return 1
fi
# 检查SSH版本
echo "3. 检查SSH协议版本..."
local ssh_version=$(ssh -o ConnectTimeout=5 -V 2>&1 | head -1)
echo " 📋 SSH客户端版本: $ssh_version"
# 详细连接测试
echo "4. 详细连接测试..."
ssh -o ConnectTimeout=10 -o BatchMode=yes -v -p $port $host exit 2>&1 | grep -E "(debug|Connection|Authenticat)" | tail -10
echo "✅ 基本检查完成"
}
# 检查密钥权限
check_key_permissions() {
echo "🔑 检查SSH密钥权限..."
local key_files=(
"$HOME/.ssh/id_rsa"
"$HOME/.ssh/id_ed25519"
"$HOME/.ssh/config"
)
for key_file in "${key_files[@]}"; do
if [[ -f "$key_file" ]]; then
local permissions=$(stat -c "%a %U:%G" "$key_file")
echo " $key_file: $permissions"
# 检查私钥权限
if [[ "$key_file" =~ id_rsa$|id_ed25519$ ]] && [[ "$permissions" != 600* ]]; then
echo " ⚠️ 警告: 私钥权限应为600,正在修复..."
chmod 600 "$key_file"
fi
fi
done
}
# 检查SSH代理
check_ssh_agent() {
echo "🕵️ 检查SSH代理..."
if [[ -n "$SSH_AUTH_SOCK" ]]; then
echo " ✅ SSH代理运行中: $SSH_AUTH_SOCK"
ssh-add -l
else
echo " ❌ SSH代理未运行"
echo " 💡 建议启动: eval \$(ssh-agent) && ssh-add"
fi
}
# 主函数
main() {
local host=$1
local port=$2
echo "开始SSH故障排查..."
echo
check_ssh_agent
echo
check_key_permissions
echo
if [[ -n "$host" ]]; then
check_ssh_connection "$host" "$port"
else
echo "💡 使用方法: $0 <主机> [端口]"
echo "💡 示例: $0 example.com 22"
fi
}
main "$@"
总结
通过本教程,你已经掌握了SSH的高级用法:
- 🔑 密钥认证 - 告别密码,拥抱安全
- 🔄 端口转发 - 搭建安全隧道,穿透网络限制
- 🚀 跳板机登录 - 一键连接内网服务器
- 🔧 批量管理 - 高效管理服务器集群
- 🔒 安全加固 - 保护你的SSH服务
这些技能就像给你的服务器管理装备上了瑞士军刀,无论是日常运维还是紧急故障处理,都能游刃有余。记住,熟练使用SSH是每个运维工程师和开发者的必备技能!
遇到问题时,记得使用故障排查工具,或者回头查看对应的配置步骤。Happy SSHing! 🎉