- 文档
- 教程
- 教育
【免费下载链接】missing-semester-cn.github.io
the CS missing semester Chinese version
远程服务器已成为现代程序员日常工作的标配:无论是部署后端服务,还是借用高算力机器跑任务,你最终都会用到 Secure Shell(SSH)。本文以本仓库(missing-semester-cn.github.io,即 MIT Missing Semester 中文版课程)中《Remote Machines》一课为骨架,系统讲解 SSH 的命令执行、密钥认证、文件复制、进程后台化、端口转发、图形转发、漫游(Mosh)、客户端/服务端配置与远程文件系统挂载,并穿插仓库中 2020 与 2026 年版本的补充内容,让读者从「能连上」进阶到「用得专业」。
SSH 与大多数命令行工具一样高度可配置,值得系统学习;本文所有命令与配置文件均可直接复制、运行,并给出了服务端与客户端的对应配置位置。
为什么需要 SSH:远程开发的核心入口
程序员使用远程服务器越来越普遍。SSH(Secure Shell)是一种加密的网络协议,它让你可以在本地终端中安全地登录远程主机,并像操作本机一样执行命令。它的价值体现在三个方面:
- 部署与运维:后端软件通常运行在云端服务器上,SSH 是接入这些机器的标准通道;
- 算力扩展:当本机算力不足时,可以通过 SSH 使用拥有更多 CPU、内存或 GPU 的远程机器;
- 统一环境:配合后文介绍的密钥、配置文件与远程文件系统,可以让「远程工作」几乎等同于「本地工作」。
仓库中 2026 年命令行环境一讲 的「远程机器」小节同样指出:SSH 连接命令形如ssh alice@server.mit.edu,即以用户alice的身份登录主机server.mit.edu,登录后获得一个你早已熟悉的 Shell 界面。这也是本文所有进阶技巧的基础。
执行远程命令:SSH 常被忽略的直接执行能力
很多人只把 SSH 当作「远程登录」工具,却忽略了它可以直接执行命令并返回结果。这一特性非常适合脚本化与自动化场景:
ssh foobar@server ls上面这条命令会在foobar用户的家目录中执行ls并打印结果,然后立即退出,不会进入交互式 Shell。
它天然支持管道,关键在于管道两端分别在哪个机器上执行:
# ls 在远程执行,grep 在本地执行:先拿到远程 ls 的输出,再在本地过滤 ssh foobar@server ls | grep PATTERN # ls 在本地执行,grep 在远程执行:把本地 ls 的输出通过 SSH 管道发给远程 grep ls | ssh foobar@server grep PATTERN第一条命令是「远程输出 + 本地过滤」,第二条是「本地输出 + 远程过滤」。2026 年版本还给出了一个更容易混淆的例子,帮助理解命令与管道的归属:
# 这里 ls 在远程执行,wc -l 在本地执行 ssh alice@server ls | wc -l # 引号包住整个管道,ls 和 wc 都在远程服务器上执行 ssh alice@server 'ls | wc -l'结论:SSH 会把 stdin 发送给远程命令,也会把远程命令的 stdout 回传本地。因此ssh可以无缝嵌入任何本地管道链。这是后续「用 SSH 传文件」(如cat localfile | ssh remote tee serverfile)的原理基础。
SSH 密钥认证:用公钥密码学替代密码
基于密钥的认证(Key-based authentication)利用公钥密码学,在不泄露私钥的前提下向服务器证明「客户端持有私钥」。这样你就不必每次登录都重新输入密码。但请牢记:私钥(例如~/.ssh/id_rsa)本质上就是你的密码,必须像保护密码一样保护它。
生成密钥对
ssh-keygen -t rsa -b 4096-t指定密钥类型(这里为 RSA),-b 4096指定 4096 位长度。如果你在生成时不设置口令(passphrase),那么任何拿到你私钥的人都能直接访问所有授权服务器,因此强烈建议设置口令,并用ssh-agent在会话期间代为保管私钥(避免每次使用都输入口令)。
2026 年版本则更推荐现代算法 Ed25519,且给出更完整的参数:
ssh-keygen -a 100 -t ed25519 -f ~/.ssh/id_ed25519-t ed25519:使用 Ed25519 椭圆曲线算法,密钥更短、更快、更安全;-a 100:指定 KDF(密钥派生函数)的迭代轮数,用于增强口令的暴力破解难度;-f ~/.ssh/id_ed25519:显式指定私钥输出路径。
如果你曾按官方指引为 GitHub 配置过 SSH 推送,那大概率已经拥有一对可用密钥。要检查私钥是否设置了口令(并验证口令正确性),可运行:
ssh-keygen -y -f /path/to/key该命令会尝试读取私钥并输出对应的公钥:若私钥设有口令,它会提示你输入;能成功输出公钥即代表口令正确、密钥可用。
部署公钥到服务器
服务器通过查看用户家目录下的.ssh/authorized_keys来决定允许哪些客户端登录。把公钥复制过去最朴素的方式是:
cat .ssh/id_dsa.pub | ssh foobar@remote 'cat >> ~/.ssh/authorized_keys'如果系统提供了ssh-copy-id(绝大多数 Linux 发行版自带),更简单的方案是:
ssh-copy-id -i .ssh/id_dsa.pub foobar@remotessh-copy-id会替你完成「追加到远程authorized_keys并设置正确权限」的全部工作。2026 年版本建议使用 Ed25519 公钥,即ssh-copy-id -i .ssh/id_ed25519 alice@remote。
通过 SSH 复制文件:ssh+tee、scp 与 rsync
文件传输是远程开发的日常。原文档给出了三种递进方案:
1. ssh + tee:最轻量的传输
利用「SSH 会把 stdin 转发给远程命令」的特性:
cat localfile | ssh remote_server tee serverfile本地cat读出文件内容,经 SSH 管道送往远程,由远程的tee写入serverfile。无需额外工具,适合偶尔传单个小文件。
2. scp:批量复制的便捷选择
当需要复制大量文件或整个目录时,Secure Copy(scp)更方便,因为它能轻松递归遍历路径:
scp path/to/local_file remote_host:path/to/remote_file例如scp -r mydir foobar@server:/home/foobar/可递归上传整个目录。
3. rsync:增量同步的进阶之选
rsync在scp之上做了关键改进:
- 增量传输:自动检测本地与远程已相同的文件,避免重复复制,传输大目录时速度优势巨大;
- 精细控制:对符号链接、权限等属性提供更细粒度的控制选项;
- 断点续传:
--partial标志可以在传输被中断后从断点继续,而不是从头再来。
rsync语法与scp类似:
rsync -avz --partial path/to/local_dir foobar@server:/path/to/remote_dir仓库 2019 年命令行环境一讲 的「rsync vs cp/scp」小节也印证了这一点:当复制大量文件、大文件或目标端已有部分数据时,rsync是巨大的改进,它会跳过已传输的文件,配合--partial可从被中断的复制中续传。需要说明的是,rsync同样支持通过~/.ssh/config中的主机别名简化命令(见下文 SSH 配置一节)。
后台运行进程:nohup、tmux/screen 与 reptyr
默认情况下,当 SSH 连接被中断时,父 Shell 的子进程会一并被杀死——这常常让长任务功亏一篑。原文档给出几种替代方案:
nohup:让进程在终端被杀后继续存活
nohup long_running_command &nohup(no hangup)使进程在终端关闭(收到 SIGHUP 信号)后继续运行。虽然有时&配合disown也能做到,但nohup是更稳妥的默认选择。2026 年版本补充了原理:nohup本质上是忽略 SIGHUP 信号的包装命令;如果进程已经启动,可以使用内建命令disown达到同样效果。
tmux / screen:面向交互式会话的终端复用器
nohup只适合「后台化」单个进程,对交互式会话并不方便。此时应使用终端复用器(terminal multiplexer),如screen或tmux:你可以随意分离(detach)和重新附着(attach)会话,即使 SSH 断开,会话仍在服务器上继续运行。
仓库 2026 年命令行环境一讲 对tmux给出了系统的对象层级说明,这里一并整理:
- Sessions(会话):独立的工作区,可包含多个 window。
tmux:启动一个新会话;tmux new -s NAME:以指定名称启动会话;tmux ls:列出所有会话;- 会话内按
<C-b> d:分离当前会话; tmux a/tmux a -t NAME:附着到最近/指定会话。
- Windows(窗口):相当于编辑器中的标签页。
<C-b> c新建窗口,<C-b> N跳转到第 N 个窗口,<C-b> p/<C-b> n切换前后窗口,<C-b> ,重命名,<C-b> w列出全部窗口。
- Panes(窗格):类似 vim 的分屏。
<C-b> "水平拆分,<C-b> %垂直拆分,<C-b> <方向键>切换窗格,<C-b> z缩放窗格,<C-b> [进入回滚复制模式。
reptyr:把已 disown 的进程重新接回终端
reptyr PID如果你已经disown了某个程序,又想把它重新挂到当前终端上,reptyr PID会抓取进程 ID 为PID的进程并附着到当前终端。这适合「进程已经在跑、但你想恢复交互」的收尾场景。
端口转发:打通远程服务的本地访问
很多软件以「监听端口」的方式提供服务。本机服务可以直接访问localhost:PORT或127.0.0.1:PORT,但远程服务器如果端口不直接暴露在公网,就需要端口转发(Port Forwarding)。它分为两种:
- 本地端口转发(Local Port Forwarding):把本地某端口与远程某端口建立隧道,访问本地端口即访问远程服务;
- 远程端口转发(Remote Port Forwarding):把远程某端口与本地某端口建立隧道,让远程机器能访问本地服务。
原文档附有两张来自 Stack Exchange 的示意图(外部链接,这里不再引用),用文字描述如下:本地转发时,数据流向为「本地端口 → SSH 隧道 → 远程端口 → 远程服务」;远程转发方向相反,为「远程端口 → SSH 隧道 → 本地端口 → 本地服务」。
最常见的场景是本地转发。例如在远程服务器上运行 Jupyter Notebook,它监听8888端口;要把该服务映射到本地9999端口:
ssh -L 9999:localhost:8888 foobar@remote_server执行后,在本机浏览器访问localhost:9999即可使用远程的 Jupyter。这里-L的完整语义是-L 本地端口:目标主机:目标端口,其中「目标主机」是相对于远程服务器而言的。
用端口转发绕过网络过滤(原文档练习中的经典用法):如果你的网络屏蔽了某些网站(例如 reddit.com),可以把请求隧道到服务器再发出:
ssh remote_server -L 80:reddit.com:80然后把/etc/hosts中把reddit.com和www.reddit.com解析到127.0.0.1,浏览器访问时流量就会经 SSH 隧道由服务器代为请求。可通过 ipinfo.io 之类的服务确认出口 IP 已变为服务器 IP。
后台化端口转发:-N表示「不执行远程命令,只做转发」,-f表示「认证成功后转入后台运行」:
ssh -N -f -L 9999:localhost:8888 foobar@remote_server这条命令会静默地在后台建立隧道,非常适合把端口转发当作常驻基础设施来使用。2026 年版本练习中还要求读者自行查证这两个标志并写出后台转发的完整命令,上文即答案。
图形转发:用 -X / -Y 运行远程 GUI 程序
有时转发端口还不够——你想在服务器上运行 GUI 程序。虽然可以借助远程桌面软件(如 RealVNC、TeamViewer)把整个桌面环境传过来,但如果只是单个 GUI 工具,SSH 自带的图形转发(Graphics Forwarding,即 X11 转发)是更轻量的选择:
# 转发图形界面(不信任模式) ssh -X foobar@server # 受信任的 X11 转发 ssh -Y foobar@server-X启用 X11 转发,-Y则是受信任模式(trusted X11 forwarding),通常用于需要访问 X 资源的程序。要让转发生效,服务端的sshd_config必须包含以下选项:
X11Forwarding yes X11DisplayOffset 10X11Forwarding yes:允许 X11 转发;X11DisplayOffset 10:指定远程 X display 的起始编号,避免与本地 display 冲突。
修改后需重启 sshd 服务生效。
漫游与弱网:Mosh(Mobile Shell)
连接远程服务器时常遇到两类痛点:一是本机休眠、关机或切换网络导致的断线;二是高延迟链路上 SSH 输入卡顿。Mosh(mobile shell)在 SSH 基础上做了三方面改进:
- 漫游(roaming):IP 地址变化后连接不中断;
- 间歇性连接(intermittent connectivity):网络暂时断开也能继续输入,恢复后自动同步;
- 智能本地回显(intelligent local echo):高延迟下输入立即回显,不再逐字符等待服务器确认。
Mosh 已收录于各主流发行版与包管理器中,安装无需 root 权限,但要求服务器上已有可用的 SSH 服务,且服务器需要开放 60000–60010 端口(这些端口不在特权端口范围内,通常默认开放)。
Mosh 的局限同样要清楚:它不支持端口转发与图形转发的漫游,如果你重度依赖-L/-X,Mosh 帮助有限。仓库 2019 年命令行环境一讲 也评价说:在慢速连接上 SSH 的延迟令人沮丧、断线后必须重连,而 Mosh 支持漫游、间歇连接和智能本地回显。2026 年版本则建议将 Mosh 视为 SSH 的补充工具,专门应对断线、休眠唤醒、网络切换与高延迟链路。
SSH 配置:客户端 ~/.ssh/config 与服务端 sshd_config
客户端配置:告别一长串参数
原文档指出,与其为常用主机创建形如alias my_server="ssh -X -i ~/.id_rsa -L 9999:localhost:8888 foobar@remote_server"的别名,不如使用~/.ssh/config,它更清晰、更强大:
Host vm User foobar HostName 172.16.174.141 Port 22 IdentityFile ~/.ssh/id_rsa RemoteForward 9999 localhost:8888 # 配置项也支持通配符 Host *.mit.edu User foobaz配置项说明:
Host:主机别名(ssh vm即连到该主机),支持*.mit.edu这类通配符匹配;User:登录用户名;HostName:真实主机名或 IP;Port:SSH 端口(默认 22);IdentityFile:使用的私钥路径;RemoteForward:远程端口转发声明(等价于命令行-R 9999:localhost:8888,即让远程的 9999 端口转发到本机的 8888)。
~/.ssh/config相比 shell 别名还有一个关键优势:scp、rsync、mosh等其他程序都能读取该文件,并把配置自动转换成对应的命令行参数。也就是说,只要在 config 中声明了Host vm,scp file vm:/path、rsync dir vm:/path、mosh vm都会自动复用同一套主机、用户、密钥与端口设置。
2026 年版本补充了一个完整示例,并强调配置文件的通用性同样适用于LocalForward:
Host vm User alice HostName 172.16.174.141 Port 2222 IdentityFile ~/.ssh/id_ed25519配置文件的隐私警示
~/.ssh/config本身属于 dotfile,纳入你自己的 dotfiles 版本管理是合理的(参见仓库中 Dotfiles 一讲 的组织方式)。但如果公开这份配置,等于向陌生人泄露:服务器地址、登录用户名、开放的端口等信息,这可能为针对性攻击提供便利。请谨慎分享。
警告:永远不要把 RSA 私钥(~/.ssh/id_rsa*)放入公开仓库!同理,Ed25519 私钥~/.ssh/id_ed25519也绝不可公开。
服务端配置:/etc/ssh/sshd_config
服务端配置通常位于/etc/ssh/sshd_config,常见的加固选项包括:
- 禁用密码认证:将
PasswordAuthentication设为no,强制使用密钥登录; - 修改 SSH 端口:更改
Port的默认值 22(对公网服务器而言,非默认端口 + 仅密钥登录能有效压制大量恶意扫描攻击); - 启用 X11 转发:设置
X11Forwarding yes; - 按用户细分配置:可通过
Match User等指令针对特定用户定制选项。
修改后需要重启 sshd 服务(如sudo systemctl restart sshd或sudo service sshd restart)才会生效。仓库 2026 年命令行环境一讲 的练习也给出了相同的加固流程:编辑sshd_config禁用PasswordAuthentication与PermitRootLogin,重启 sshd 后再验证密钥登录。
远程文件系统:用 sshfs 把远程目录挂到本地
有时你希望在本地编辑器里直接编辑远程文件。sshfs可以把远程服务器上的目录挂载到本地,之后就能像操作本地文件夹一样读写远程文件:
sshfs foobar@server:/remote/path /local/mountpoint仓库 2020 年大杂烩一讲 在讲解 FUSE(用户空间文件系统)时给出了底层原理:FUSE 允许运行在用户空间的程序实现文件系统调用并与内核接口对接,sshfs正是「将所有文件系统操作通过 SSH 转发到远程主机,由远程处理后再返回结果」的虚拟文件系统实现——文件实际存储在远程,但对本地软件而言与本地文件别无二致。
安全与最佳实践清单
综合原文档与仓库各讲,远程开发的安全底线可以归纳为:
- 私钥即密码:
~/.ssh/id_rsa、~/.ssh/id_ed25519等私钥文件必须妥善保管,绝不进入公开仓库或分享给他人; - 设置口令 + ssh-agent:生成密钥时设置 passphrase,并通过
ssh-agent管理会话,兼顾安全与便利; - 服务端加固:
PasswordAuthentication no、PermitRootLogin no,公网服务器建议改用非默认端口; - 谨慎公开配置:
~/.ssh/config会暴露服务器地址、用户名与端口信息,公开前务必评估风险; - 弱网用 Mosh,交互用 tmux,长任务用 nohup:按场景选择正确的进程保活与连接方案。
课后实战练习
原文档提供了七道循序渐进的练习,全部保留如下(部分补充了 2026 年版本的变体与答案要点):
搭建 SSH 服务端:安装一台 Linux 虚拟机并运行 SSH 服务(如 OpenSSH)。用
ip addr查看机器 IP,找到inet字段(忽略127.0.0.1,那是回环接口)。检查/生成密钥:进入
~/.ssh/检查是否已有密钥对;没有则用ssh-keygen -t rsa -b 4096(或 2026 版推荐的ssh-keygen -a 100 -t ed25519)生成。建议设置口令并使用ssh-agent。免密登录 + 服务端加固:用
ssh-copy-id把公钥复制到虚拟机,测试免密 SSH。然后编辑服务端sshd_config,把PasswordAuthentication改为禁用密码认证,并禁用PermitRootLogin(禁止 root 登录)。修改后重启 sshd 并重新验证登录。修改 SSH 端口:编辑
sshd_config更改端口号,确认仍可 SSH 登录。要点:公网服务器使用非默认端口 + 仅密钥登录,能显著减少恶意攻击。Mosh 断线恢复:在服务器/虚拟机上安装 mosh,建立连接后断开虚拟机的网卡,观察 mosh 能否正确恢复连接。
本地端口转发实战:用端口转发把被网络过滤的网站隧道到服务器。运行
ssh remote_server -L 80:reddit.com:80,在/etc/hosts中把reddit.com、www.reddit.com指向127.0.0.1,确认通过服务器访问该网站(可用 ipinfo.io 验证出口 IP 变化)。后台端口转发:查阅
ssh的-N和-f标志,解释ssh -N -f -L 9999:localhost:8888 foobar@remote_server的作用——-N只做转发不执行命令,-f认证后转入后台,二者组合即可实现常驻的后台隧道。
2026 年版本还补充了一条「Web 服务转发验证」练习:在虚拟机中运行python -m http.server 8888启动 Web 服务,本地访问http://localhost:9999确认能访问到虚拟机里的服务——这正是本地端口转发最直观的验收方式。
参考资料
原文档末尾列出的两篇经典延伸阅读(SSH Hacks与Secure Secure Shell,均为外部链接,此处不展开)可作为进阶参考。本仓库中与本主题直接相关的讲稿还有:2026 年命令行环境一讲(含远程机器与终端复用器专题)、2020 年大杂烩一讲(含 FUSE/sshfs 原理)、2019 年命令行环境一讲(含 rsync/mosh 工具对比)。各讲稿均以 Markdown 形式存放在仓库的_2019/、_2020/与_2026/目录下,讲稿页面通过 _layouts/lecture.html 渲染,读者可对照原文深入研读。
- 文档
- 教程
- 教育
【免费下载链接】missing-semester-cn.github.io
the CS missing semester Chinese version
相关推荐
SSH 密钥认证完全指南:从密码告别到 GitHub 与服务器免密登录(easy-vibe 实战)
SSH 密钥认证完全指南:从密码告别到 GitHub 与服务器免密登录(easy vibe 实战) 导读 :本指南以 easy vibe 项目开发工具库中的 S
教程文档Quick Reference 速查手册:SSH 连接、SCP 传输与密钥管理实战指南
Quick Reference 速查手册:SSH 连接、SCP 传输与密钥管理实战指南 本指南是 jaywcjlove/reference 开源速查表仓库中 d
文档知识库教程开发工具easy-vibe 开发环境实战:SSH 与密钥认证完整指南
easy vibe 开发环境实战:SSH 与密钥认证完整指南 本指南是 easy vibe 开源课程"开发工具篇"中的核心章节,系统讲解 SSH 密钥认证的原理
教程文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考