美文网首页
2023-07-21 服务器外网连接技巧

2023-07-21 服务器外网连接技巧

作者: 麦冬花儿 | 来源:发表于2023-08-12 09:57 被阅读0次

    首先要有公网的服务器
    ssh -f -N -R 52813:lcoalhost:22 train@chenlianfu.com

    [train@MiWiFi-R3P-srv ~]$ cat sshToAliyun.pl 
    #!/usr/bin/perl
    use strict;
    use Getopt::Long;
    
    my $usage = <<USAGE;
    Usage:
        $0 [options]
    
        本程序用于创建一个到Aliyun服务器(chenlianfu.com)的反向隧道。必须使用普通用户运行本程序,即可持续维持该隧道。本程序可以随意多次运行,对前面运行的程序没有影响,对隧道的稳定连接没有影响。
        特别注意:为了保护Aliyun服务器服务器的安全,一定要使用自己的用户,且该用户名一定要是自己姓名的全拼,和文件www.chenlianfu.com/public/information/Ports_for_sshToAliyun.txt中的用户名一致。否则,即使成功运行该程序后,陈连福也会不定期查看ssh授权文件并根据用户姓名进行清理,或定期自动清理名单中不存在的用户,导致使用Aliyun服务器进行的端口影射失效。所以,欲使用本程序,一定要联系陈连福报备端口信息。
    
        程序运行原理:(1)首先,生成一对ssh密钥,然后将公钥写入到aliyun服务器,第一次运行本程序时,该过程可能需要输入密码。(2)生成一个创建反向隧道的perl程序。该perl程序先检测能否通过Aliyun服务器的指定端口连接到服务器自身。检测方法是通过ssh命令使用Aliyun的指定端口登录到本服务器的当前用户。由于一般服务器禁止root用户远程登录,所以当前使用本程序的用户不能是root,否则该检测会失败。若检测不能通过aliyun服务器连接到服务器自身,则重新创建反向隧道。(3)使用crontab例行程序方法每隔一段时间(半个小时)就会自动运行该perl程序,从而保持反向隧道的连接。
    
        --user_name <string>    default: train
        设置使用的Aliyun服务器上的用户。
    
        --sshToAliyun <string>    default: \$HOME/.sshToAliyun
        程序生成一个perl程序文件,用于构建到Aliyun服务器的反向隧道。设置该文件的路径和名称。
    
        --port_aliyun <int>    default: None
        设置反向隧道所使用的端口号。该端口时映射到Aliyun服务器,在Aliyun服务器上占用的端口。该端口号理论上是可以随便填写的,推荐使用52000-53000区段的端口,这些端口已经在Aliyun服务器(chenlianfu.com)上开放了。使用这些端口,则可以输入一个ssh命令直接登陆内网服务器。若填写其它端口号,则需要先登录到aliyun服务器,然后再从aliyun服务器登录到内网服务器,需要输入两次ssh命令。为了防止和他人发生端口冲突,请联系陈连福报备端口号。陈连福会将各位老师的用户名和端口号信息填写在网址文件www.chenlianfu.com/public/information/Ports_for_sshToAliyun.txt中。
    
        --port_intranet <int>    default: 22
        设置内网服务器的ssh登录所使用的端口。
    
        --aliyun_noPasswd_To_intranet    default: None
        设置该参数,则会将Aliyun的公钥上传到内网服务器,可以从Aliyun服务器直接无密码登录内网服务器。为了内网服务器的安全,不推荐使用该参数。
    
        --help
        打印帮助信息。
    
    USAGE
    
    my ($user_name, $sshToAliyun, $help, $port_aliyun, $port_intranet, $aliyun_noPasswd_To_intranet);
    GetOptions (
        "user_name:s" => \$user_name,
        "sshToAliyun:s" => \$sshToAliyun,
        "help!" => \$help,
        "port_aliyun:i" => \$port_aliyun,
        "port_intranet:i" => \$port_intranet,
        "aliyun_noPasswd_To_intranet!" => \$aliyun_noPasswd_To_intranet,
    );
    if ($help){die $usage}
    unless ($port_aliyun) {die "\nThe parameter --port_aliyun was required!\n\n$usage";}
    
    my $home = `echo \$HOME`;
    my $whoami = `whoami`;
    chomp($home);
    chomp($whoami);
    $sshToAliyun ||= "$home/.sshToAliyun";
    $user_name ||= "train";
    $port_intranet ||= 22;
    
    # 创建一对rsa密钥,并和Aliyun服务器交换密钥
    my $cmdString;
    unless (-e "$home/.ssh/id_rsa") {
        $cmdString = 'ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa';
        print STDERR "CMD: $cmdString\n";
        system($cmdString);
        $cmdString = 'cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys';
        print STDERR "CMD: $cmdString\n";
        system($cmdString);
    }
    
    $cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com cd";
    print STDERR "CMD: $cmdString\n";
    
    if ( system($cmdString) == 0 ) {
        print STDERR "The intranet server can connect to Aliyun server without password.\n";
    }
    else {
        $cmdString = "ssh-copy-id -i ~/.ssh/id_rsa.pub $user_name\@chenlianfu.com";
        print STDERR "CMD: $cmdString\n";
        system($cmdString);
    
        if ($aliyun_noPasswd_To_intranet) {
            $cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com 'cat ~/.ssh/id_rsa.pub' >> ~/.ssh/authorized_keys";
            print STDERR "CMD: $cmdString\n";
            system($cmdString);
        }
    
        $cmdString = "ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 $user_name\@chenlianfu.com cd";
        print STDERR "CMD: $cmdString\n";
    
        if ( system($cmdString) == 0 ) {
            print STDERR "The intranet server can connect to Aliyun server without password.\n";
        }
        else {
            die "Error: The intranet server can not connect to Aliyun server without password!\n";
        }
    }
    
    # 生成创建反向隧道的perl程序
    open OUT, ">", $sshToAliyun or die "Can not create file $sshToAliyun, $!";
    my $out ='#!/usr/bin/perl
    use strict;
    
    unlink "/tmp/sshOKOKOKssh" if -e "/tmp/sshOKOKOKssh";
    my $cmdString = \'ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 -p ' . "$port_aliyun $whoami" . '@chenlianfu.com "touch /tmp/sshOKOKOKssh"\';
    #print STDERR "CMD: $cmdString\n";
    system($cmdString);
    
    if (-e "/tmp/sshOKOKOKssh") {
        unlink "/tmp/sshOKOKOKssh";
        #print STDERR "反向隧道正常联通中...\n";
    }
    else {
        #print STDERR "反向隧道不能联通...\n";
        $cmdString = \'/usr/bin/ps -aux | grep -P "ssh.*-f -N -R ' . $port_aliyun . ':"\';
        #print STDERR "CMD: $cmdString\n";
        my $ssh_out = `$cmdString`;
        foreach (split /\n/, $ssh_out) {
            @_ = split /\s+/;
            $cmdString = "kill -s 9 $_[1]";
            #print STDERR "CMD: $cmdString\n";
            system($cmdString);
        }
        $cmdString = \'ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no -o ConnectTimeout=10 -f -N -R ' . $port_aliyun . ':localhost:' . "$port_intranet $user_name" . '@chenlianfu.com\';
        #print STDERR "CMD: $cmdString\n";
        if ( system($cmdString) == 0 ) {
            #print STDERR "反向隧道重建成功...\n";
        }
        else {
            die "反向隧道重建失败...请检测内网服务器是否联网,再检测Aliyun服务器是否联网...\n";
        }
    }';
    print OUT "$out\n";
    close OUT;
    print STDERR "The perl script $sshToAliyun was created.\n";
    
    $cmdString = "chmod 755 $sshToAliyun";
    print STDERR "CMD: $cmdString\n";
    system($cmdString);
    $cmdString = $sshToAliyun;
    print STDERR "CMD: $cmdString\n";
    system($cmdString);
    
    open OUT, ">", "$home/.crontab" or die "Can not create file $home/.crontab\n";
    $cmdString = 'crontab -l';
    my $cron = `$cmdString`;
    my %cron;
    foreach (split /\n/, $cron) {
        $cron{$_} = 1 if $_;
    }
    $cron{"1\t*\t*\t*\t*\t$sshToAliyun"} = 1;
    $cron{"31\t*\t*\t*\t*\t$sshToAliyun"} = 1;
    foreach (sort keys %cron) {
        print OUT "$_\n";
    }
    close OUT;
    $cmdString = "crontab $home/.crontab";
    print STDERR "CMD: $cmdString\n";
    system($cmdString);
    

    相关文章

      网友评论

          本文标题:2023-07-21 服务器外网连接技巧

          本文链接:https://www.haomeiwen.com/subject/ucmzudtx.html