刚拿到一台服务器的时候,绝大多数人的第一反应都是同一个:我怎么上去?怎么把代码和文件放上去?
这两个问题,看起来简单,实际上贯穿了从开发、部署到日常维护的整个周期。无论你是用云服务器练手,还是在公司机房里维护一台 Linux 服务器,“服务器的连接以及文件的上传”都是最基础也最绕不开的操作。很多教程把这件事拆得七零八落,今天我把它们串在一起,从连接原理讲到具体命令,再讲到上传文件时最容易踩的坑,一步不落走一遍。
这篇内容适合三类人:刚买了云服务器不知道从哪里开始的新手;用 VSCode 连着远程服务器开发、但对 scp 和 rsync 不太熟的开发者;以及想搞清楚文件上传为什么老是出问题的运维新人。看完之后,你能自己完成从登录服务器到把本地文件传上服务器的完整闭环,并且知道出问题时该往哪个方向排查。
1. 连接服务器之前,先把这几件事想明白
1.1 你说的“连接服务器”,到底是连什么
很多人以为“连接服务器”就是把电脑和一台远方的机器连起来,像插一根网线一样简单。其实不是。我们平时说的连接服务器,本质是“远程登录”——你在本地电脑上输入命令,服务器执行,然后把结果回传给你。这个过程依赖的是 SSH 协议。
SSH(Secure Shell)是一种加密的网络协议,默认跑在 22 端口。它干的事情,就是让你安全地远程登录到另一台机器上执行命令。为什么强调“安全”?因为早年大家用 Telnet,明文的,谁在网络上抓包谁就能看到你的密码,跟把家门钥匙插在锁孔里没区别。SSH 把所有流量都加密了,所以成了事实标准。
理解这一点有个实际好处:当你配置防火墙或者云服务器安全组时,就知道该放行哪个端口。默认 22 端口,如果你改了端口,就要同步改防火墙规则,不然后面怎么连都连不上。
1.2 SSH 登录的两把钥匙:密码登录与密钥登录
连接服务器时,身份认证有两种主流方式。
第一种是密码登录。就是你在本地输入 ssh 用户名@服务器IP,然后输入密码。简单直接,适合初次使用。缺点也很明显:密码容易泄露,容易被人暴力尝试。我在真实环境里见过不少被扫爆的服务器,root 密码设置得再复杂,暴露在公网上也扛不住持续的字典攻击。
第二种是密钥登录。原理是本地生成一对密钥——一把公钥、一把私钥。你把公钥放到服务器的 ~/.ssh/authorized_keys 文件里,私钥留在本地。连接时,服务器用公钥验证你的身份,本地用私钥应答。这个机制可以理解成配了一把专属钥匙:公钥是锁,私钥是钥匙,钥匙只有你有。
我现在所有服务器都用密钥登录。生产环境直接禁用密码认证,只有需要临时访问时才临时开。这个习惯能挡住绝大多数自动化攻击。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从零到一:搭建一套最顺手的连接环境
2.1 最常用也最稳的一种连接方式:SSH 命令行
不管你的电脑是 Windows、macOS 还是 Linux,SSH 客户端基本都自带了。Windows 10 之后的系统自带 OpenSSH 客户端,可以直接在 PowerShell 或 CMD 里运行 SSH 命令,不需要额外安装软件。
连接命令非常简单:
bash复制ssh 用户名@服务器IP
如果你是第一次连接,会看到提示确认服务器的指纹,输入 yes 回车即可。然后输入密码,就能登录到服务器的 shell 环境。
这里我强烈建议新手做一件事:不要用 root 直接登录。原因是 root 权限太大,一旦操作失误,影响面无法挽回。更稳妥的做法是:
bash复制# 在服务器上创建新用户(仅第一次需要)
adduser devops
# 给新用户 sudo 权限
usermod -aG sudo devops
然后用这个新用户来登录。日常操作权限不够时再通过 sudo 提权。这个习惯能避免非常多灾难性事故。
2.2 图形界面上传文件:比命令行更省心的方案
命令行对于不熟悉终端操作的人来说还是有门槛的。如果你想用鼠标拖拽文件,可以考虑 SFTP 图形客户端。
SFTP 并不是一个新的协议,它其实是“基于 SSH 的文件传输协议”。所以只要服务器开了 SSH,你就能用支持 SFTP 的客户端直接连接,比如 FileZilla、WinSCP,或者国内的 FinalShell、Xshell。这类工具界面直观,左边是本机文件,右边是服务器文件,拖拽就可以上传、下载。
选择上我的经验是:Windows 下用 WinSCP 或 FinalShell 都比较顺手,macOS 下用 FileZilla 或者直接利用系统自带的“连接服务器”功能也可以。图形化工具对新手足够友好,但有一点要注意:拖拽上传后,文件的所有者和权限可能与你预期不同,尤其涉及到网站目录时,容易出现“上传了但网页报 403”的问题。这一点我在后面“权限”部分还会展开。
2.3 推荐配置:用 VSCode 一边写代码一边连服务器
如果你不是单纯传文件,而是要在服务器上改代码、跑脚本、看日志,那一定要试试 VSCode 的 Remote-SSH 插件。
它的工作方式很巧妙:你在本地用 VSCode 打开远程服务器的目录,编辑、搜索、调试都在本地界面完成,但实际执行都在服务器端。体验上跟写本地代码几乎一样,唯一的区别是底部状态栏显示着连接的目标服务器地址。
配置方法不复杂:
- 在 VSCode 插件市场安装“Remote - SSH”插件。
- 按 F1,输入
Remote-SSH: Connect to Host,然后输入你的 SSH 连接信息,比如devops@服务器IP。 - 选择远程服务器的目录打开即可。
用 VSCode 连服务器的好处不只是界面好看。它能直接查看远程目录、集成终端、安装插件做代码补全和调试。我可以直接打开远程服务器的 /var/log/nginx/error.log 实时盯着报错,发现一个改一个,效率比在终端里 vim 高很多。
3. 文件上传实操:四个办法覆盖九成场景
连接上服务器后,接下来就是核心需求:把本地文件传到服务器上。我按使用场景整理了四个办法,你根据自己情况选就行。
3.1 scp 上传单个文件或整个目录
scp 是最基础的上传命令,基于 SSH 协议,语法和 cp 很像。上传单个文件:
bash复制scp /本地路径/文件名 用户名@服务器IP:/远程目录/
比如:
bash复制scp ~/Desktop/demo.tar.gz devops@192.168.1.100:/home/devops/
如果你改了 SSH 端口,需要加 -P 参数(注意是大写 P,小写 p 在 scp 里是保留文件时间戳的意思,很多人在这里翻车):
bash复制scp -P 2222 ~/Desktop/demo.tar.gz devops@192.168.1.100:/home/devops/
上传整个目录,加上 -r 参数:
bash复制scp -r ~/Desktop/myproject/ devops@192.168.1.100:/home/devops/
scp 最大的优点是简单,在任何装了 SSH 的机器上都能用,不需要额外配置。缺点也有:如果传输中断,scp 会直接失败,不能续传;而且它是全量拷贝,即使只有一个文件变了,它也会重新传一遍。对于一次性的小文件,选 scp 没毛病。
3.2 rsync 增量同步,批量上传的正确姿势
如果你要上传的是一个不断更新的项目目录,或者文件特别多、特别大,scp 就有点吃力了。这时候应该用 rsync。
rsync 是 Linux 下最经典的文件同步工具,它的核心能力是“只传变化的部分”。第一次全量传,之后再次执行时,它比对源和目标文件的时间戳、大小等信息,只把新增或修改的文件传过去。对于我这种经常改几张图片、几个代码文件就要部署一次的人来说,rsync 能省下大量时间。
批量上传整个目录,最常用的命令是:
bash复制rsync -avz --progress /本地目录/ 用户名@服务器IP:/远程目录/
拆解一下参数:
-a归档模式,保留权限、时间戳、软链接等元数据。-vverbose,显示传输过程。-z传输时压缩,网络带宽小的时候很有帮助。--progress显示进度条。
如果服务器 SSH 端口不是默认的 22,用 -e 指定:
bash复制rsync -avz -e "ssh -p 2222" /本地目录/ 用户名@服务器IP:/远程目录/
注意这里有几个细节:
第一,本地目录末尾有没有斜杠,效果完全不同。rsync -avz /data/ user@server:/backup/ 表示把 /data/ 里的内容同步到 /backup/ 里;而 rsync -avz /data user@server:/backup/ 表示把 data 这个目录本身同步到 /backup/ 里面。这个区别很容易让人传完发现目标路径多了一层,最好第一次先加 --dry-run(只演练不实际执行)确认一下。
第二,rsync 默认通过 SSH 通道传输,所以你只要远程服务器能 SSH 登录,rsync 就能用。不需要额外开启端口。
第三,生产环境更新代码时,我会带上 --delete 参数,让远程目录里本地已经删除的文件也删掉,保持两边严格一致。但这个参数很危险,用之前必须先 --dry-run 看一遍输出,确认没有误删风险。
3.3 用 SFTP 客户端做可视化拖拽上传
命令行固然高效,但有些场景下图形化工具更省事。比如你只是想快速传一个配置文件,或者需要批量下载服务器上的日志文件,用 WinSCP 或 FileZilla 拖拽一下就行。
以 WinSCP 为例:
- 新建站点,选择文件协议 SFTP。
- 填入主机名、用户名、密码或密钥文件。
- 登录后,左边是本机文件,右边是服务器目录。
- 直接拖拽上传或下载。
这类客户端通常还附带编辑、重命名、修改权限等操作,对新手尤其友好。不过我还是想提醒一点:图形化工具传完文件后,务必确认目标文件的所有者和权限是否正确。我遇到过不少次,开发人员用 FileZilla 上传网站文件后,网页直接 500,排查下来是文件属主变成了他自己的用户名,而 PHP-FPM 进程的用户读不了这个文件。这种问题在命令行里运行 ls -l 可以一眼看穿,在图形界面里反而不那么直观。
3.4 用 git、网盘中转等间接方式处理“不太方便直传”的场景
有些时候,你无法直连服务器,或者文件大得离谱,直接用 scp/rsync 都不合适。这时候可以走间接路线。
最常见的间接方式是 git。如果你代码托管在 GitHub、GitLab 或 Gitee 上,直接在服务器上执行:
bash复制git clone 仓库地址
或者更新:
bash复制git pull
等于把“文件上传”这件事变成了一个版本管理操作,不仅安全,还天然带有回滚能力。我在发布生产环境代码时基本都走这条路,而不是用 scp 硬传。
另一种间接方式是对象存储。如果文件超过 1GB,比如备份数据库,我会先传到云厂商的对象存储(OSS/COS/S3),再从服务器上 wget 或 curl 下载下来。这种方式适合跨网络环境传输大文件,因为直接 scp 很容易因为网络波动中断,而对象存储通常有断点续传和分片上传,稳定得多。
4. 上传之路的坑,我替你踩过的都写在里面了
4.1 权限、路径与换行符,最容易翻车的三个细节
文件上传后“看起来成功,实际用不了”,90% 都出在三件事上:权限不对、路径不对、换行符不对。
权限不对通常是上传的是代码或配置文件,但运行服务的用户没有读取权限。比如你用 root 上传了文件到 /var/www/html,文件属主是 root,权限是 600,而 Web 服务器以 www-data 用户运行,自然读不到。排查时顺手执行:
bash复制ls -l /var/www/html/文件名
如果确认是权限问题:
bash复制chown www-data:www-data /var/www/html/文件名
chmod 644 /var/www/html/文件名
路径不对更常见。很多人在本地开发时目录结构是 D:\project\dist,上传到服务器后想当然地放在了 /var/www/html/dist,结果发现页面 404。我以前就吃过这个亏。建议每次上传前先在服务器上 pwd 确认当前目录,再用 ls 看一下目标目录是否存在,别靠记忆猜路径。
换行符这个坑特别隐蔽。Windows 下文本文件的换行符是 CRLF(\r\n),Linux 下是 LF(\n)。如果你在 Windows 编辑了一个 .sh 脚本,然后直接传到 Linux 服务器上运行,很可能会报 bad interpreter 之类的错误,让新手摸不着头脑。
解决办法有两个:在 VSCode 里把右下角的“CRLF”切换成“LF”再保存上传;或者上传到服务器后用工具转换一下:
bash复制dos2unix 脚本名.sh
4.2 断点续传、连接超时与配置文件生效
上传大文件最怕传了一半网络断了。scp 中断就是中断,只能重头再来。rsync 则聪明得多,中断后再次执行相同的命令,它会跳过已传完的部分继续传,这就是我反复推荐 rsync 传大目录的原因。如果你已经用 scp 传到一半失败了,别慌,换 rsync 再跑一遍同样能把剩余部分同步完。
连接超时也是高频问题。你正在终端里敲命令,过几分钟不动,再敲发现卡住了,这是因为 SSH 连接空闲后没活动,被服务端或网络设备关闭了。解决办法是在 SSH 配置里加心跳参数。
在服务器的 /etc/ssh/sshd_config 里设置:
code复制ClientAliveInterval 60
ClientAliveCountMax 3
意思是每 60 秒向客户端发送一次保活探测,连续 3 次无响应才断开。改完重启 SSH 服务:
bash复制sudo systemctl restart sshd
另外,修改服务器配置文件后,有些服务不会自动重新加载。如果你改的是 Nginx 或 Apache 的配置,记得 nginx -t 先做语法检查,再 systemctl reload nginx。改完不重启就判断“配置没用”,这是新手最常见的冤枉路。
4.3 快速自查表
整理一份我在排障时用的速查清单,你也能对照排查:
| 现象 | 可能原因 | 检查命令或手段 |
|---|---|---|
| SSH 连接超时 | 安全组/防火墙未放行 22 端口 | 云控制台检查安全组;本地 telnet 服务器IP 22 |
| 密码正确但登录失败 | 服务器禁用了密码登录 | 查看 /etc/ssh/sshd_config 里 PasswordAuthentication |
| 上传后网页 403 | 文件权限/属主不对 | ls -l 查看属主和权限 |
| 文件上传一半报中断 | 网络不稳定,scp 不能续传 | 改用 rsync -avz --progress |
| 脚本执行报错 | Windows 换行符导致 | dos2unix 转一下格式 |
| 中文文件名乱码 | 本地与服务器编码不一致 | 尽量使用英文字母命名文件 |
| rsync 传完目录层级多了一层 | 源路径末尾斜杠问题 | 先 --dry-run 验证路径结构 |
5. 别只会上传,还要知道文件上传为什么总出安全问题
5.1 文件上传功能为什么是攻击者的“心头好”
“文件上传”这四个字,在开发者的语境里还有一个绕不开的话题:安全。几乎所有现代 Web 应用都有上传功能,比如头像、附件、文档,而每一个带上传功能的接口,都可能成为攻击者的突破口。
原因很简单:服务器会接收并存储用户提交的文件。如果服务器没有严格校验这个文件是什么,攻击者就可能上传一个恶意脚本(比如 PHP 文件)到服务器上,然后通过 URL 访问它,直接在服务器上执行任意代码。这就是网上常说的 WebShell,也是“一句话木马”这类名词的由来。
安全圈里有个非常经典的学习靶场叫 upload-labs,还有一个平台叫 CTFHub,里面专门有一个“文件上传”分类。它们的价值不在于教人怎么攻击,而在于让开发者真正理解“一个上传功能有哪些让人意想不到的漏洞点”。我在团队里带人的时候,会让他们去这里练一遍,目的就是建立防护意识:如果你不知道攻击者会怎么绕过,就不可能写出安全的上传功能。
5.2 你自己开发上传功能时,这几个防线必须到位
如果你在做网站或后端开发,涉及“用户上传文件”的需求,至少要守住这几条底线:
第一,上传接口必须做服务端校验。前端的类型校验根本不算是防护,因为攻击者可以直接用工具绕过前端,发一个任意内容的请求过来。真正的校验必须在服务器端做,包括文件扩展名、MIME 类型和文件内容头。
第二,不要信任文件名。攻击者经常给恶意文件起一个看起来无害的名字,比如 shell.jpg.php、shell.php.jpg。正确做法是上传后服务端随机生成文件名,完全丢弃用户传来的原始文件名。
第三,上传目录和执行权限要隔离。上传的文件只应该在静态文件目录里,该目录不能执行任何脚本,这是最关键的一道防线。比如 Nginx 里可以配置上传目录 location 禁止 PHP 解析:
code复制location /uploads/ {
location ~ \.php$ {
deny all;
}
}
第四,限制文件大小和类型。对图片,可以强制重新编码一遍;对压缩包,可以做内容扫描;对文档,可以用服务端转换格式。这些措施不一定都要上,但根据业务风险等级,至少有意识地选择对应策略。
我见过太多初创项目只顾功能、忽略上传安全,结果被写入恶意文件后整台服务器沦陷。文件上传从来不只是“传上去就完事”,它是一条边界,一条需要认真对待的边界。
