在Linux和类Unix系统中,scp(Secure Copy)是基于SSH协议的轻量安全文件传输工具,核心优势是无需额外配置、原生加密,适用于本地与远程、跨远程主机的文件/目录复制。
一、基础原理与安全机制
1. 核心依赖与加密逻辑
- 基于SSH协议(默认端口22),依赖OpenSSH客户端(
openssh-client),远程服务器需启用sshd服务。 - 加密链路:采用SSH的端到端加密(默认AES-256),传输内容(文件数据、认证信息)均不会明文暴露,安全性优于FTP等工具。
- 与
sftp的区别:scp专注"复制",sftp侧重"交互式文件管理"(如新建目录、删除文件),二者共享SSH认证体系。
2. 认证方式
| 认证方式 | 操作方式 | 安全性 | 关键注意事项 |
|---|---|---|---|
| 密码认证 | 交互式输入密码 | 中 | 密码不会明文传输,但可能被服务器日志记录;需启用PasswordAuthentication yes(sshd配置) |
| 密钥认证 | 基于SSH密钥对无密码登录 | 高 | 推荐生产环境使用,步骤如下: 1. 生成密钥对(兼容新旧系统): ssh-keygen -t ed25519 -C "备注"(优先,高效安全) ssh-keygen -t rsa -b 4096 -C "备注"(兼容老系统) 2. 上传公钥到远程:ssh-copy-id -p 22 user@remote(非默认端口需指定) 3. 私钥权限必须为600:chmod 600 ~/.ssh/id_ed25519(权限过宽会被SSH拒绝) |
3. 权限与属性继承
- 默认行为:保留文件权限(
rwx),但所有者/组会变为目标主机的登录用户。 (-p)选项:保留修改时间(mtime)、访问时间(atime)、权限模式 ,但不保留ACL权限和SELinux上下文 (需额外用--preserve=all或rsync)。- 例外:SUID/SGID位、特殊设备文件(如
/dev/sda)无法通过scp完整复制,需用dd或rsync -a。
二、核心语法与路径格式
1. 基础语法
bash
scp [选项] [源路径] [目标路径]
- 核心规则:源路径是"要复制的文件/目录",目标路径是"复制到的位置" (本地路径直接写,远程路径需带
user@host:前缀)。 - 关键提醒:
scp的端口选项是大写-P(与ssh -p相反),避免混淆!
2. 路径格式全场景示例
| 场景 | 命令示例 | 关键说明 |
|---|---|---|
| 本地文件 → 远程目录 | scp /local/file.txt user@192.168.1.100:/remote/dir/ |
目标目录需以/结尾,否则会把文件重命名为dir |
| 本地目录 → 远程目录(递归) | scp -r /local/dir/ user@remote:/remote/ |
必须加-r,本地目录结尾加/表示复制目录内内容,不加则复制目录本身 |
| 远程文件 → 本地目录 | scp user@remote:/remote/file.log /local/backup/ |
本地目录不存在会报错,需提前创建(mkdir -p /local/backup) |
| 远程目录 → 本地目录(递归) | scp -r user@remote:/remote/dir/ /local/ |
同上,远程目录结尾/的含义一致 |
| 远程→远程(本地中转) | scp user1@host1:/file user2@host2:/dir/ |
依赖本地网络带宽,适合两台远程主机无法直接通信的场景 |
| 远程→远程(直接通信) | scp -3 user1@host1:/file user2@host2:/dir/ |
加-3强制本地中转;不加则尝试两台远程主机直接通信(需互信) |
| 含特殊字符的路径 | scp 'user@remote:/path/file with space.txt' /local/ |
用单引号包裹,或用反斜杠转义:file\ with\ space.txt |
| 通配符批量传输 | scp user@remote:/data/{a,b,c}.txt /local/ |
支持花括号扩展、*.log、[0-9].txt等通配符 |
| 从文件列表批量传输 | scp --files-from=file_list.txt user@remote:/dir/ |
file_list.txt中每行一个文件路径(本地/远程均可),适合大量文件传输 |
3. 端口与密钥指定
bash
# 1. 非标准SSH端口(如2222)
scp -P 2222 /local/file user@remote:/dir/
# 2. 指定自定义私钥(如非默认路径的密钥)
scp -i ~/.ssh/work_key user@remote:/file /local/
# 3. 同时指定端口和密钥
scp -P 2222 -i ~/.ssh/work_key /local/file user@remote:/dir/
三、常用选项(补充示例+使用场景)
| 选项 | 作用 | 实操示例 |
|---|---|---|
-r |
递归复制目录(必选,否则仅复制目录名) | scp -r /local/project user@remote:/var/www/ |
-P <端口> |
指定SSH端口(大写!小写-p是保留属性) |
scp -P 2222 file.txt user@remote:/tmp/ |
-i <密钥> |
指定私钥文件(解决默认密钥不匹配问题) | scp -i ~/.ssh/aws_key user@aws-host:/data/ |
-p |
保留文件属性(mtime/atime/权限) | scp -p /etc/nginx/nginx.conf user@remote:/etc/nginx/ |
-q |
安静模式(不显示进度,仅输出错误) | scp -q -r /local/backup user@remote:/data/(适合脚本) |
-C |
启用压缩(文本文件提速明显,二进制文件效果有限) | scp -C /local/logs.tar.gz user@remote:/backups/ |
-l <速率> |
限制传输速率(单位Kbit/s,1KB/s=8Kbit/s) | scp -l 8192 large.iso user@remote:/dir/(限制1MB/s) |
-v |
详细模式(调试用,显示SSH连接、认证、传输细节) | scp -v file.txt user@remote:/tmp/(排查连接失败) |
-o <选项> |
传递SSH参数(绕过常见限制) | scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null file.txt user@remote:/tmp/(临时连接陌生主机,跳过密钥检查) |
-F <配置> |
指定SSH配置文件(多环境隔离) | scp -F ~/.ssh/config_test file.txt test-server:/tmp/ |
四、高级用法与技巧
1. SSH配置简化
在~/.ssh/config中配置主机别名(权限需为600:chmod 600 ~/.ssh/config),支持多环境快速切换:
config
# 生产环境服务器
Host prod
HostName 10.0.0.10
User deploy
Port 2222
IdentityFile ~/.ssh/prod_ed25519
ServerAliveInterval 30 # 每30秒发心跳,防止连接超时
Compression yes # 默认启用压缩
# 测试环境服务器
Host test
HostName 192.168.1.20
User tester
Port 22
IdentityFile ~/.ssh/test_rsa
使用简化命令:
bash
scp -r /local/project prod:/var/www/ # 无需输入IP、端口、密钥路径
scp test:/var/log/app.log /local/ # 远程下载同样简化
2. 传输进度显示
scp原生无进度条,但可通过以下3种方式实现,按需选择:
-
方案1:
pv工具(推荐,直观)bash# 上传(显示进度、速率、剩余时间) pv /local/large_file.iso | ssh -p 2222 user@remote "cat > /remote/large_file.iso" # 下载 ssh -p 2222 user@remote "pv /remote/large_file.iso" | cat > /local/large_file.iso安装
pv:sudo apt install pv(Debian/Ubuntu)、sudo dnf install pv(CentOS/RHEL)。 -
方案2:
rsync替代(支持进度+断点续传)bashrsync -avzP -e "ssh -p 2222" /local/file user@remote:/dir/-P=--progress(进度条) +--partial(保留部分传输文件)。 -
方案3:原生
scp -v(间接查看)bashscp -v /local/file user@remote:/dir/详细输出中会显示"bytes sent/received",间接判断传输进度(适合无
pv环境)。
3. 断点续传(优化scp替代方案)
scp本身不支持断点续传,除了rsync,还可通过dd命令实现(适合大文件):
bash
# 1. 先查看已传输的文件大小(远程主机)
ssh user@remote "du -b /remote/large_file.iso" # 输出:104857600 large_file.iso(已传100MB)
# 2. 本地继续上传剩余部分(跳过前100MB)
dd if=/local/large_file.iso bs=1M skip=100 | ssh user@remote "dd of=/remote/large_file.iso bs=1M seek=100"
if:输入文件;of:输出文件;bs=1M:块大小1MB;skip:本地跳过已传部分;seek:远程跳过已传部分。
4. 批量传输优化
-
从文件列表传输 :将需要传输的文件路径写入
file_list.txt(每行一个),批量传输:bashscp --files-from=file_list.txt user@remote:/data/ -
排除指定文件 :
scp本身不支持--exclude,可结合tar打包后传输(适合目录传输):bash# 本地打包(排除log和tmp目录)→ 远程解压 tar -czf - --exclude='*.log' --exclude='tmp/' /local/project | ssh user@remote "tar -xzf - -C /remote/"
5. 跨网段/低带宽优化
-
启用压缩+限制速率:
bashscp -C -l 4096 /local/large.tar.gz user@remote:/dir/ # 限制512KB/s(4096 Kbit/s ÷8) -
关闭SSH压缩(二进制文件场景):
bashscp -o Compression=no /local/video.mp4 user@remote:/dir/ # 避免压缩耗时反而降速
五、常见问题与解决方案
1. 连接被拒绝(Connection refused)
| 可能原因 | 解决方案 |
|---|---|
| SSH服务未运行 | 远程主机执行:sudo systemctl start sshd(CentOS)/ sudo systemctl start ssh(Ubuntu) |
| 端口被防火墙拦截 | 远程主机开放端口: sudo ufw allow 2222(Ubuntu) sudo firewall-cmd --add-port=2222/tcp --permanent && sudo firewall-cmd --reload(CentOS) |
| 端口号错误 | 确认远程SSH端口(`cat /etc/ssh/sshd_config |
| 远程主机不可达 | 先测试连通性:ping remote_host、telnet remote_host 2222 |
2. 权限不足(Permission denied)
| 可能原因 | 解决方案 |
|---|---|
| 目标目录不可写 | 1. 上传到临时目录再移动: scp file.txt user@remote:/tmp/ && ssh user@remote "sudo mv /tmp/file.txt /opt/protected/" 2. 给目标目录添加ACL权限: ssh user@remote "sudo setfacl -m u:user:rwx /opt/protected/" |
| 私钥权限过宽 | 私钥必须为600:chmod 600 ~/.ssh/id_ed25519(SSH拒绝权限≥644的私钥) |
| 远程用户无读取源文件权限 | 确保远程用户能访问源文件:ssh user@remote "ls -l /remote/file.txt"(无权限则用sudo打包) |
3. 传输超时/中断
-
解决方案1:添加SSH心跳(客户端),在
~/.ssh/config中添加:configServerAliveInterval 30 ServerAliveCountMax 5 # 5次心跳失败才断开 -
解决方案2:服务器端配置(需root),修改
/etc/ssh/sshd_config:configClientAliveInterval 60 # 服务器每60秒发心跳 ClientAliveCountMax 3重启sshd:
sudo systemctl restart sshd。
4. 主机密钥验证失败(Host key verification failed)
-
原因:远程主机密钥变更(如重装系统、IP复用),本地
~/.ssh/known_hosts记录冲突。 -
解决方案:
bash# 方法1:删除指定主机的旧密钥(推荐) ssh-keygen -R remote_host # 或指定IP:ssh-keygen -R 192.168.1.100 # 方法2:临时跳过密钥检查(不推荐生产环境) scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null file.txt user@remote:/dir/
六、与其他传输工具的对比
| 工具 | 核心优势 | 劣势 | 传输速度 | 支持增量 | 支持断点续传 | 适用场景 |
|---|---|---|---|---|---|---|
scp |
简单易用、原生SSH、无额外依赖 | 无进度条、不支持增量/断点 | 中等(单线程) | ❌ | ❌ | 小文件/目录、一次性传输 |
rsync |
增量传输、断点续传、进度条、灵活过滤 | 语法稍复杂、需额外安装 | 快(支持压缩+增量) | ✅ | ✅ | 大文件、频繁同步、目录备份 |
sftp |
交互式操作、支持文件管理(增删改查) | 不适合批量复制、无进度条 | 中等 | ❌ | ❌ | 需手动选择文件、远程文件管理 |
curl/wget |
支持HTTP/HTTPS/FTP、适合公开资源 | 需服务器支持对应服务、安全性依赖协议 | 中等 | ❌ | 部分支持(-c选项) |
从Web服务器下载公开文件 |
lrzsz(rz/sz) |
简单拖拽(SSH客户端支持) | 传输速率低、不支持大文件 | 慢 | ❌ | ❌ | 小文件、本地与SSH客户端直接传输 |
七、安全实践(强化生产环境适配)
1. 强制密钥认证,禁用密码登录
修改远程服务器/etc/ssh/sshd_config(需root):
config
PasswordAuthentication no # 禁用密码认证
PubkeyAuthentication yes # 启用密钥认证
ChallengeResponseAuthentication no # 禁用挑战响应认证
- 关键提醒:修改前务必确保已上传公钥(
ssh-copy-id),否则会无法登录! - 重启sshd:
sudo systemctl restart sshd。
2. 限制SSH用户与访问范围
-
创建专用传输用户(无登录权限):
bashsudo useradd -m -s /bin/false scp_user # /bin/false禁止登录,仅用于传输 sudo passwd scp_user # 可选,若需临时密码(但已禁用密码认证) -
配置Chroot环境(限制用户仅访问指定目录):
config# /etc/ssh/sshd_config 新增 Subsystem sftp internal-sftp Match User scp_user ChrootDirectory /data/scp_root # 限制根目录 ForceCommand internal-sftp # 仅允许sftp/scp,禁止SSH登录 AllowTcpForwarding no X11Forwarding no配置后需设置目录权限:
sudo chown root:root /data/scp_root && sudo chmod 755 /data/scp_root。
3. 审计与日志监控
-
查看传输日志(记录所有scp/sftp操作):
bash# Debian/Ubuntu sudo grep -E "scp|sftp" /var/log/auth.log # CentOS/RHEL sudo grep -E "scp|sftp" /var/log/secure # 实时监控 sudo journalctl -u sshd -f | grep -E "session opened|session closed" -
关键日志字段:
user(操作用户)、from(来源IP)、command(操作类型:scp/sftp)。
4. 其他安全建议
- 定期更换SSH密钥(每年至少1次):重新生成密钥对,替换远程主机
~/.ssh/authorized_keys中的旧公钥。 - 禁用root用户SSH访问:
sshd_config中设置PermitRootLogin no,通过普通用户sudo执行管理员操作。 - 使用非默认SSH端口:将
Port 22改为Port 2222等,减少暴力破解尝试(需同步防火墙配置)。
快速参考表(常用命令速查)
| 需求 | 命令示例 |
|---|---|
| 本地文件上传到远程 | scp /local/file.txt user@remote:/dir/ |
| 本地目录上传到远程 | scp -r /local/dir user@remote:/dir/ |
| 远程文件下载到本地 | scp user@remote:/dir/file.txt /local/ |
| 远程目录下载到本地 | scp -r user@remote:/dir /local/ |
| 指定端口+密钥上传 | scp -P 2222 -i ~/.ssh/key /local/file user@remote:/dir/ |
| 批量下载远程txt文件 | scp user@remote:/dir/*.txt /local/ |
| 压缩传输大文本文件 | scp -C /local/logs.tar.gz user@remote:/dir/ |
| 限制传输速率(1MB/s) | scp -l 8192 /local/large.iso user@remote:/dir/ |
| 简化命令(SSH配置) | scp /local/file prod:/var/www/ |
scp是Linux系统中最基础、零配置的安全传输工具,适合简单的一次性文件/目录复制场景。其核心价值在于"原生SSH集成",无需额外部署服务,安全性有保障。
- 小文件/一次性传输 → 用
scp(简单高效); - 大文件/增量同步/断点续传 → 用
rsync(功能更强); - 交互式远程文件管理 → 用
sftp(操作灵活)。
掌握-r(递归)、-P(端口)、-i(密钥)、-p(保留属性)四大核心选项,结合SSH配置简化命令,可大幅提升传输效率。生产环境中务必启用密钥认证、限制用户权限,通过日志审计强化安全管控。