linux的ssh隧道创建(进行数据库连接)

1.通过跳板机建立加密隧道(SSH 端口转发)

  • 本地端口转发(适用于前置机访问数据库)

在前置机上通过 SSH 连接跳板机,将本地端口(如本地 3307)转发到数据库端口(如远程 3306)。

命令示例:

ssh-L 本地端口:数据库IP:数据库端口 跳板机用户@跳板机IP
#例:ssh -L 3307:192.168.1.100:3306 user@jump-host.com

之后,前置机可通过1ocalhost:3307访问数据库,数据经 SSH 隧道加密传输。

  • 动态端口转发(适用于多端口或代理场景)
ssh-D 本地代理端口 跳板机用户@跳板机IP

配合代理工具(如 Proxychains),可让前置机的应用通过跳板机访问数据库及其他服务。

2.实战案例:

2.1使用密钥文件进行跳转

数据库需要走ssh隧道:

业务中台中间件
mysql
101.10.20.9:336


# 后台运行可以这样写,弊端是会自动挂,只能临时使用
nohup ssh -N -L 192.168.25.202:3307:101.10.20.9:336  root@192.152.17.181 -i /root/.ssh/private-key & 

为解决这个问题编写脚本:ssh_tunnel_monitor.sh

此脚本可监控ssh隧道状态,若ssh隧道关闭,可以自动重启。

内容如下:

#!/bin/bash

# SSH隧道监控和自动重启脚本(优化版)
# 功能:自动监控隧道状态,断开时强制终止旧进程并重启,避免进程堆积

# --------------------- 配置区域 --------------------- #
LOG_FILE="/root/logs/ssh_tunnel_monitor/ssh_tunnel_monitor.log"         # 日志文件路径
PRIVATE_KEY="/root/.ssh/private-key"               # 私钥路径
SSH_USER="root"                                    # SSH用户名
SSH_SERVER="192.152.17.181"                         # SSH服务器IP
LOCAL_IP="192.168.25.202"                          # 本地绑定IP

# 隧道配置:格式为 "本地端口:目标主机:目标端口 描述"
TUNNELS=(
    "3307:101.10.20.9:336 MySQL数据库隧道"
)

# --------------------- 工具函数 --------------------- #
# 日志记录函数
log() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local message="$timestamp [$(basename "$0")] $1"
    echo "$message"
    echo "$message" >> "$LOG_FILE"
}

# 检查依赖工具
check_dependencies() {
    local required_commands=("ssh" "pgrep" "netstat" "kill")
    for cmd in "${required_commands[@]}"; do
        if ! command -v "$cmd" &> /dev/null; then
            log "错误: 缺少依赖工具 '$cmd'"
            exit 1
        fi
    done
}

# 强制终止旧隧道进程
kill_old_tunnel() {
    local port=$1
    local process_pattern="ssh -N -L $LOCAL_IP:$port:"
    local pids=$(pgrep -f "$process_pattern")
    
    if [[ -n "$pids" ]]; then
        log "发现旧隧道进程 ($port): $pids,正在强制终止..."
        kill -9 $pids &> /dev/null
        sleep 1  # 等待进程终止
    fi
}

# 启动隧道(带旧进程清理)
start_tunnel() {
    local tunnel_info=$1
    local description=$2
    local port=$(echo "$tunnel_info" | cut -d: -f1)
    local remote_host=$(echo "$tunnel_info" | cut -d: -f2)
    local remote_port=$(echo "$tunnel_info" | cut -d: -f3)
    
    # 清理旧进程
    kill_old_tunnel "$port"
    
    # 启动新隧道
    log "启动隧道: $description ($LOCAL_IP:$port -> $remote_host:$remote_port)"
    nohup ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 \
        -N -L "$LOCAL_IP:$port:$remote_host:$remote_port" \
        "$SSH_USER@$SSH_SERVER" -i "$PRIVATE_KEY" >/dev/null 2>&1 &
    
    # 检查启动结果
    sleep 3
    local new_pid=$(pgrep -f "ssh -N -L $LOCAL_IP:$port:" | head -n1)
    if [[ -n "$new_pid" ]]; then
        log "隧道启动成功,PID: $new_pid"
    else
        log "错误: 隧道 $description 启动失败"
    fi
}

# 检查隧道状态(通过端口监听判断)
is_tunnel_alive() {
    local port=$1
    netstat -tulpn | grep -q ":$port "
    return $?
}

# --------------------- 核心逻辑 --------------------- #
# 监控主循环
monitor_loop() {
    log "------------------------- 监控循环开始 -------------------------"
    for tunnel in "${TUNNELS[@]}"; do
        local tunnel_info=$(echo "$tunnel" | awk '{print $1}')
        local description=$(echo "$tunnel" | awk '{$1=""; print substr($0, 2)}')
        local port=$(echo "$tunnel_info" | cut -d: -f1)
        
        if ! is_tunnel_alive "$port"; then
            log "警告: 隧道 $description 断开,触发重启..."
            start_tunnel "$tunnel_info" "$description"
        else
            local pid=$(pgrep -f "ssh -N -L $LOCAL_IP:$port:" | head -n1)
            log "隧道 $description 运行正常,PID: $pid"
        fi
    done
    log "------------------------- 监控循环结束 -------------------------\n"
    sleep 30  # 检查间隔(秒)
}

# --------------------- 命令行接口 --------------------- #
main() {
    check_dependencies
    
    # 创建日志文件(若不存在)
    if [[ ! -f "$LOG_FILE" ]]; then
        touch "$LOG_FILE"
        chmod 600 "$LOG_FILE"
        log "创建日志文件: $LOG_FILE"
    fi
    
    case "$1" in
        start)
            if pgrep -f "$0 monitor" &> /dev/null; then
                log "错误: 监控进程已在运行"
                exit 1
            fi
            
            # 初始化清理所有旧隧道
            log "初始化: 清理所有旧隧道进程..."
            for tunnel in "${TUNNELS[@]}"; do
                kill_old_tunnel $(echo "$tunnel" | cut -d: -f1)
            done
            
            # 启动监控守护进程
            nohup "$0" monitor >/dev/null 2>&1 &
            log "监控守护进程启动,PID: $!"
            ;;
        
        monitor)
            log "监控进程启动,开始循环检查隧道状态..."
            while true; do
                monitor_loop
            done
            ;;
        
        stop)
            log "停止所有隧道和监控进程..."
            # 终止隧道进程
            for tunnel in "${TUNNELS[@]}"; do
                local port=$(echo "$tunnel" | cut -d: -f1)
                kill_old_tunnel "$port"
            done
            
            # 终止监控进程
            local monitor_pid=$(pgrep -f "$0 monitor")
            if [[ -n "$monitor_pid" ]]; then
                kill "$monitor_pid"
                log "监控进程已终止,PID: $monitor_pid"
            else
                log "监控进程未运行"
            fi
            ;;
        
        status)
            log "------------------------- 隧道状态 -------------------------"
            for tunnel in "${TUNNELS[@]}"; do
                local tunnel_info=$(echo "$tunnel" | awk '{print $1}')
                local description=$(echo "$tunnel" | awk '{$1=""; print substr($0, 2)}')
                local port=$(echo "$tunnel_info" | cut -d: -f1)
                
                if is_tunnel_alive "$port"; then
                    local pid=$(pgrep -f "ssh -N -L $LOCAL_IP:$port:" | head -n1)
                    echo -e "✓ $description ($LOCAL_IP:$port) - 运行中,PID: $pid"
                else
                    echo -e "✗ $description ($LOCAL_IP:$port) - 未运行"
                fi
            done
            
            # 检查监控进程状态
            local monitor_pid=$(pgrep -f "$0 monitor")
            if [[ -n "$monitor_pid" ]]; then
                echo -e "\n✓ 监控进程 - 运行中,PID: $monitor_pid"
            else
                echo -e "\n✗ 监控进程 - 未运行"
            fi
            ;;
        
        restart)
            "$0" stop
            sleep 2
            "$0" start
            ;;
        
        *)
            echo "用法: $0 {start|stop|restart|status}"
            exit 1
            ;;
    esac
}

# 执行主函数
main "${@:-status}"
  1. 赋予执行权限:chmod +x ssh_tunnel_monitor.sh
  2. 启动监控:./ssh_tunnel_monitor.sh start
  3. 检查状态:./ssh_tunnel_monitor.sh status
  4. 停止监控:./ssh_tunnel_monitor.sh stop

测试:

查看ssh进程: ps -ef | grep ssh

杀死ssh进程:kill -9进程号

查看ssh进程: ps -ef | grep ssh

  • 如果还连接不上,请查看防火墙状态
systemctl status firewalld
  • 添加规则
firewall-cmd --add-port=端口号/tcp --permanent

firewall-cmd --reload 生效

  • 查看规则
firewall-cmd --list-all

2.2使用账号密码进行ssh跳转

sshpass_tunnel_monitor.sh

#!/bin/bash

# SSH隧道监控和自动重启脚本(优化版)
# 功能:自动监控隧道状态,断开时强制终止旧进程并重启,避免进程堆积

# --------------------- 配置区域 --------------------- #
LOG_FILE="/root/logs/ssh_tunnel_monitor/ssh_tunnel_monitor.log"         # 日志文件路径
SSH_PASSWORD='your_password' # SSH 密码
SSH_USER="root"                                    # SSH用户名
SSH_SERVER="xxx.xxx.xx.xx"                         # SSH服务器IP
LOCAL_IP="192.168.25.202"                          # 本地绑定IP

# 隧道配置:格式为 "本地端口:目标主机:目标端口 描述"
TUNNELS=(
    "3307:ip:port MySQL数据库隧道"
)

# --------------------- 工具函数 --------------------- #
# 日志记录函数
log() {
"sshpass_tunnel_monitor.sh" 200L, 6701B                                                                                                                     1,1          顶端
            if [[ -n "$monitor_pid" ]]; then
                echo -e "\n✓ 监控进程 - 运行中,PID: $monitor_pid"
            else
                echo -e "\n✗ 监控进程 - 未运行"
            fi
            ;;
        
        restart)
            "$0" stop                              
            sleep 2
            "$0" start
            ;;
        
        *)
            echo "用法: $0 {start|stop|restart|status}"
            exit 1
            ;;
    esac
}

# 执行主函数
main "${@:-status}"
"sshpass_tunnel_monitor.sh" 200L, 6701B                                                                                                                     200,1        底端
            local monitor_pid=$(pgrep -f "$0 monitor")
            if [[ -n "$monitor_pid" ]]; then
                echo -e "\n✓ 监控进程 - 运行中,PID: $monitor_pid"
            else
                echo -e "\n✗ 监控进程 - 未运行"
            fi
            ;;

        restart)
            "$0" stop
            sleep 2
            "$0" start
            ;;

        *)
            echo "用法: $0 {start|stop|restart|status}"
            exit 1
            ;;
    esac
}

# 执行主函数
main "${@:-status}"
                                                                                                                                                            200,1        底端
            log "------------------------- 隧道状态 -------------------------"
            for tunnel in "${TUNNELS[@]}"; do
                local tunnel_info=$(echo "$tunnel" | awk '{print $1}')
                local description=$(echo "$tunnel" | awk '{$1=""; print substr($0, 2)}')
                local port=$(echo "$tunnel_info" | cut -d: -f1)

                if is_tunnel_alive "$port"; then
                    local pid=$(pgrep -f "ssh -N -L $LOCAL_IP:$port:" | head -n1)
                    echo -e "✓ $description ($LOCAL_IP:$port) - 运行中,PID: $pid"
                else
                    echo -e "✗ $description ($LOCAL_IP:$port) - 未运行"
                fi
            done

            # 检查监控进程状态
            local monitor_pid=$(pgrep -f "$0 monitor")
            if [[ -n "$monitor_pid" ]]; then
                echo -e "\n✓ 监控进程 - 运行中,PID: $monitor_pid"
            else
                echo -e "\n✗ 监控进程 - 未运行"
            fi
            ;;

        restart)
            "$0" stop
            sleep 2
            "$0" start
            ;;

        *)
            echo "用法: $0 {start|stop|restart|status}"
            exit 1
            ;;
    esac
}

# 执行主函数
main "${@:-status}"
                                                                                                                                                            200,1        底端

        status)
            log "------------------------- 隧道状态 -------------------------"
            for tunnel in "${TUNNELS[@]}"; do
                local tunnel_info=$(echo "$tunnel" | awk '{print $1}')
                local description=$(echo "$tunnel" | awk '{$1=""; print substr($0, 2)}')
                local port=$(echo "$tunnel_info" | cut -d: -f1)

                if is_tunnel_alive "$port"; then
                    local pid=$(pgrep -f "ssh -N -L $LOCAL_IP:$port:" | head -n1)
                    echo -e "✓ $description ($LOCAL_IP:$port) - 运行中,PID: $pid"
                else
                    echo -e "✗ $description ($LOCAL_IP:$port) - 未运行"
                fi
            done

            # 检查监控进程状态
            local monitor_pid=$(pgrep -f "$0 monitor")
            if [[ -n "$monitor_pid" ]]; then
                echo -e "\n✓ 监控进程 - 运行中,PID: $monitor_pid"
            else
                echo -e "\n✗ 监控进程 - 未运行"
            fi
            ;;

        restart)
            "$0" stop
            sleep 2
            "$0" start
            ;;

        *)
            echo "用法: $0 {start|stop|restart|status}"
            exit 1
            ;;
    esac
}

# 执行主函数
main "${@:-status}"


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怕被各位卷死

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值