Tech Learning · 06

服务器与 SSH:
远程连接的艺术

理解服务器是什么、如何通过 SSH 安全连接、密钥认证的原理,以及实用的服务器管理技巧。

约 18 分钟 基础入门 2026
如果这篇文章对你有帮助,点个赞让我知道吧 👋
感谢你的支持!🎉

服务器是什么

服务器(Server)本质上就是一台一直开着的电脑,专门用来提供服务。它可能在云端机房、也可能在你家里的角落,但核心特点是:

你访问的每个网站、每个 App 背后,都有服务器在响应你的请求。

个人电脑 服务器
运行时间 按需开关机 持续运行
访问方式 本地操作(键盘、鼠标、屏幕) 远程连接(SSH、RDP)
主要用途 开发、办公、娱乐 托管服务、处理请求、存储数据
操作系统 Windows / macOS / Linux 主要是 Linux(Ubuntu、CentOS 等)

为什么需要服务器

作为开发者,你会在这些场景下用到服务器:

云服务器 vs 物理服务器:现在大部分人用的是云服务器(VPS),比如阿里云、腾讯云、AWS。它们本质是虚拟机,按需付费,几分钟就能开通。物理服务器需要自己买硬件、配网络,成本高,适合企业或特殊需求。

SSH 是什么

SSH(Secure Shell)是一种加密的网络协议,用来安全地远程登录和操作服务器。

想象一下:你的服务器在云端机房,没有屏幕、键盘、鼠标。怎么操作它?通过 SSH,你在自己电脑的终端里输入命令,SSH 把命令加密传输到服务器,服务器执行后把结果传回来——就像你坐在服务器前操作一样。

🔐

为什么要加密?因为你的命令、密码、数据都在互联网上传输。如果不加密,中间任何节点都能看到你的密码。SSH 用强加密算法保护这些信息,即使被截获也无法破解。

SSH 基础连接

密码认证(最简单的方式)

假设你有一台服务器:

在你的终端(WSL / Linux / macOS)里运行:

$ ssh ubuntu@123.45.67.89

命令格式解释:

  • ssh:SSH 客户端程序
  • ubuntu:服务器上的用户名
  • @:分隔符
  • 123.45.67.89:服务器的 IP 地址(也可以是域名)

第一次连接会提示:

The authenticity of host '123.45.67.89 (123.45.67.89)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

输入 yes 并回车,然后输入密码(输入时不会显示任何字符,这是正常的),回车后就登录成功了。

第一次连接时发生了什么

SSH 会把服务器的指纹(fingerprint)保存到你本地的 ~/.ssh/known_hosts 文件里。下次连接时,如果指纹变了,SSH 会警告你(可能是中间人攻击)。

安全提示:如果你不是第一次连接,却看到指纹变化的警告,不要继续连接。可能是服务器被重装了,也可能有人在中间劫持你的连接。联系服务器管理员确认。

SSH 密钥认证

密码认证虽然简单,但有几个问题:

密钥认证是更安全、更方便的方式。它的原理是非对称加密

密钥对的概念

你会生成一对密钥:

登录时的流程:

1

你发起连接,服务器发送一个随机挑战

2

你的电脑用私钥对挑战进行签名

3

服务器用你的公钥验证签名

4

验证通过,允许登录——全程不传输密码

🔑

为什么安全?因为私钥从不离开你的电脑,即使有人截获了通信内容,也无法伪造签名。只有持有私钥的人才能通过验证。

生成密钥对

在你的本地电脑(不是服务器)上运行:

# 生成 ED25519 密钥对(推荐,更安全更快)
$ ssh-keygen -t ed25519 -C "your_email@example.com"

# 如果系统不支持 ED25519,用 RSA(传统方式)
$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

参数说明:

  • -t ed25519:指定密钥类型为 ED25519(现代、高效、安全)
  • -t rsa -b 4096:RSA 类型,4096 位长度(传统但兼容性好)
  • -C "email":添加注释,方便识别这个密钥是谁的

运行后会提示:

Enter file in which to save the key (/home/ubuntu/.ssh/id_ed25519):

直接回车使用默认路径,或者输入自定义路径(比如 ~/.ssh/my_server_key)。

Enter passphrase (empty for no passphrase):

这是给私钥加密的密码。建议设置,这样即使私钥文件被盗,没有这个密码也用不了。如果不想设置,直接回车留空。

生成完成后,~/.ssh/ 目录下会有两个文件:

~/.ssh/id_ed25519       # 私钥,保密!
~/.ssh/id_ed25519.pub   # 公钥,可以公开

上传公钥到服务器

有两种方法:

方法一:使用 ssh-copy-id(推荐)

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@123.45.67.89

输入服务器密码后,公钥会自动添加到服务器的 ~/.ssh/authorized_keys 文件里。

参数说明:-i ~/.ssh/id_ed25519.pub 指定要上传的公钥文件路径。如果不指定,会使用默认的 ~/.ssh/id_rsa.pub

方法二:手动复制(如果 ssh-copy-id 不可用)

1

查看公钥内容:

$ cat ~/.ssh/id_ed25519.pub

复制输出的整行内容(以 ssh-ed25519 开头)

2

登录服务器(用密码):

$ ssh ubuntu@123.45.67.89
3

在服务器上创建 SSH 目录(如果不存在):

$ mkdir -p ~/.ssh
$ chmod 700 ~/.ssh
4

把公钥追加到 authorized_keys:

$ echo "你复制的公钥内容" >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys

权限很重要!~/.ssh 必须是 700(只有所有者可读写执行),authorized_keys 必须是 600(只有所有者可读写)。权限不对,SSH 会拒绝密钥认证。

测试密钥登录

退出服务器(exitCtrl+D),然后重新连接:

$ ssh ubuntu@123.45.67.89

如果配置正确,应该不再要求输入服务器密码,直接登录成功。如果你给私钥设置了 passphrase,会要求输入私钥密码(这是本地验证,不是服务器密码)。

SSH 配置文件

每次都输入 ssh ubuntu@123.45.67.89 很麻烦,尤其是有多台服务器时。可以用 SSH 配置文件简化。

编辑 ~/.ssh/config(如果不存在就创建):

$ nano ~/.ssh/config

添加以下内容:

# 我的云服务器
Host myserver
    HostName 123.45.67.89
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519
    Port 22

# 另一台服务器
Host workserver
    HostName work.example.com
    User admin
    IdentityFile ~/.ssh/work_key
    Port 2222

配置项说明:

  • Host:别名,你自己定义的简短名字
  • HostName:实际的 IP 地址或域名
  • User:登录用户名
  • IdentityFile:使用的私钥文件路径
  • Port:SSH 端口(默认 22,可省略)

保存后,连接就简单了:

# 不用再输入 IP、用户名、密钥路径
$ ssh myserver

# 连接另一台
$ ssh workserver

还可以配合 scprsync 使用:

# 复制文件到服务器
$ scp myfile.txt myserver:/home/ubuntu/

# 同步目录
$ rsync -avz ./myproject/ myserver:~/projects/

安全最佳实践

1. 禁用密码登录(只允许密钥)

配置好密钥认证后,应该禁用密码登录,防止暴力破解。

在服务器上编辑 SSH 配置:

$ sudo nano /etc/ssh/sshd_config

找到并修改这几行:

PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no

保存后重启 SSH 服务:

$ sudo systemctl restart sshd

警告:禁用密码登录前,务必确认密钥登录能正常工作!否则你会把自己锁在外面。建议先开一个新终端测试密钥登录,确认无误后再禁用密码。

2. 修改 SSH 默认端口

默认端口 22 是扫描器的首要目标。改成其他端口可以减少大量自动化攻击。

$ sudo nano /etc/ssh/sshd_config

修改:

Port 2222  # 改成 1024-65535 之间的任意端口

重启 SSH 后,连接时需要指定端口:

$ ssh -p 2222 ubuntu@123.45.67.89

# 或者在 ~/.ssh/config 里配置 Port 2222

3. 使用防火墙限制访问

# 只允许特定 IP 访问 SSH(推荐)
$ sudo ufw allow from 你的IP地址 to any port 22

# 或者限制连接速率(防止暴力破解)
$ sudo ufw limit 22/tcp

4. 定期更新系统

$ sudo apt update && sudo apt upgrade -y

5. 监控登录日志

# 查看最近的登录记录
$ last

# 查看失败的登录尝试
$ sudo grep "Failed password" /var/log/auth.log

常用服务器任务

文件传输

scp(简单复制)

# 上传文件到服务器
$ scp myfile.txt ubuntu@123.45.67.89:/home/ubuntu/

# 下载文件到本地
$ scp ubuntu@123.45.67.89:/home/ubuntu/data.csv ./

# 上传整个目录(-r 递归)
$ scp -r ./myproject ubuntu@123.45.67.89:~/projects/

# 使用配置文件的别名
$ scp myfile.txt myserver:~/

rsync(增量同步,更高效)

# 同步目录(只传输变化的文件)
$ rsync -avz ./myproject/ myserver:~/projects/

# 参数说明:
# -a: archive 模式(保留权限、时间戳等)
# -v: verbose(显示详细过程)
# -z: 压缩传输

# 排除某些文件
$ rsync -avz --exclude 'node_modules' --exclude '.git' ./myproject/ myserver:~/projects/

# 删除目标目录中源目录没有的文件(危险!)
$ rsync -avz --delete ./myproject/ myserver:~/projects/

进程管理

让程序在后台持续运行

SSH 断开后,普通进程会被终止。使用这些方法让程序持续运行:

方法一:nohup
# 后台运行,输出重定向到 nohup.out
$ nohup python app.py &

# 指定输出文件
$ nohup python app.py > app.log 2>&1 &

# 查看后台任务
$ jobs

# 查看进程
$ ps aux | grep python
方法二:screen(推荐)
# 安装 screen
$ sudo apt install screen

# 创建新会话
$ screen -S myapp

# 在会话里运行程序
$ python app.py

# 按 Ctrl+A 然后按 D 离开会话(程序继续运行)

# 重新连接到会话
$ screen -r myapp

# 列出所有会话
$ screen -ls
方法三:systemd(生产环境推荐)

创建系统服务,开机自启,崩溃自动重启:

$ sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/myapp
ExecStart=/usr/bin/python3 /home/ubuntu/myapp/app.py
Restart=always

[Install]
WantedBy=multi-user.target
# 启用并启动服务
$ sudo systemctl enable myapp
$ sudo systemctl start myapp

# 查看状态
$ sudo systemctl status myapp

# 查看日志
$ sudo journalctl -u myapp -f

端口转发

本地端口转发(访问服务器内网服务)

服务器上运行着一个只监听 localhost:5000 的服务,你想在本地浏览器访问:

$ ssh -L 8080:localhost:5000 myserver

现在访问本地的 http://localhost:8080 就等于访问服务器的 localhost:5000

参数说明:-L 本地端口:目标主机:目标端口。目标主机是从服务器的视角看的,localhost 指服务器自己。

远程端口转发(让服务器访问你的本地服务)

你本地运行着一个服务(比如开发中的网站),想让服务器能访问:

$ ssh -R 9000:localhost:3000 myserver

服务器上访问 localhost:9000 就会转发到你本地的 localhost:3000

动态端口转发(SOCKS 代理)

$ ssh -D 1080 myserver

在浏览器里配置 SOCKS5 代理 localhost:1080,所有流量都会通过服务器转发。

常见问题排查

问题 1:Permission denied (publickey)

原因:密钥认证失败。

排查步骤:

# 1. 确认公钥已上传到服务器
$ ssh myserver "cat ~/.ssh/authorized_keys"

# 2. 检查本地私钥权限(必须是 600)
$ ls -l ~/.ssh/id_ed25519
$ chmod 600 ~/.ssh/id_ed25519

# 3. 检查服务器上的权限
$ ssh myserver "ls -ld ~/.ssh && ls -l ~/.ssh/authorized_keys"
# ~/.ssh 应该是 700,authorized_keys 应该是 600

# 4. 用详细模式查看连接过程
$ ssh -v myserver

问题 2:Connection refused

原因:服务器 SSH 服务未运行,或防火墙阻止。

# 检查服务器 SSH 服务状态(需要先能登录)
$ sudo systemctl status sshd

# 检查防火墙
$ sudo ufw status

# 检查端口是否开放
$ sudo netstat -tlnp | grep :22

问题 3:Connection timed out

原因:网络不通,或 IP/端口错误。

# 测试网络连通性
$ ping 123.45.67.89

# 测试端口是否开放
$ telnet 123.45.67.89 22
# 或
$ nc -zv 123.45.67.89 22

问题 4:Host key verification failed

原因:服务器指纹变化(可能是服务器重装了,或中间人攻击)。

解决:如果确认是服务器重装,删除旧指纹:

$ ssh-keygen -R 123.45.67.89

下一步

掌握了 SSH 和服务器基础后,你可以:

服务器是你项目的家,SSH 是你回家的钥匙。现在你已经掌握了这把钥匙的使用方法。