Redwood 服务器入门指南:掌握 SSH 连接与 Baremetal 部署基础
【免费下载链接】redwoodRedwoodGraphQL项目地址: https://gitcode.com/gh_mirrors/re/redwood
Redwood 应用从开发机走向真实物理服务器,第一步就是学会通过 SSH 连接远程主机。本文以 Redwood 6.x 官方文档《Introduction to Servers》为主体,结合仓库中 Baremetal 部署的 CLI 源码与配置模板,系统讲解 SSH 的三种认证方式、密钥管理、Agent Forwarding、提示符与别名优化,为你后续使用 Baremetal 部署(yarn rw deploy baremetal)打下坚实基础。
为什么需要这篇指南
Redwood 框架既支持 Netlify、Vercel、Render 等云托管平台,也提供了自建服务器部署选项Baremetal。Baremetal 的部署原理是:从你的开发机(或 CI 客户端)通过 SSH 连接一台或多台远程服务器,然后在远程执行git clone、yarn install、数据库迁移、构建和进程重启等一系列命令。因此,学会手动用 SSH 连接服务器,是成功使用 Baremetal 的前提——如果你自己都连不上服务器,Baremetal 也不可能替你连上。
在 *nix 系统(macOS、Linux)上,SSH 是系统自带的连接工具;在 Windows 上安装 PowerShell 等终端环境后同样可以使用。本文涉及的 SSH 连接策略共有三种:
- 用户名 + 密码(Username & password)
- 私钥(Private key)
- 公钥(Public key)
术语澄清
正式动手之前,先厘清几个容易混淆的概念:
- SSH:Secure Shell Protocol 的缩写,是贯穿本文使用的
ssh命令行工具所基于的协议 ssh:代码字体中的ssh特指实际的命令行工具,而非广义的 "SSH" 协议概念ssh-agent:另一个实用工具,负责跟踪公钥和私钥,并将其提供给ssh工具使用
首次连接前的准备工作
在能够通过 SSH 连接服务器之前,你必须知道目标服务器的用户名。这个用户名由你的云服务商决定,不同平台的默认账号各不相同:
| 云平台 | 镜像/实例类型 | 默认用户名 |
|---|---|---|
| AWS | Ubuntu 镜像创建的 EC2 实例 | ubuntu |
| AWS | Amazon 自家 Linux 镜像 | ec2user |
| Digital Ocean | Droplet | root |
不同厂商、不同镜像的默认用户可能千差万别,务必在连接前从托管/云服务商处确认。
指纹提示(Fingerprint Prompt)
无论使用哪种认证方式,第一次连接陌生服务器时都会看到如下提示,这是因为你从未连接过这台服务器:
The authenticity of host '192.168.0.122 (192.168.0.122)' can't be established. ED25519 key fingerprint is SHA256:FHQDzxsqA68c+BhLPUkyN8aAVrznDtekhPg/99JXk8Q. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?这是一次快速的安全校验,用于确认你正在连接的正是你以为的那台机器。只要服务器地址无误,输入yes即可。随后你会看到一条提示,告知该主机已被加入已知主机列表(之后再次连接同一台服务器就不会再被询问):
Warning: Permanently added '192.168.0.122' (ED25519) to the list of known hosts.所有已知服务器的记录都保存在本机这个文件中:
~/.ssh/known_hosts复用 IP 地址的坑:如果你连接的是云端服务器,经常开关实例并复用 IP 地址,那么下次连接该 IP 时会报错(因为服务器的签名已与
known_hosts中记录的旧签名不一致)。解决办法是:在~/.ssh/known_hosts中找到对应行并删除,即可重新连接。
Baremetal 首次部署失败?如果你从未手动通过 SSH 连接过目标服务器,Baremetal 部署很可能失败——因为 Baremetal 没有交互式提示来接受服务器指纹。你需要至少手动连接服务器一次,Baremetal 才能正常连接。
三种连接方式详解
方式一:用户名 + 密码
用户名/密码认证最直观:用ssh命令指定用户名和服务器地址(域名或 IP)即可。密码通常是在创建服务器时设置,或由服务商随机生成。
ssh user@server.com以 Digital Ocean Droplet 为例,用户为root,IP 为192.168.0.122:
ssh root@192.168.0.122随后系统会提示输入密码(输入时按键不可见):
root@192.168.0.122's password:密码错误允许重试三次。无论连接成功与否,都可以跳到下一节 Connected 继续。
方式二:私钥认证
部分服务商(如 AWS)在创建服务器时不会给密码,而是直接给你一个私钥文件,这类文件通常以.pem结尾。请务必记住这个文件存放的位置——在放弃密码方案的前提下,它是你连接服务器的唯一凭证。一旦丢失,只能销毁实例重新创建。
作者的习惯是把私钥统一放在~/.ssh目录(可再建子目录),集中管理所有 SSH 相关文件。
关于公钥/私钥对:密钥对由一把公钥和一把私钥组成。任一把都可以加密文档,但只有对应的私钥能解密。因此公钥可以自由分发(这正是它叫"公钥"的原因),而私钥持有者可以验证文档确实是用配套公钥加密的。反过来,私钥可以生成文档签名,公钥可以验证签名是否由匹配的私钥创建——于是你得到原始消息后,验证签名即可信任消息确实来自私钥持有者。
注意:无法用公钥解密用私钥加密的内容,否则公钥分发给任何人的意义就消失了(任何人都能读到你的消息)。如果双方需要双向加密通信,可以互相交换公钥,各自用对方的公钥加密。
直接用私钥连接时,很可能遇到一个吓人的报错:
ssh -i ~/.ssh/keyname.pem ubuntu@192.168.0.122 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0666 for '/Users/rob/.ssh/shared/algostake.pem' are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored.原因是从互联网下载的文件权限通常过于宽松(系统上任何人都可读),SSH 要求私钥文件只允许你自己读写。解决办法是用chmod将权限收紧为600(仅文件所有者可读写,其他人无任何权限):
chmod 600 ~/.ssh/keyname.pem其中keyname替换为实际文件名。改好权限后,用-i标志指定私钥路径连接:
ssh -i ~/.ssh/keyname.pem ubuntu@192.168.0.122方式三:公钥认证
部分服务商(如 Digital Ocean)允许在创建服务器时自动把你的公钥放到服务器上,从而完全跳过密码和私钥认证。这也是本文最终推荐并会落实到 Baremetal 部署的首选方式。
如果你还不清楚公钥是什么、自己的公钥在哪里、或"把公钥放到服务器上"意味着什么,可以先跳到 生成公钥/私钥对 一节。
公钥认证只需用户名和服务器地址:
ssh ubuntu@192.168.0.122如果服务器不支持创建时预置公钥,则需要手动把公钥添加到服务器,见 将 SSH 公钥添加到服务器。
Connected:连接成功后的检查
无论使用哪种认证方式,此时你应该已经连上服务器了。如果看到如下错误:
ubuntu@192.168.0.122: Permission denied (publickey,password).通常有四种可能:
- 用户名错误
- 密码错误
- 本机尝试使用的公钥不在服务器的
~/.ssh/authorized_keys文件中 - 通过
-i指定的私钥未被服务器接受
此时可以加上-v(verbose)标志重新运行命令,SSH 会详细打印它尝试过的每一种登录方式,方便排查。
连接成功的典型画面是一段系统欢迎信息(以下是 Ubuntu 22.04 示例,你的机器可能不同):
Welcome to Ubuntu 22.04 LTS (GNU/Linux 5.15.0-41-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Wed Aug 3 21:09:41 UTC 2022 System load: 0.25439453125 Users logged in: 0 Usage of /: 6.3% of 24.05GB IPv4 address for eth0: 192.168.0.122 Memory usage: 22% IPv4 address for eth0: 10.48.0.5 Swap usage: 0% IPv4 address for eth1: 10.124.0.2 Processes: 97 0 updates can be applied immediately. ... root@remote-server:~#最后一行root@remote-server:~#就是命令行提示符,从这里开始可以输入命令了。
断开连接
断开连接只需一个exit命令;直接关闭终端窗口也会终止连接:
root@remote-server:~# exit Connection to 192.168.0.122 closed.简化访问:把公钥放到服务器上
每次都要输入用户名或带-i指定私钥并不愉快。幸运的是 SSH 基于公钥/私钥密码学,可以用你的公钥验证身份。你大概已经在 GitHub 的Settings > SSH and GPG keys上传过公钥——我们要做的类似:把本机公钥放到服务器上,让服务器在连接时认出你,从而跳过密码。
如果你已经在使用公钥认证,可以直接跳过本节——你已经在做了。
服务器上可以保存多台开发机的公钥,这样你能从多台电脑连接。这在团队协作时尤其方便:有人离职时只需从服务器移除他的公钥。对比之下,密码认证要么把单一部署账号的密码共享给所有队友(有人离职就得改密码),要么给每人发一份服务器私钥副本(每有人离职就要换一遍)。维护公钥列表要简单得多。
公钥/私钥对
你可能已经拥有一对公钥/私钥了!检查~/.ssh目录,找找扩展名相同前缀的两个文件——一个带.pub后缀(例如id_ed25519和id_ed25519.pub)。如果你不记得自己创建过这两个文件,那它们多半是ssh-keygen之类的程序生成的,SSH 已经在使用它们了!
用下面这个命令查看 SSH 当前已知的密钥:
ssh-add -L输出为零行或多行公钥,形如:
ssh-ed25519 AAAAB3NzaC1yc2EAAAADAQAB<REDACTED>CU90x/khqD1sDW= rob@computer.local把输出与~/.ssh/id_ed25519.pub的内容对比,如果一致,说明 SSH 连接时已经在使用你的公钥了。如果没有密钥对呢?
生成公钥/私钥对
生成新密钥对只需一条命令:
ssh-keygen -t ed25519-t ed25519指定使用 ED25519 算法。可选的算法有很多,但并非所有算法在所有系统上都受支持。命令执行后会问你几个问题:
Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/rob/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again:- 如果没有任何密钥,直接按ENTER采用默认文件名
id_ed25519 - Passphrase(口令)是密钥上的额外安全层,但每次访问私钥都要输入口令,反而抵消了"把公钥共享给服务器以便快速访问"的便利性。只要你能保护好私钥,就不必设口令——连按两次 ENTER 跳过即可
生成完成后的输出类似:
Your identification has been saved in id_ed25519 Your public key has been saved in id_ed25519.pub The key fingerprint is: SHA256:6Qg7RQRGp1AtfVIOucEt1HtZWkYMU1LZYBVwBsXwTWQ rob@computer.local The key's randomart image is: +--[ED25519 256]--+ | .B&@O+ .E +==| | o=*= .** . o .o| | . o . . . .| | .o o . o ..| | o . A * + .| | = + = + | | o . * . | | . o | | | +----[SHA256]-----+Randomart 是什么?密钥校验通常是比较无意义的字符串(即密钥指纹的十六进制表示),人眼对比起来又慢又容易出错。Randomart 用结构化图像代替字符串,让人类能更快、更直观地判断两个公钥是否相同。
添加到 ssh-agent
密钥存在了,但 SSH 知道使用它吗?问问管理密钥的ssh-agent:
ssh-add -L如果列表里没有你的新公钥,只需告诉ssh-agent密钥位置(注意:这里传的是私钥路径):
ssh-add ~/.ssh/id_ed25519再次运行ssh-add -L就应该能看到你的密钥了。
电脑重启后密钥丢失:某些情况下重启后
ssh-agent会忘记密钥。可以在本机(不是服务器)的~/.zshrc中加一行,让每次开启新终端会话时自动添加密钥:ssh-add ~/.ssh/id_ed25519
将 SSH 公钥添加到服务器
SSH 现在会把公钥呈现给服务器,但服务器还不知道该怎么处理它。接下来把公钥复制到服务器上,让服务器允许来自该公钥的连接。先在终端打印公钥以便复制:
cat ~/.ssh/id_ed25519.pubmacOS 上可以用这条两段式命令直接复制到剪贴板:
cat ~/.ssh/id_ed25519.pub | pbcopy
然后照常用 ssh 连接服务器(用户名/密码或私钥均可),打开~/.ssh/authorized_keys文件进行编辑。nano编辑器通常内置且简单易用,vi也是选择之一:
nano ~/.ssh/authorized_keys把公钥粘贴到文件的新行。建议在密钥上方加一条注释,注明来源电脑(姓名 + 主机名),否则随着电脑升级、同事接入,你将很快分不清哪个密钥属于谁:
# Rob Cameron (optimus-prime) ssh-ed25519 AAAAB3NzaC1yc2EAAAADAQAB<REDACTED>CU90x/khqD1sDW= rob@computer.local保存并退出。现在断开 SSH 会话(exit)后重新连接,这次不需要密码,也不需-i指定私钥,直接:
ssh root@192.168.0.122就可以登录了!
SSH Agent Forwarding(代理转发)
连接远程服务器后,你可能还想从服务器再 SSH 到其他机器,并让对方识别为你本人(个人电脑上的你),而不是这台服务器。默认情况下这是不成立的:从远程服务器发起 SSH 连接时,使用的是服务器自身的凭据,意味着你需要在服务器上再走一遍前面所有配置公钥的流程。
SSH 提供了一个机制解决这个问题:SSH Agent Forwarding(代理转发)。
它最典型的应用场景是从 GitHub 部署代码到远程服务器:你已经以本人身份连上了远程服务器,也已经有权限连接 GitHub,那就直接复用这些凭据。可以用下面命令验证是否已生效:
ssh -T git@github.com如果看到类似输出:
Hi cannikin! You've successfully authenticated, but GitHub does not provide shell access. Connection to github.com closed.说明代理转发已经生效!GitHub 识别出了你的用户名并授予访问权限——远程服务器转发了你的公钥(也就是连接远程服务器时用的那把),一切顺理成章。
如果看到:
git@github.com: Permission denied (publickey).则代理转发尚未开启,需要按 GitHub 官方指南完成配置。
Deploy Keys(部署密钥)
你可能不想在部署时使用个人 SSH 密钥。代理转发的一个缺点是:它要求你本人(或代表你的部署系统)SSH 进入机器执行部署,而不是让 CI/CD 系统独立完成。另一个是安全问题:个人 SSH 密钥通常拥有仓库的全部权限,远超部署所需的只读权限。
基于这些考虑,可以改用deploy keys(部署密钥):生成一对专属于服务器(们)的密钥对,把公钥告诉 GitHub。这样服务器无需你参与即可连接 GitHub 并克隆代码库,而且可以把该密钥的访问权限锁定到单个仓库、只读级别。
自定义提示符(Prompt)
部署到生产环境时,在提示符上时刻提醒自己正连接着哪台服务器非常有帮助——而不是看到一串 IP 或随机主机名:
root@remote-server:~# # or user@192.168.0.122这是生产环境还是预发环境?集群里的哪一台?提示符完全可以自定义。一个实用的命名约定是:应用名 + 环境 + 服务器序号。例如应用叫 "ruby",是生产环境集群的第一台服务器,可以期望提示符长这样:
root@ruby-prod1:~#提示符通常定义在以下文件之一:
~/.bashrc ~/.bash_profile ~/.zshrc ~/.zprofile如果使用 bash/zsh 之外的 shell,文件名会不同,但思路一致。用nano或vi打开文件,找到以PS1=开头的行(可能不止一行):
if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] ' else PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' fi上面的第一段PS1用于彩色提示符,第二段用于黑白终端,两处都要改。
这串字符里有三个特殊转义符:\u(用户)、\h(主机名)和\w(工作目录),你可能全部或部分用到。其余如[\033[00m\]之类的都是颜色代码,暂时忽略。
对于简单场景,只需把\h替换为想显示的主机名字符串:
if [ "$color_prompt" = yes ]; then PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@ruby-prod1\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] ' else PS1='${debian_chroot:+($debian_chroot)}\u@ruby-prod1:\w\$' fi保存文件后用source让变量在当前会话生效:
source ~/.bashrc提示符立刻变成自定义主机名。这样每次连接服务器都能清楚地知道自己在哪,避免在错误的环境里执行危险命令。
如果想玩出更多花样,市面上还有 PS1 生成器,可以生成包含各种高级内容的提示符字符串并轻松定制颜色。
用别名实现一键连接
看到ruby-prod1能帮你记住当前在哪台服务器,但能不能直接把ruby-prod1当作命令来连接?当然可以!
在本机的.zshrc、.bash_profile等配置文件中加一行:
alias ruby-prod1='ssh root@192.168.0.122'然后执行source ~/.zshrc使其生效。之后只需输入服务器名字即可连接,完全跳过 ssh 命令:
ruby-prod1没有比这更省事的了!
与 Baremetal 部署的衔接
完成以上所有步骤后,你就具备了使用 Baremetal 部署的 SSH 基础。Redwood 的 Baremetal 部署正是模拟你手动做的事情:SSH 连入远程服务器并执行命令。如果你能手动连上服务器,Baremetal 也能。
从源码看,Baremetal 部署命令定义在 packages/cli/src/commands/deploy/baremetal.js,它通过 packages/cli/src/commands/deploy/baremetal/SshExecutor.js 中封装的node-ssh库建立连接。连接参数(host、port、username、password、privateKey、privateKeyPath、passphrase、agentForward)与本文讲解的认证方式一一对应——例如agentForward: serverConfig.agentForward && process.env.SSH_AUTH_SOCK就对应本文的 Agent Forwarding 概念,部署时会把本机已加载到ssh-agent的密钥转发到远程服务器,用于拉取 GitHub 私有仓库。
Baremetal 的初始化配置由 packages/cli/src/commands/setup/deploy/providers/baremetal.js 生成deploy.toml、ecosystem.config.js和web/src/maintenance.html三个文件,其中deploy.toml的 SSH 连接选项注释(host、port、username、password、privateKey、privateKeyPath、passphrase、agentForward)与本文内容完全一致。
完成 SSH 学习后,下一步可以参考仓库中的 Baremetal 部署指南 或 当前版本的 Baremetal 文档,执行:
yarn rw setup deploy baremetal然后进行首次部署:
yarn rw deploy baremetal production --first-run小结
本文完整覆盖了 SSH 连接远程服务器的全部基础:三种认证方式(用户名密码、私钥、公钥)、首次连接的指纹确认、密钥对的生成与ssh-agent管理、将公钥部署到服务器、Agent Forwarding 与 Deploy Keys 两种 Git 访问方案,以及提升日常效率的提示符自定义与连接别名。这些都是使用 Redwood Baremetal 部署自建服务器的必修课——连接服务器的能力,决定了你能把应用部署到哪里。
【免费下载链接】redwoodRedwoodGraphQL项目地址: https://gitcode.com/gh_mirrors/re/redwood
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考