阿里云 OSS
大约 10 分钟、不需要花钱,就能在阿里云上给孤云准备好一个存储桶,以及一对只授权这个桶的密钥。本文是官方引导;控制台界面请以你打开时为准。
新手建议从海外地域(例如香港 cn-hongkong)开始:不需要域名、备案或证书。想要内地速度,先读「内地地域的两个硬约束」。
要准备什么
- 一个阿里云账号;没有就先注册,并完成实名认证(个人可用身份证)。
- 一个付款方式。开通 OSS 本身是 ¥0.00;费用只产生在实际存储量、请求次数与外网流量上。
- 一个全局唯一的桶名,例如
your-bucket-name:3–63 位小写字母、数字和短横线,首尾必须是字母或数字。 - 只有内地路线才需要:一个已完成 ICP 备案的域名、HTTPS 证书,以及一台符合条件的内地服务器(轻量应用服务器 / ECS,包年包月 ≥3 个月、带公网带宽)用来领取备案服务码。
- 建议用电脑操作:RAM 与 AccessKey 的控制台在电脑上顺手得多。
只走海外地域的话,不需要域名、备案、证书,也不需要多买服务器。
分步操作
-
第 1 步
注册阿里云账号并完成实名认证
- 打开阿里云注册页,用手机号或邮箱注册。
- 完成实名认证(个人可用身份证);认证通过后才能开通 OSS。
- 内地路线建议把域名、备案与 OSS 放在同一个账号,后面少一步。
-
第 2 步
开通对象存储 OSS
- 在控制台搜「对象存储 OSS」,进入产品页点「立即开通」。
- 开通页列出的订单金额是 ¥0.00;必须勾选「我已阅读并同意…专属条款」,再点「去支付」。
- 支付页确认金额 ¥0.00,完成后点「管理控制台」进入 OSS 控制台。开通本身不收费。
-
第 3 步
创建存储桶(Bucket)
- 在「Bucket 列表」点「创建 Bucket」。
- 桶名全局唯一,例如
your-bucket-name:3–63 位小写字母、数字和短横线,首尾必须是字母或数字。 - 地域选离你和主要使用者最近的。海外建议香港
cn-hongkong;内地请先读下面的硬约束。 - 读写权限选「私有」,「阻止公共访问」保持开启。
- 存储类型用「标准」,版本控制保持关闭(孤云不使用多版本)。
-
第 4 步
创建 RAM 子用户并取密钥
- 进入「访问控制 RAM」→「身份管理 → 用户」→「创建用户」。
- 勾选「OpenAPI 调用访问」(较新的界面写作「使用永久 AccessKey 访问」)—— 都是指用 AccessKey 调用;不要勾选控制台登录。
- 创建完成后,AccessKey ID 与 Secret 只显示一次,立刻复制保存;关掉页面就再也看不到 Secret。
- 不要使用主账号(根账号)密钥,也不要挂
AliyunOSSFullAccess。
-
第 5 步
挂最小权限策略
- 在「权限管理 → 权限策略」里新建一条自定义策略,切到脚本(JSON)编辑方式。
- 粘贴下面的最小权限策略,把
your-bucket-name换成你的真实桶名。 - 回到用户页面,把这条自定义策略授权给刚才建的子用户。
- 不要把资源范围收窄到某个目录:孤云还要在
.guyun/前缀下写回收站清单、设备连接记录,以及跨设备交接用的.guyun/handoff/;收窄会让这些写入失败。 - 不要授予
oss:*、删桶、改 Bucket ACL 或管理历史版本;缩略图属于oss:GetObject,不需要额外权限。
-
第 6 步
把四个值填进孤云
- 打开孤云的「添加存储」,服务商选「阿里云 OSS」。
- 填:Bucket 名称 = 你的桶名;地域 = 桶所在地域(例如
cn-hongkong);Endpoint =https://oss-{地域}.aliyuncs.com;AccessKey ID 与 Secret = 刚才那对密钥。 - 海外地域的地址方式用「Bucket 子域名」;绑了自定义域名就把 Endpoint 改成你的域名,地址方式选「自定义域名 CNAME」。
- 密钥只保存在本机 Keychain,不上传、不同步;不要贴到聊天、文档或代码里。
-
第 7 步
测试连接并保存
- 回到孤云点「测试连接并保存」,它只调用 ListObjectsV2 列出一次根目录。
- 读得通不代表写得进:建议在桶里建一个临时目录,做一次上传 / 下载 / 删除,再把临时目录删掉。
- 连不上时对照下面的「常见错误」,按错误码排查。
四条路径
先挑一条符合你现有条件的路线 —— 各条的接入工作量差别很大。
| 路径 | 需要准备 | 代价 | 适合谁 |
|---|---|---|---|
海外地域(如香港 cn-hongkong) | 只要 OSS 与一对密钥 | 内地访问跨境,速度略慢 | 推荐新手,没有备案问题 |
| 内地地域 + 自定义域名 | 已备案的域名 + HTTPS 证书 + 一台符合条件的内地服务器(换备案服务码) | 备案要 1–20 个工作日,还要额外买服务器 | 有域名、要内地速度的人 |
| 内地地域 + 默认域名 | 仅限 2025-03-20 之前开通 OSS 的账号 | 新账号不可用,会报 PublicEndpointForbidden | 老账号 |
| 不想看这些,走 ROS | 只要 OSS | 多两次点击(复制并粘贴模板) | 想省事的人 |
最小权限 RAM 策略
把这段 JSON 粘进你正在新建的自定义策略(脚本编辑)。它只授权这一个桶的读写,不含删桶与 Bucket 配置。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": ["oss:ListObjects", "oss:GetBucketLocation", "oss:ListMultipartUploads"],
"Resource": ["acs:oss:*:*:your-bucket-name"]
},
{
"Effect": "Allow",
"Action": ["oss:GetObject", "oss:PutObject", "oss:DeleteObject", "oss:AbortMultipartUpload", "oss:ListParts"],
"Resource": ["acs:oss:*:*:your-bucket-name/*"]
}
]
}
把 your-bucket-name 换成真实桶名 —— 这一处没替换是新手最常见的 403 原因。
挂策略时的三条红线
不要把资源范围收窄到某个目录。 除了你自己的文件,孤云还要在 .guyun/ 前缀下写回收站清单、设备连接记录,以及跨设备交接用的短命记录 .guyun/handoff/;收窄会让这些写入失败。
不要授予 oss:* 或 AliyunOSSFullAccess,也不要允许删桶、改 Bucket ACL 或管理历史版本。 缩略图属于 oss:GetObject,上面的策略已经够用。
不要使用主账号密钥。 给孤云单独建一个 RAM 子用户,只授权这一个桶。
内地地域的两个硬约束
① 备案服务码:OSS 不提供。 给 OSS 的域名办备案时要选一个备案服务码,而服务码只由符合条件的内地服务器产品赠送(轻量应用服务器 / ECS,内地节点、包年包月且时长 ≥3 个月、已购公网带宽)。OSS 不在名单里,免费试用与按量付费的 ECS 也不符合条件。域名若在境外注册商(GoDaddy、Namecheap、Cloudflare 等),还要先转入境内注册商才能备案。
② PublicEndpointForbidden:默认外网域名被拒。 2025-03-20 起新开通 OSS 的账号,用默认外网域名(例如 oss-cn-hangzhou.aliyuncs.com)访问内地 Bucket 的数据类 API(上传、下载都算)一律被拒。它限制的是域名,不是权限:桶设为私有、阻止公共访问、不对外提供任何链接,一样受限;判断依据是 OSS 的开通时间,不是建桶时间,与桶权限无关;S3 兼容域名 s3.oss-{地域}.aliyuncs.com 同样受限。
要留在内地地域,就得绑定一个已备案的自定义域名(并配置 HTTPS 证书);否则请换香港或其他海外地域 —— 那里的默认域名不受这条限制。
ROS 一键路线:一次建好桶、RAM 用户和密钥
不想一步步点,就让阿里云的资源编排(ROS)按下面这份模板一次建好:私有且阻止公共访问的桶、只授权该桶的 RAM 用户,以及这个用户的 AccessKey。完成后从资源栈的「输出」里复制 AccessKey ID 与 Secret。
- 打开 ROS 控制台:
https://ros.console.aliyun.com/。国际站账号用ros.console.alibabacloud.com。 - 复制下面的模板全文,在创建页选「指定模板 → 输入模板」,模板内容格式选 ROS + JSON,粘贴进去再点下一步。
- 坑 1:依赖要显式写。 模板里给策略与 AccessKey 指定 RAM 用户时,用
Ref取参数里的用户名不会让 ROS 自动建立依赖,必须显式写DependsOn: AppUser(这份模板里已经写好,并用Fn::GetAtt引用资源属性);改模板时把这两处丢掉,会报The user … is not exists一类的校验错误。 - 坑 2:RAM 的
DisplayName上限是 12 个字符(官方文档写 1–128,实际 API 只允许 12,中文按 1 个算)。超过会在校验阶段被拦下;这份模板用的是固定值「孤云存储」,桶名放在备注里。 - 坑 3:创建页下方有一个「安全确认」勾选框(「我确认,阿里云 ROS 可能创建 RAM 资源」),不勾选无法创建。资源栈名保持默认即可(形如
guyun_2026-09-11_xxxx)。 - 失败时点资源栈的「事件」看原因:桶名被占用最常见;报
The Parameter (BucketName) was not defined in template说明模板没粘进去(回第 1 步重来);漏勾「安全确认」也会被拦下。 - 同一账号里再建一个桶时,把创建页里的
RAM 用户名从默认的guyun-app改成别的(例如guyun-{bucket})—— 同名用户已存在时创建会失败。 - 删资源栈会连同它建的桶与 RAM 用户一起删掉,桶里有数据时不要随手删。
ROS 模板(原文)
复制全文,粘贴到 ROS 创建页的「输入模板」里。
{
"ROSTemplateFormatVersion": "2015-09-01",
"Description": {
"zh-cn": "为孤云创建:私有且阻止公共访问的 OSS Bucket、只授权该桶读写的 RAM 用户、以及该用户的 AccessKey。AccessKey ID 与 Secret 会出现在资源栈的「输出」里,复制回应用即可。",
"en": "Creates, for Guyun: a private OSS bucket with public access blocked, a RAM user limited to that bucket, and an AccessKey for it. The AccessKey ID and secret appear in the stack outputs; copy them back into the app."
},
"Parameters": {
"BucketName": {
"Type": "String",
"Label": {
"zh-cn": "Bucket 名称",
"en": "Bucket name"
},
"Description": {
"zh-cn": "全局唯一。3–63 位,只能用小写字母、数字和短横线,首尾必须是字母或数字。例如 my-photos-2026。",
"en": "Globally unique. 3–63 characters: lowercase letters, digits and hyphens, starting and ending with a letter or digit. For example my-photos-2026."
},
"AllowedPattern": "^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$",
"MinLength": 3,
"MaxLength": 63
},
"RamUserName": {
"Type": "String",
"Label": {
"zh-cn": "RAM 用户名",
"en": "RAM user name"
},
"Description": {
"zh-cn": "给应用专用的子账号。如果账号下已经有同名用户,请改成别的名字再创建。",
"en": "A dedicated sub-account for the app. If a user with this name already exists, pick another one."
},
"Default": "guyun-app",
"AllowedPattern": "^[a-zA-Z0-9._-]{1,64}$",
"MinLength": 1,
"MaxLength": 64
}
},
"Resources": {
"Bucket": {
"Type": "ALIYUN::OSS::Bucket",
"Properties": {
"BucketName": {
"Ref": "BucketName"
},
"AccessControl": "private",
"StorageClass": "Standard",
"BlockPublicAccess": true
}
},
"AppUser": {
"Type": "ALIYUN::RAM::User",
"Properties": {
"UserName": {
"Ref": "RamUserName"
},
"DisplayName": {
"Fn::Sub": "孤云存储"
},
"Comments": {
"Fn::Sub": "孤云专用存储用户;授权桶 ${BucketName} 的读写;随资源栈删除。"
}
}
},
"BucketPolicy": {
"Type": "ALIYUN::RAM::ManagedPolicy",
"DependsOn": "AppUser",
"Properties": {
"PolicyName": {
"Fn::Sub": "guyun-${BucketName}-rw"
},
"Description": {
"Fn::Sub": "Guyun: read and write ${BucketName} only. No bucket-level administration."
},
"PolicyDocument": {
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:ListObjects",
"oss:GetBucketLocation",
"oss:ListMultipartUploads"
],
"Resource": [
{
"Fn::Sub": "acs:oss:*:*:${BucketName}"
}
]
},
{
"Effect": "Allow",
"Action": [
"oss:GetObject",
"oss:PutObject",
"oss:DeleteObject",
"oss:AbortMultipartUpload",
"oss:ListParts"
],
"Resource": [
{
"Fn::Sub": "acs:oss:*:*:${BucketName}/*"
}
]
}
]
},
"Users": [
{
"Fn::GetAtt": [
"AppUser",
"UserName"
]
}
]
}
},
"AccessKey": {
"Type": "ALIYUN::RAM::AccessKey",
"DependsOn": "AppUser",
"Properties": {
"UserName": {
"Fn::GetAtt": [
"AppUser",
"UserName"
]
}
}
}
},
"Outputs": {
"BucketName": {
"Label": {
"zh-cn": "Bucket 名称",
"en": "Bucket name"
},
"Description": {
"zh-cn": "填到应用的「Bucket 名称」里。",
"en": "Paste into the app's bucket name field."
},
"Value": {
"Ref": "BucketName"
}
},
"RegionId": {
"Label": {
"zh-cn": "地域",
"en": "Region"
},
"Description": {
"zh-cn": "资源栈所在地域,也就是 Bucket 的地域。",
"en": "The stack's region, which is the bucket's region."
},
"Value": {
"Ref": "ALIYUN::Region"
}
},
"Endpoint": {
"Label": {
"zh-cn": "HTTPS Endpoint",
"en": "HTTPS endpoint"
},
"Description": {
"zh-cn": "走默认域名时填到应用的「HTTPS Endpoint」里(地址方式选「Bucket 子域名」);如果之后绑了自定义域名,Endpoint 要改成那个域名。",
"en": "With the default endpoint, paste this into the app's HTTPS endpoint field (addressing: virtual host). If you bind a custom domain later, the endpoint becomes that domain instead."
},
"Value": {
"Fn::Sub": "https://oss-${ALIYUN::Region}.aliyuncs.com"
}
},
"AccessKeyId": {
"Label": {
"zh-cn": "AccessKey ID",
"en": "AccessKey ID"
},
"Description": {
"zh-cn": "复制后填到应用的「AccessKey ID」里。",
"en": "Copy into the app's AccessKey ID field."
},
"Value": {
"Fn::GetAtt": [
"AccessKey",
"AccessKeyId"
]
}
},
"AccessKeySecret": {
"Label": {
"zh-cn": "AccessKey Secret",
"en": "AccessKey secret"
},
"Description": {
"zh-cn": "只在这里显示,复制后填进应用的 Keychain;不要粘贴到聊天、文档或代码里。",
"en": "Shown here only. Copy it into the app's Keychain; never paste it into a chat, document or repository."
},
"Value": {
"Fn::GetAtt": [
"AccessKey",
"AccessKeySecret"
]
}
}
},
"Metadata": {
"ALIYUN::ROS::Interface": {
"ParameterGroups": [
{
"Parameters": [
"BucketName"
],
"Label": {
"default": "OSS"
}
},
{
"Parameters": [
"RamUserName"
],
"Label": {
"default": "RAM"
}
}
],
"Outputs": [
"BucketName",
"RegionId",
"Endpoint",
"AccessKeyId",
"AccessKeySecret"
]
}
}
}
这份模板与上面的手工路线做出完全一样的资源和权限:私有且阻止公共访问的桶、只授权该桶的策略、为该用户创建的 AccessKey。模板内容就在本页,不需要信任任何第三方托管。
官方来源
控制台文案会变,这几页是查证依据。
- 地域与外网 Endpoint 总表 (在新窗口打开)
- 通过自定义域名访问 OSS(内地域默认域名的限制) (在新窗口打开)
- 如何获取备案服务码(OSS 不在名单里) (在新窗口打开)
- OSS 自定义域名的备案要求与子域名规则 (在新窗口打开)
- PublicEndpointForbidden 错误说明 (在新窗口打开)
- 用 AWS SDK 访问 OSS(S3 兼容端点同样受限) (在新窗口打开)
- 创建 RAM 用户 (在新窗口打开)
- ROS:自定义创建资源栈页面 (在新窗口打开)
- 打开 ROS 控制台 (在新窗口打开)
抄下这四个值
这四个值要填进孤云的「添加存储」页:
| 抄下这个值 | 填进孤云的哪一格 |
|---|---|
桶名your-bucket-name(换成你的真实桶名) | 桶名称 |
地域cn-hongkong | 地域 / Region |
端点https://oss-cn-hongkong.aliyuncs.com | Endpoint |
| 密钥 RAM 子用户的 AccessKey ID 与 Secret | AccessKey ID 与 Secret |
怎么知道成了
- 孤云的「测试连接并保存」返回成功,能列出桶的根目录(空桶返回空列表也算成功)。
- 想完整验证:在桶里建一个临时目录,上传一个文件、下载一次、再删掉 —— 三步都通过,读写权限就齐了。
- 常见错误都不出现:没有 403,没有
PublicEndpointForbidden,没有SignatureDoesNotMatch。
回到孤云,点「测试连接并保存」。
常见错误
在「测试连接并保存」里看到这些错误码时,按下面的顺序排查。
| 现象 / 错误码 | 含义 | 怎么办 |
|---|---|---|
403 AccessDenied | 密钥没权限,或自定义策略里的桶名没替换成真实桶名;也可能策略没授权给这个子用户 | 回第 5 步核对:your-bucket-name 是否已替换、策略是否挂在这个用户上、密钥是否属于该用户 |
PublicEndpointForbidden | 内地域 + 默认外网域名 + OSS 在 2025-03-20 之后开通 | 绑定已备案的自定义域名(Endpoint 换成该域名、地址方式选 CNAME),或把桶换到香港 / 其他海外地域 |
SignatureDoesNotMatch / InvalidAccessKeyId | 密钥复制错了(Secret 只显示一次,没存下就再也拿不到),或 ID 与 Secret 不是同一对 | 在 RAM 用户下重新创建一对 AccessKey,把两个值一起复制回孤云 |
| 连接测试通过,但上传失败 | 测试只调用了 ListObjectsV2 —— 读得通不代表写得进 | 确认策略里有 oss:PutObject / oss:DeleteObject,再在临时目录里做一次上传 / 下载 / 删除 |
错误码不在表里时,把完整报错和 Request ID 一起记下来 —— 提工单时要用。