Linux学习笔记 #3 使用远程服务器

本文最后更新于:2024年5月6日 下午

在前文的基础上,介绍了远程控制 Linux 服务器的情景,以及在学习中常用的不间断会话服务。

本文大部分内容参考了清华 ZAH 同学的教程,部分参考了 刘遄 老师的《Linux 就该这么学》,菜鸟教程-Linux

远程控制服务

日常工作中,我们常常会使用远程服务器来进行开发/运维,连接远程服务器需要用到 SecureShell(SSH)。

初次连接

打开本地的终端模拟器,通过如下命令使用 SSH 连接到其他服务器:

1
$ ssh [email protected] -p 30001

在这个例子中,我们尝试以用户名 hewei 登陆服务器 server.hitsz.edu.cn。服务器可以通过服务器主机名指定(如本例),也可以使用 IP 指定(如 [email protected])。SSH 的默认端口是 22,也可以通过 -p port 制定端口。

输入上述命令后,如果成功连接,会提示输入密码,该密码就是远程服务器中对应账户的密码。

本文中由于没有其他服务器,就在本机上用 VirtualBox 创建了一个 Ubuntu 虚拟机作为服务器,获取虚拟机 IP,在主机中用终端连接。参考文章:用vbox搭建Linux服务器

注意:用本方法需要确保主机接有网线,且虚拟机配置桥接网卡与主机以太网相同。

另一种方法是用公共集群作为临时服务器,可能不支持 SSH,这时候要在远程终端手动激活 sudo service sshd start

进入服务器后,可以看到命令行左侧的提示符变成了 hewei@hewei-VirtualBox ~>,其中 ~ 代表在 /home/hewei 用户目录下,> 符号提示远程用户身份,不同服务器可能不一样。输入 logout 可退出远程服务器。

SSH 配置文件

上述连接远程服务器的命令还可以通过修改 SSH 配置文件来简化,进入主机所在的用户文件夹下的 .ssh 文件夹(SSH 密钥所在的文件夹),新建配置文件 config,添加:

1
2
3
4
5
Host training (任意别名,用于助记)
HostName 152.136.177.53 (域名/IP)
Port 30001 (端口号)
User hewei (用户名)
IdentityFile ~/.ssh/id_rsa (私钥路径,默认,可不填)

配置完文件后,我们可以使用 ssh test 这样的命令来连接服务器,有助于管理多个服务器的账户。

免登录执行

SSH 的一个经常被忽视的特性是它可以在不登录服务器的状态下直接远程执行命令,例如在配置完 config 后,使用 ssh 别名 命令:

1
$ ssh training ls /home/hewei

这步操作同样需要输入密码,但不会登录服务器,在主机环境中直接返回结果。

SSH 鉴权

使用 SSH 当然免不了基于密钥对的验证机制,我们只需要将公钥放在服务器上,每次登录时向服务器证明客户端持有对应的私钥。这样就可以避免每次登陆都输入密码了。

Git学习笔记 #3 远程仓库使用 中,同样讲述了这个问题,这里假设我们已经生成了密钥对。在本机终端下,可以通过如下命令把公钥传到服务器:

1
2
$ cat ~/.ssh/id_rsa.pub | ssh training 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
$ # 拷贝公钥,利用 ssh training 免登录操控主机,创建路径并重定向公钥到 authorized_keys

如果本机是 Linux/MacOS,支持 ssh-copy-id 命令,可以用下面这种更简单的方案:

1
$ ssh-copy-id -i ~/.ssh/id_rsa.pub training

当然,如果已经连上远程终端,也可以在远程直接操作:

1
2
3
$ mkdir -p ~/.ssh
$ vi ~/.ssh/authorized_keys # 用 vi 编辑器打开,手动复制公钥进去
$ echo "这里放你的公钥" >> ~/.ssh/authorized_keys # 这样可以不用 vi

如果服务器添加公钥后本机登录仍需要密码,则原因可能是 ~/.ssh 目录和 ~/.ssh/authorized_keys 文件的权限不对,使用以下命令即可:

1
2
$ chmod 700 ~/.ssh
$ chmod 644 ~/.ssh/authorized_keys

scp 文件传输

通常我们需要将文件的工程文件放到服务器上执行,如果采用了 MobaXterm、Xshell 这类增强终端,可以通过拖拽的方式直接实现文件互传。

但如果直接在本机终端中,可以通过如下指令:

1
2
3
4
$ # 上传文件到服务器,参数一为本地文件
$ scp test.zip training:/home/hewei/test.zip
$ # 从服务器下载文件,参数一为服务器文件
$ scp training:/home/hewei/test.zip test.zip

此外,使用 scp -r 可以上传文件夹。如果需要更高级的功能,可以考虑使用 rsync


此方法也可以用于两台服务器之间传输文件,此时服务器 A 就相当于主机,服务器 B 就相当于远程(B 的 .ssh/authorized_keys 里需要有 A 的公钥,如果没有则需要输入密码)。下面是一个基本的 scp 命令的格式,用于从一个服务器传输文件到另一个服务器:

1
scp [选项] 源文件 用户名@目标服务器:目标路径

假设你已经在服务器 1.1.1.1 上,并且你想把本地文件 example.txt 发送到服务器 2.2.2.2 上的 /home/username/ 目录,你可以使用以下命令:

1
scp -P 2222 example.txt [email protected]:/home/hewei/

这里的参数解释如下:

  • -P 2222:指定 SSH 端口号为 2222(注意是大写的 P)。
  • example.txt:是你想传输的文件名。
  • [email protected]:目标服务器的用户名和 IP 地址。
  • /home/hewei/:目标服务器上的目标路径,你想把文件放在哪里。

此外,如果目标服务器使用的是默认的 SSH 端口(22),则可以省略 -P 参数。如果你在执行命令时遇到权限问题,可能需要考虑是否有适当的读写权限或者使用 sudo

如果是首次连接到目标服务器,系统可能会要求你验证目标服务器的身份,并询问是否继续连接。此时需要输入 yes,然后输入目标服务器的用户密码,除非已经设置了 SSH 免密登录。

利用 VS Code 连接

在今年的操作系统实验课上,又学到了一招连接远程服务器的办法,不得不说 VS Code 太强大了!以下的内容需要 Remote - SSH 插件支持。

安装插件后,在 SSH TARGETS 栏选择 Add New,之后会弹出输入框,输入 初次连接命令,则会弹出提示自动设置 .ssh/config 文件!添加成功后,左侧的 SSH TARGETS 栏就会增加新的远程节点。

在该节点旁边,选中 Connect to Host in New Window 即可打开一个 VS Code 窗口,新打开的窗口会要求你选择目标机器的平台,选择 Linux,按下回车,再确定连接,输入密码,即可连接成功。观察到终端显示的提示符是 190110429@OSLabExecNode1:~$,成功!

之后,点击 VS Code 侧边栏的资源管理器,就可以直接打开远程的文件夹和文件,更方便编程和调试。此外,同样可以用 SSH 鉴权来简化输入密码的步骤,方法同上。在 VS Code 中按下 Ctrl+反引号 可以快捷打开终端。

预备知识

Vim 入门

通常我们将工程传到服务器上跑时,可能需要修改某些代码或参数,如果没有使用增强终端或者 VSCode Remote 等插件,我们就只能在 CLI 界面进行交互。

要在 CLI 界面简单地编辑⼀个文件,可用的选择大概有 vi, vim, nano 等,通常来说我们选择使用 vim。使用 vim <filename> 命令打开文件进行编辑。

刚打开文件时,vim 处于一个 Normal 模式,在 Normal 模式下按 i 进入 Insert 模式,此时就可以像其他编辑器一样对文件进行编辑。编辑后按下 ESC 键退回到 Normal 模式。

在 Normal 模式下按 : 进入 Command 模式,在这个模式下可以使用命令进行操作,常用命令有::q 退出,:w 保存,:wq 保存并退出。

软件包管理机制

大多数现代类 Unix 操作系统都提供了一个集中的软件包管理机制,以帮助用户搜索、安装和管理软件。而软件通常以包的形式存储在仓库(repository)中,对软件包的使用和管理被称为包管理。而 Linux 包的基本组成部分通常有:共享库、应用程序、服务和文档。

包管理器又称软件包管理系统,它是在电脑中自动安装、配制、卸载和升级软件包的工具组合,在各种系统软件和应用软件的安装管理中均有广泛应用。

几乎每⼀个系统发行版都有它的包管理器,Ubuntu 有 apt,Arch 有 pacman,macOS 有 Homebrew

包管理器换源

由于众所周知的原因,仓库在国内的访问速度是不佳的,往往需要更换为国内的镜像源,常见的镜像站点有清华的 Tuna,其 Ubuntu 源地址为:https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ 。

Ubuntu 的软件配置文件时 /etc/apt/sources.list,首先将系统自带的该文件备份:

1
2
$ sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
$ ls /etc/apt/source.list -lah # 查看文件权限,发现需要 root 权限

此时如果直接用 vim 打开文件,会发现无法进入 Insert 模式,于是需要用:

1
$ sudo vim /etc/apt/source.list # 用 root 身份打开文件

进入编辑器后,可以进入 Insert 慢慢删除,也可以直接在 Normal 模式下输入 ggyG 全选删除。然后将网站中的配置文件复制进去。

现在就可以使用镜像源下载软件包了,这里以下面要用的 Tmux 为例:

1
2
3
4
5
$ # 由于包管理器是在系统中,也需要 sudo 来获得 root 权限,且需要密码
$ sudo apt update # 检查已安装的软件包是否有可用的更新
$ sudo apt search tmux # 在仓库中查找是否有该源文件,可以跳过
$ sudo apt install tmux # 安装软件包
$ sudo apt remove tmux # 删除已安装软件包

从网络下载资源

如果没有 sudo 权限也想下载软件,或者想下载某些数据集时,就需要内容下载命令 wgetcurl,其中前者由系统自带,后者需要用包管理器安装 sudo apt-get install curl。两个命令的功能有所重叠,总体而言,后者更适合复杂的下载任务,具体用法如下:

  • 基础下载功能:

    1
    2
    $ curl -O https://hwcoder.top/index.html	# 大写 O,如果缺省则只会打印内容不会下载
    $ wget https://hwcoder.top/index.html # 不用参数,直接下载到当前目录
  • 下载文件并重命名(指定路径):

    1
    2
    $ curl -o rename.html https://hwcoder.top/index.html	# 小写 o
    $ wget -O rename.html https://hwcoder.top/index.html # 大写 O
  • 断点续传:

    1
    2
    $ curl -O -C https://hwcoder.top/index.html	# 大写 C
    $ wget -c https://hwcoder.top/index.html # 小写 c

其中 curl -# 还有进度条功能,支持正则表达式匹配批量下载。wget 支持递归下载,常用于打包下载整个网页。

Tmux 不间断会话服务

命令行的典型使用方式是,打开一个终端窗口(terminal window,以下简称窗口),在里面输入命令。用户与计算机的这种临时的交互,称为⼀次「会话」(session) 。

服务中断

会话的⼀个重要特点是,窗口与其中启动的进程是绑定的——打开窗口,会话开始;关闭窗口,会话结束,会话内部的进程也会随之终止,不管有没有运行结束。

因此,使用 SSH 远程控制服务时,当与远程主机的会话被关闭时,在远程主机上运行的命令也随之被中断。

如果运行某个重要的程序,中途是绝对不能关闭在本地打开的终端窗口或断开网络连接的,甚至连网速的波动都有可能导致任务中断,此时只能重新进行远程连接并重新开始任务。而我们需要在服务器上跑的东西恰恰就是比较占用资源的程序,通常需要执行较长时间,如果因为网速波动而中断就很难受。

分离会话

为了解决这个问题,会话与窗口可以「解绑」:窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候,再让会话「重新绑定」其他窗口。

Terminal Multiplexer(终端复用器,简称为 Tmux)就是一款能够实现多窗口远程控制的开源服务程序。简单来说就是为了解决网络异常中断或为了同时控制多个远程终端窗口而设计的程序。Unix 系统自带,无需安装。

远程连接服务器后,输入 tmux 进入 Tmux 窗口,窗口下方会出现绿色的一行。在 Tmux 窗口中,输入 tmux detach 命令,就会将当前会话与窗口分离

1
2
$ tmux        # 在终端窗口输入,进入 Tmux 窗口
$ tmux detach # 在 Tmux 窗口输入,退回终端窗口

上述命令执行后,就会退回到本地终端窗口,但是会话和里面的进程仍然在后台运行。此时可以输入命令查看后台正在运行的 Tmux 会话:

1
2
$ tmux list-session
$ tmux ls # 两条命令等价

会弹出 0: 1 windows (created Mon Sept 9 20:34:12 2021) 的提示信息,其中 0 表示该窗口标题(默认从 0 开始递增),此外也可以命名窗口

1
$ tmux new -s <session-name>  # 新建 Tmux 窗口并命名

接入会话

此时就算退出远程连接,会话也会保持运行,可以使用以下命令重新接入某个已存在的会话:

1
2
$ tmux attach -t 0				 # 使用会话编号
$ tmux attach -t <session-name> # 使用会话名称

杀死会话

在终端窗口中,如果要彻底杀死一个运行中的会话,需要用到以下命令:

1
2
$ tmux kill-session -t 0  			   # 使用会话编号
$ tmux kill-session -t <session-name> # 使用会话名称

当然,也可以先用 attach 命令接入会话,再按下 Ctrl+D 或者输入 exit 直接退出 Tmux 会话(注意退出与解绑不同)。

管理多窗格

有时候需要同时执行多个程序,并观察输出,就需要多个会话窗口。利用 Tmux 还可以将一个窗口切分为多个(并且独立执行会话,互不干扰)。只要使用如下命令:

1
2
3
$ tmux split-window     # 上下切割窗格
$ tmux split-window -h # 左右切割窗格
$ tmux select-pane -U / -D / -L / -R # 切换至 上/下/左/右 窗格

在工作中,通过输入命令来切换窗格难免有些麻烦,Tmux 为用户提供了一系列快捷键来执行窗格的切换:先同时按下 Ctrl+B 组合键进入控制模式,松手后:

  • 按下 % 表示划分左右两个窗格;
  • 按下 " 表示划分上下两个窗格;
  • 按下 <方向键> 表示到上下左右相邻的一个窗格;
  • 按下 x 表示关闭窗格。

Linux学习笔记 #3 使用远程服务器
https://hwcoder.top/Linux-Note-3
作者
Wei He
发布于
2021年9月11日
许可协议