云服务器传code全链路解析:ssh、scp、unzip协同实战
1. 项目概述:云服务器传 code 文件这件事,远不止敲一行 scp 那么简单
“云服务器传 code 文件等内容”——这行标题看着平平无奇,像极了新手在技术群里的第一句提问。但如果你真在凌晨两点卡在部署环节,对着终端里反复报错的scp: connection refused或failed to unzip发呆,就会明白:这根本不是“传个文件”这么轻巧的事,而是一整套横跨本地开发环境、网络链路、远程系统权限、压缩包完整性、执行上下文的协同工程。我做过上百次 SpringBoot 项目从本地 IDE 到阿里云 ECS 的完整交付,也帮客户排查过腾讯云 CentOS7.9 上unzip命令静默失败的底层编码问题;这些经验告诉我,真正卡住人的,从来不是某个命令记不熟,而是对每个环节背后“为什么必须这样”的无知。本文聚焦的,就是把“传 code”这件事彻底拆开:从你右键点击 VSCode 的“Remote-SSH 连接”那一刻起,到最终java -jar app.jar成功监听 8080 端口,中间所有隐性依赖、常见断点、参数陷阱和实操心法。核心关键词云服务器、code、scp、ssh、unzip不是孤立工具名,而是五个咬合紧密的齿轮——ssh 是通道的锁芯,scp 是通道上的货运列车,code 是货物本身,unzip 是卸货时的开箱工具,而云服务器,是那座你从未真正看清全貌的仓库建筑。适合三类人:刚买完阿里云学生机想部署第一个项目的大学生、用着 Docker 却搞不清基础文件传输逻辑的初级运维、以及被“导入资源包失败 caused by: invalid zip archive”这类报错反复折磨的前端工程师。这不是命令速查表,而是一份带着体温的操作日志。
2. 整体设计思路:为什么不用 rsync?为什么绕不开 ssh 密钥?为什么 unzip 在不同系统上会“装死”?
2.1 传输方案选型:scp 是最朴素的“安全底线”,不是最优解但绝对不可跳过
很多人一上来就想用rsync或 VSCode 的 Remote-SSH 自动同步,甚至直接拉 Git 仓库。但我要先泼一盆冷水:在首次建立可信链路前,scp 是唯一值得你花十分钟认真配置的方案。原因有三:
第一,零依赖性。scp是 OpenSSH 套件的原生组件,只要云服务器装了openssh-server(所有主流发行版默认安装),无需额外装rsync、inotify-tools或 VSCode 插件。我见过太多人在 Ubuntu 22.04 上rsync报bash: rsync: command not found,最后发现连rsync包都没装——而scp永远在/usr/bin/scp下安静待命。
第二,语义明确,错误直白。scp -r ./src user@ip:/home/user/app/这条命令,含义清晰到小学生都能看懂:把本地./src目录递归复制到远程user用户家目录下的app文件夹。而rsync -avz --delete的参数组合,光-a就包含-rlptgoD七个子开关,新手调错一个就可能删掉远程整个目录。更关键的是,scp的报错如Permission denied (publickey)或No route to host,直接指向问题根源;rsync的connection unexpectedly closed却常让人误以为是网络问题,实际只是远程 shell 启动脚本里写了exit 1。
第三,它是所有高级方案的基石。VSCode 的 Remote-SSH 扩展底层调用的就是scp做文件上传;Docker 构建时COPY . /app的源文件,最初也是靠scp传上去的。跳过scp直接上高级工具,就像没学过加减法就去解微分方程——表面快,内里全是空中楼阁。
2.2 为什么必须配 ssh 密钥?密码登录是生产环境的“自杀式操作”
看到热搜词里反复出现ssh 免输入密码 vscode和git配置ssh密钥,就知道这是个高频痛点。但很多人只知其然,不知其所以然:免密码不是为了省事,而是为了切断攻击面。
云服务器的 SSH 默认端口 22 是互联网扫描器的头号目标。暴力破解密码的脚本每秒可尝试上千次组合,而你的root密码哪怕设成P@ssw0rd2024!,在算力面前也撑不过 3 小时。密钥认证则完全不同:它基于非对称加密,私钥永远留在你本地电脑,公钥放在服务器~/.ssh/authorized_keys中。登录时,服务器用公钥加密一段随机数据发给你,你用私钥解密后返回结果——整个过程不传输密码,也不暴露私钥。即使攻击者拿到公钥,也无法反向推导私钥(RSA-2048 的暴力破解需超宇宙年龄)。
实操中,我坚持两个铁律:
- 绝不使用密码登录 root 账户。创建普通用户(如
deploy),用sudo usermod -aG sudo deploy加入管理员组,再禁用 root 密码:sudo passwd -l root。 - 私钥必须加密码保护。生成时用
ssh-keygen -t ed25519 -C "your_email@example.com",过程中务必输入 passphrase。有人嫌麻烦,结果私钥文件被盗,等于把服务器大门钥匙交给了黑客。我的经验是:用 macOS 的 Keychain 或 Windows 的 OpenSSH Agent 缓存 passphrase,输一次即可全天免密,安全与便捷兼得。
2.3 unzip 的“隐形战争”:为什么 CentOS7.9 要手动编译,而 Ubuntu 22.04 却总报编码错误?
热搜词里unzip下载 centos7.9和ubuntu unzip并列出现,绝非偶然。unzip这个看似简单的工具,在不同发行版上藏着巨大的兼容性陷阱。
先说 CentOS7.9:官方源的unzip版本是 6.0(2012 年发布),而现代 Java 项目打包的 JAR/WAR 文件普遍使用 ZIP64 扩展和 UTF-8 文件名。老版unzip解压时会把中文路径变成乱码,甚至直接跳过文件。解决方案不是yum install unzip,而是源码编译新版:
# 下载 unzip 6.0 之后的版本(如 6.1) wget https://sourceforge.net/projects/infozip/files/UnZip%206.x%20%28latest%29/UnZip%206.0/unzip60.tar.gz tar -xzf unzip60.tar.gz cd unzip make -f unix/Makefile generic sudo make -f unix/Makefile install这个过程耗时约 3 分钟,但能一劳永逸解决invalid zip archive错误。
再说 Ubuntu 22.04:它自带unzip 6.0,但问题出在 locale 设置。当服务器LANG=C(纯 ASCII 环境)时,unzip会按 CP437 编码解压文件名,而你的 Windows/Mac 打包工具用的是 UTF-8,结果就是caused by: invalid zip archive: coul(实际是could not被截断)。修复只需一行:
# 永久生效(写入 /etc/environment) echo 'LANG=en_US.UTF-8' | sudo tee -a /etc/environment # 或临时生效(当前会话) export LANG=en_US.UTF-8提示:判断是否为编码问题,用
unzip -l your.zip查看列表。如果文件名显示为??.java或乱码,基本可锁定为 locale 问题。
3. 核心细节解析:从本地 code 到云服务器落地的七道关卡
3.1 关卡一:code 文件的“纯净度”检查——你传的真是能跑的代码吗?
很多部署失败,根源不在服务器,而在你本地的code本身。我见过三次类似案例:开发者把整个 IDEA 项目目录(含.idea/、target/、node_modules/)打包上传,结果unzip后磁盘爆满,或java -jar因找不到主类失败。真正的“code 内容”必须满足三个硬性条件:
- 结构干净:SpringBoot 项目只传
target/your-app.jar(Maven 构建后)或dist/目录(Vue 项目);Python Flask 只传app.py+requirements.txt;Node.js 只传package.json+index.js+node_modules/(若未用 Docker)。 - 依赖明确:检查
pom.xml或package.json中的版本号是否与服务器环境匹配。例如,你在本地用 JDK17 开发,却往只装了 OpenJDK8 的 CentOS7 上传jar,java -version一查就露馅。我的做法是:在pom.xml中强制指定<java.version>11</java.version>,并在服务器java -version输出后才开始传输。 - 路径可移植:避免硬编码绝对路径。比如
File file = new File("/Users/xxx/data.txt")在服务器上必然报错。应改用相对路径new File("data.txt")或通过 JVM 参数传入:java -Ddata.path=/home/deploy/data -jar app.jar。
实操技巧:用tree -L 2 -I "node_modules|.git|.idea|target"命令快速预览要传的目录结构,确保只包含必要文件。曾有个客户传了 2GB 的node_modules,结果scp传了 40 分钟,最后发现服务器内存不足,npm install直接 OOM——其实npm ci --only=production就能解决。
3.2 关卡二:scp 命令的“五维参数矩阵”——每个字母都在说话
scp看似简单,但参数组合构成一张精密的控制网。热搜词里scp -r -p和scp -p频繁出现,说明很多人只知皮毛。我们来拆解scp的核心参数如何影响传输结果:
| 参数 | 作用 | 必须性 | 实操风险 |
|---|---|---|---|
-r | 递归复制目录 | 传整个项目时必需 | 若目标目录已存在同名文件,会覆盖而非合并 |
-p | 保留文件权限、时间戳、属主 | 强烈推荐 | 若不加,.sh脚本传过去后chmod +x才能执行,增加步骤 |
-C | 启用压缩传输 | 大文件(>10MB)时推荐 | 对小文件反而增加 CPU 开销,降低速度 |
-i ~/.ssh/id_ed25519 | 指定私钥文件 | 使用密钥认证时必需 | 路径错误直接报Permission denied,需用ls -l ~/.ssh/确认权限为600 |
-o StrictHostKeyChecking=no | 跳过主机密钥确认 | 自动化脚本中必需 | 仅限内网或可信环境,公网服务器禁用,否则易受中间人攻击 |
一个典型的安全命令是:
scp -rpC -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=no ./springboot-app.jar deploy@123.56.78.90:/home/deploy/app/这里-p保证app.jar的执行权限保留;-C对 JAR 这种高压缩率文件提速 30%;StrictHostKeyChecking=no避免首次连接时交互式确认(自动化部署必备)。
注意:
-p保留的是本地文件的权限。如果本地app.jar权限是644(不可执行),传过去还是644。Java JAR 本身不需要执行权限,但如果是启动脚本start.sh,就必须chmod +x start.sh再传,或传完立刻ssh deploy@ip 'chmod +x /home/deploy/app/start.sh'。
3.3 关卡三:云服务器的“接收区”规划——别让文件散落在/root下吃灰
传文件不是终点,而是起点。我见过太多人scp完就ssh进去ls,发现文件在/root下,然后cd /root、java -jar app.jar,结果因权限问题无法写日志,或端口被占用。科学的接收区规划有三个层级:
一级隔离:专用用户与目录
创建deploy用户(非 root),所有代码、配置、日志都归属该用户。目录结构固定为:/home/deploy/ ├── app/ # 主程序 jar/war 文件 ├── config/ # 外部配置文件(application.yml) ├── logs/ # 日志输出目录(需 `chmod 755`) └── scripts/ # 启动/停止脚本(start.sh, stop.sh)这样做的好处是:
sudo systemctl管理服务时,能精准控制用户权限,避免root运行带来的安全风险。二级防护:SELinux 与防火墙放行
阿里云 CentOS7.9 默认开启 SELinux,它会阻止 Java 进程绑定 8080 端口,报错java.net.BindException: Permission denied。解决方案不是关 SELinux(setenforce 0),而是打标签:# 允许 java 绑定 8080-8089 端口 sudo semanage port -a -t http_port_t -p tcp 8080 # 查看当前端口策略 sudo semanage port -l | grep http_port_t同时,云服务器安全组必须放行对应端口。很多人只记得
iptables,却忘了阿里云控制台的“安全组规则”才是第一道墙。三级兜底:磁盘空间与 inode 预警
scp传大文件前,先df -h看磁盘,df -i看 inode。曾有个客户传了 5000 个微小配置文件,df -h显示还有 20GB,但df -i显示 inode 使用率 99%,导致unzip时提示No space left on device。解决方案:清理/tmp下旧文件,或用find /home/deploy/logs -name "*.log" -mtime +7 -delete定期删除 7 天前日志。
3.4 关卡四:unzip 的“解压仪式感”——三步验证法确保万无一失
unzip不是按下回车就完事的魔法。我总结了一套“三步验证法”,每次解压必走流程:
第一步:校验压缩包完整性
# 检查 ZIP 结构是否损坏 unzip -t your-code.zip # 输出 "No errors detected in compressed data of your-code.zip" 才算过关如果报bad CRC或invalid zip archive,说明传输过程中文件损坏。此时不要重试unzip,而应重新scp——因为scp本身有 MD5 校验,传坏的概率极低,大概率是本地源文件就有问题。
第二步:预览内容结构
# 查看内部文件列表,确认路径、编码、大小 unzip -l your-code.zip | head -20 # 重点关注:是否有中文路径?最大文件是否超 2GB?(老版 unzip 不支持 ZIP64)如果看到???.java,立即停手,按前文方法修复 locale;如果最大文件标着4.2G,而你用的是 CentOS7.9 默认 unzip,必须升级。
第三步:带参数解压,拒绝默认行为
# 推荐命令:解压到指定目录,不覆盖已有文件,显示详细过程 unzip -o -d /home/deploy/app/ your-code.zip # -o 表示 overwrite,避免交互式询问 # -d 指定解压目录,防止解压到当前目录造成混乱实操心得:永远不要在
/home/deploy/app/目录下直接unzip your.zip。如果your.zip里有app/子目录,解压后会变成/home/deploy/app/app/,多一层嵌套。用-d明确指定目标,是职业习惯。
4. 实操全流程:以 SpringBoot 项目部署到阿里云 ECS 为例
4.1 准备工作:本地环境与云服务器的“双向体检”
在敲任何命令前,必须完成双方环境的基线确认。这不是形式主义,而是避免 80% 的“玄学错误”。
本地环境检查清单(Mac/Linux):
ssh -V输出OpenSSH_9.6p1或更高(低于 8.0 的版本有已知漏洞)scp -V确认与 ssh 版本一致tree命令可用(brew install tree或apt install tree)- 私钥文件
~/.ssh/id_ed25519权限为600(chmod 600 ~/.ssh/id_ed25519) - 阿里云 ECS 的公网 IP 已复制,安全组已放行 22(SSH)和 8080(应用端口)
云服务器检查清单(CentOS7.9):
# 1. 确认 SSH 服务运行 sudo systemctl status sshd # 2. 确认 Java 环境(SpringBoot 需 JDK11+) java -version # 应输出 openjdk version "11.0.22" # 3. 确认 unzip 版本(必须 >=6.0) unzip -v | head -1 # 输出 UnZip 6.00 或更高 # 4. 创建部署用户并授权 sudo adduser deploy echo "deploy ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/deploy # 5. 初始化目录结构 sudo -u deploy mkdir -p /home/deploy/{app,config,logs,scripts}注意:
sudo -u deploy mkdir确保目录属主是deploy,避免后续chown。如果忘记这步,scp传过去的文件属主会是root,deploy用户无法修改。
4.2 第一阶段:安全通道建立——从密码登录到密钥免密的完整迁移
这是整个流程的“信任锚点”。很多教程教你怎么生成密钥,却不说清楚迁移过程中的断点处理。
步骤 1:本地生成密钥对
# 生成 ed25519 类型密钥(比 RSA 更快更安全) ssh-keygen -t ed25519 -C "deploy@aliyun" -f ~/.ssh/id_ed25519 # 过程中输入 passphrase(如 123456),记住它!步骤 2:将公钥上传到服务器
# 方法一:用 ssh-copy-id(最简单) ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@123.56.78.90 # 方法二:手动复制(当 ssh-copy-id 不可用时) cat ~/.ssh/id_ed25519.pub | ssh deploy@123.56.78.90 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"步骤 3:服务器端加固
编辑/etc/ssh/sshd_config:
# 禁用密码登录(关键!) PasswordAuthentication no # 禁用 root 登录 PermitRootLogin no # 指定允许登录的用户 AllowUsers deploy重启服务:sudo systemctl restart sshd。
步骤 4:本地测试与故障排除
# 测试连接(应无需密码,且输入 passphrase 后直接登录) ssh -i ~/.ssh/id_ed25519 deploy@123.56.78.90 # 如果报错 "Permission denied (publickey)",按此顺序排查: # 1. 检查 ~/.ssh/id_ed25519 权限是否为 600 # 2. 检查服务器 ~/.ssh/authorized_keys 权限是否为 600,目录 ~/.ssh 权限是否为 700 # 3. 检查 /var/log/secure 日志:sudo tail -20 /var/log/secure | grep sshd实操心得:
ssh -v deploy@ip加-v参数可输出详细调试日志,看到debug1: Offering public key: /Users/xxx/.ssh/id_ed25519表示客户端已发送密钥,若后续无响应,问题一定在服务器端配置。
4.3 第二阶段:code 传输与解压——从本地 target 目录到服务器 app 目录的精准投送
假设你的 SpringBoot 项目已用mvn clean package打包,生成target/demo-0.0.1-SNAPSHOT.jar。
步骤 1:本地结构检查与压缩
# 进入项目根目录 cd /path/to/your/project # 创建纯净的部署包(不含 .git、IDE 文件) zip -r demo-deploy.zip target/demo-0.0.1-SNAPSHOT.jar \ --exclude "*.git*" \ --exclude "*.idea*" \ --exclude "target/*test*" # 检查 zip 大小 ls -lh demo-deploy.zip # 应在 10-50MB 区间,过大需检查是否误含 node_modules步骤 2:scp 传输(带进度与压缩)
# 传输命令(注意路径斜杠结尾表示目录) scp -rpC -i ~/.ssh/id_ed25519 demo-deploy.zip deploy@123.56.78.90:/home/deploy/app/ # 传输完成后,服务器端验证 ssh deploy@123.56.78.90 "ls -lh /home/deploy/app/demo-deploy.zip"步骤 3:服务器端解压与验证
# 登录服务器 ssh deploy@123.56.78.90 # 进入 app 目录 cd /home/deploy/app/ # 1. 校验 zip unzip -t demo-deploy.zip # 2. 预览内容 unzip -l demo-deploy.zip | head -10 # 3. 解压(覆盖旧文件,解压到当前目录) unzip -o demo-deploy.zip # 4. 重命名 jar 文件为统一名称(便于脚本管理) mv target/demo-0.0.1-SNAPSHOT.jar app.jar # 5. 设置执行权限(虽 jar 不需要,但习惯成自然) chmod 644 app.jar步骤 4:配置分离与日志准备
# 创建外部配置文件 cat > /home/deploy/config/application.yml << 'EOF' server: port: 8080 spring: profiles: active: prod logging: file: name: /home/deploy/logs/app.log EOF # 创建日志目录并授权 mkdir -p /home/deploy/logs chmod 755 /home/deploy/logs4.4 第三阶段:启动与守护——让 Java 进程在后台稳定运行
传完、解完、配完,最后一步是让它活下来。
步骤 1:手动启动测试
# 切换到 app 目录 cd /home/deploy/app/ # 用外部配置启动 java -jar app.jar --spring.config.location=file:/home/deploy/config/application.yml # 观察控制台输出,看到 "Started Application in X seconds" 即成功 # Ctrl+C 停止步骤 2:编写 systemd 服务(推荐)
创建/etc/systemd/system/app.service:
[Unit] Description=SpringBoot App Service After=network.target [Service] Type=simple User=deploy WorkingDirectory=/home/deploy/app ExecStart=/usr/bin/java -jar /home/deploy/app/app.jar --spring.config.location=file:/home/deploy/config/application.yml Restart=always RestartSec=10 StandardOutput=journal StandardError=journal SyslogIdentifier=app [Install] WantedBy=multi-user.target启用服务:
sudo systemctl daemon-reload sudo systemctl enable app.service sudo systemctl start app.service # 查看状态 sudo systemctl status app.service # 查看日志 sudo journalctl -u app.service -f步骤 3:防火墙与安全组最终确认
# CentOS7 防火墙放行 8080 sudo firewall-cmd --permanent --add-port=8080/tcp sudo firewall-cmd --reload # 阿里云控制台:安全组规则中添加入方向规则,端口范围 8080/8080,授权对象 0.0.0.0/0(或限定 IP)此时,用浏览器访问http://123.56.78.90:8080,应看到 SpringBoot 默认页面。
5. 常见问题与排查技巧实录:那些让你抓狂的报错,其实都有迹可循
5.1 “ssh: could not resolve hostname d: name or service not known” —— 你少打了 @ 符号!
这个报错在热搜词里赫然在列,99% 的原因是命令写错了。新手常把scp ./code deploy@123.56.78.90:/path误写成scp ./code deploy123.56.78.90:/path(漏了@),或者scp ./code deploy@123.56.78.90:/path写成scp ./code deploy@123.56.78.90:/path(多了一个空格)。ssh解析时,把deploy123.56.78.90当成一个主机名,而 DNS 里当然查不到。
排查技巧:
- 用
ping 123.56.78.90确认 IP 可达 - 用
ssh -v deploy@123.56.78.90看调试日志,找到debug1: Connecting to deploy123.56.78.90 [deploy123.56.78.90] port 22这一行,就能定位拼写错误
5.2 “failed to unzip 1: invalid zip archive: coul” —— 字符串截断暴露的深层问题
这个报错的后半截coul明显是could not的截断,说明unzip进程在读取 ZIP 头部时异常退出。根本原因有两个:
- ZIP 文件损坏:
scp传输中断,或本地源文件不完整。用file your.zip检查,正常输出your.zip: Zip archive data, at least v2.0 to extract;若输出your.zip: data,说明不是 ZIP 文件。 - 磁盘空间不足:
unzip解压时需要临时空间,通常是原文件大小的 1.5 倍。用df -h /home看剩余空间,若 < 1GB,先清理/tmp。
终极验证法:在本地用unzip -t your.zip,若报错,问题在源文件;若本地正常,服务器报错,则是服务器环境问题(locale 或 unzip 版本)。
5.3 “ssh connection reset by peer” —— 不是网络问题,是服务器主动断连
这个报错常让人怀疑是阿里云网络抖动,实则 90% 是服务器端的sshd配置问题。sshd默认有连接超时机制,当客户端长时间无操作,会主动断开。
解决方案:
编辑服务器/etc/ssh/sshd_config:
# 客户端每 60 秒发一次保活包 ClientAliveInterval 60 # 连续 3 次无响应则断开 ClientAliveCountMax 3重启sudo systemctl restart sshd。
注意:
ClientAliveInterval是服务器端配置,ServerAliveInterval是客户端配置(在~/.ssh/config中设置)。两者配合,才能彻底解决“连接突然断开”。
5.4 “vscode ssh 连接后无法上传文件” —— VSCode 的隐藏权限陷阱
VSCode Remote-SSH 扩展有时显示连接成功,但拖拽文件上传失败,报错EACCES: permission denied。这是因为 VSCode 的上传功能默认使用sftp协议,而sftp的根目录是用户家目录(/home/deploy),但你可能想传到/opt/app。
解决方法:
- 在 VSCode 的 Remote-SSH 配置中,右键服务器连接 →
Configure Server Settings→Remote.SSH: Default Path,改为/home/deploy/app - 或更彻底:在
~/.ssh/config中为该服务器添加:
这样每次连接都自动进入目标目录。Host my-aliyun HostName 123.56.78.90 User deploy IdentityFile ~/.ssh/id_ed25519 RemoteCommand cd /home/deploy/app
5.5 “导入资源包失败 caused by: 0: failed to unzip 1: invalid zip archive: coul” —— 前端工程师的专属噩梦
这个报错常见于 Vue/React 项目导入.zip资源包(如 UI 组件库)。根本原因在于:前端构建工具(如 Webpack/Vite)打包的 ZIP,内部文件名用了 UTF-8,而某些 Linux 系统的unzip默认用 CP437 解码。
三步修复:
- 在服务器执行
locale,确认LANG是en_US.UTF-8或zh_CN.UTF-8 - 若不是,执行
export LANG=en_US.UTF-8临时生效,或永久写入/etc/environment - 用
unzip -O UTF-8 your.zip强制指定编码解压(-O参数要求 unzip 6.0+)
实操心得:前端同学可以养成习惯,在打包 ZIP 前,用
zip -r -Z store your.zip *(-Z store表示不压缩,只打包),这样unzip解压时不会因压缩算法差异出错。
6. 进阶思考:当 scp 不再够用,下一步该走向何方?
做到上面所有步骤,你已经能稳定部署 95% 的项目。但技术演进不会停步,当团队规模扩大、项目增多、CI/CD 需求出现时,“手敲 scp” 就成了瓶颈。这时,你需要考虑三个跃迁方向:
6.1 方向一:从 scp 到 rsync —— 增量同步的效率革命
scp每次都是全量传输,而rsync只传差异部分。一个 100MB 的 SpringBoot 项目,改了一行代码,scp还是传 100MB,rsync可能只传 1KB。命令范式:
# 本地构建后,只同步变更文件 rsync -avz --delete -e "ssh -i ~/.ssh/id_ed25519" \ ./target/classes/ \ deploy@123.56.78.90:/home/deploy/app/classes/--delete确保远程删除的文件本地也删,保持完全一致。但要注意:rsync的--delete是危险操作,首次使用务必加--dry-run参数预览。
6.2 方向二:从手动部署到 CI/CD —— GitHub Actions 的 5 行自动化
当你有多个服务器,或需要测试通过后自动部署,就得拥抱 CI/CD。GitHub Actions 是最轻量的选择。在项目根目录创建.github/workflows/deploy.yml:
name: Deploy to Aliyun on: [push] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build with Maven run: mvn clean package -DskipTests - name: Deploy via SCP uses: appleboy/scp-action@v0.1.7 with: host: ${{ secrets.HOST }} username: ${{ secrets.USERNAME }} key: ${{ secrets.KEY }} source: "target/*.jar" target: "/home/deploy/app/"配置好 Secrets(HOST/USERNAME/KEY),每次git push,Actions 就自动构建、
