跳到主要内容
孤云

阿里云 OSS:中国大陆 + 备案全套

这条路线代价最大:要自己准备域名、完成 ICP 备案(通常 1–20 个工作日),再给域名配一张 HTTPS 证书;都到位后,剩下的控制台步骤大约 10 分钟。

本文是孤云的官方引导。控制台若显示英文或繁体,按按钮的同义词对照操作即可。

分步操作

  1. 第 1 步

    注册并完成实名验证

    • 没有账号就先注册,并按控制台提示完成实名验证;已有账号可跳过。
    • 两个入口,账号不通用:国际站 www.alibabacloud.com(英文界面为主、国际信用卡或 PayPal);中国站 www.aliyun.com(简体中文、要实名验证、支付宝或微信支付一类)。注册后就用同一个站点的控制台做完下面的步骤。
  2. 第 2 步

    开通 OSS

    • 在控制台搜索「对象存储 OSS」,进入产品页点「立即开通」。
    • 必须勾选协议再确认;开通本身不收费。
  3. 第 3 步

    准备域名并完成备案

    • 域名在境外注册商(GoDaddy、Namecheap 等)要先转入境内注册商,才能提交备案。
    • OSS 不提供备案服务码:先买一台符合条件的内地服务器(ECS 或轻量应用服务器,包年包月且 ≥3 个月、带公网带宽),用它领服务码再提交;审核通常 1–20 个工作日。
  4. 第 4 步

    创建存储桶

    • 在「Bucket 列表」点「创建 Bucket」,填桶名(全球唯一,例如 your-bucket-name)并选一个内地地域。
    • 读写权限选「私有」,「阻止公共访问」保持开启。
  5. 第 5 步

    绑定自定义域名、证书与 CNAME

    • 打开桶的「域名管理」→「绑定域名」,填你的域名,再上传或选择一张 HTTPS 证书。
    • 到域名当前的 DNS 服务商加一条 CNAME 记录,指向 OSS 给出的外网访问域名(以控制台当前界面为准)。
  6. 第 6 步

    创建 RAM 子用户并取密钥

    • 在「访问控制 RAM」→「用户」→「创建用户」,勾选「OpenAPI 调用访问」,不要勾选控制台登录。
    • AccessKey ID 与 Secret 只显示一次,立刻复制保存;不要用主账号密钥。
  7. 第 7 步

    把最小权限策略挂给这个子用户

    • 在「权限管理 → 权限策略」新建自定义策略,切到脚本(JSON)编辑,粘贴下面的策略并把 your-bucket-name 换成真实桶名。
    • 回到用户页面,把这条策略授权给刚才的子用户。
  8. 第 8 步

    回孤云填值并测试连接

    • 在孤云「添加存储」里选「阿里云 OSS」,填桶名、地域、密钥,端点填你的域名(例如 https://oss.example.com)。
    • 地址方式选「自定义域名 CNAME」,再点「测试连接并保存」。

最小权限策略(必做)

在 RAM 里新建自定义策略、切到脚本编辑,粘贴这段 JSON。

json
{
  "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 换成真实桶名。 也不要把资源范围收窄到某个目录:孤云要在 .guyun/ 前缀下写回收站清单与设备记录。

其他情况(用不到可以跳过)

为什么必须自定义域名

阿里云自 2025-03-20 起,新开通 OSS 的账号用默认外网域名访问内地桶的数据类 API(上传、下载)会被拒绝,错误码 PublicEndpointForbidden。

它限制的是域名,不是权限:桶设成私有、不对外提供任何链接,甚至改用 S3 兼容域名,都一样受限。

判断依据是这个账号的 OSS 开通时间,不是建桶时间;老账号后来新建的桶不受限。

备案服务码

  • OSS 不在赠送备案服务码的产品名单里,不能单独申请。
  • 要给 OSS 用的域名备案,得先买一台符合条件的内地服务器:ECS 或轻量应用服务器,包年包月且时长 ≥3 个月、已购公网带宽;免费试用与按量付费的 ECS 都不满足。
  • 备案审核通常 1–20 个工作日。
  • 主域名已备案时,给 OSS 单独用一个子域名(例如 oss.example.com)即可,子域名不用再备案;域名在境外注册商时先转入境内注册商。

ROS 一键模板(可选捷径)

让资源编排(ROS)一次建好私有桶、只授权该桶的 RAM 用户和 AccessKey。

  • 先复制下面的模板全文。
  • 在 ROS 创建页选「指定模板 → 输入模板」粘贴。
  • 必须勾选「安全确认」,否则创建会被拦下。
  • 失败时点资源栈的「事件」看原因,桶名被占用最常见。

ROS 模板

json
{
  "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"
      ]
    }
  }
}

模板建出的资源与权限和手工路线完全相同。

控制台地址

阿里云国际站 https://www.alibabacloud.com/;中国站 https://www.aliyun.com/。

两边界面略有差别,按同义按钮操作即可。

抄下这四个值

它们要填进孤云「添加存储」页对应的格子:

抄下这个值填进孤云的哪一格
桶名
控制台里的桶名,全球唯一,例如 your-bucket-name。
桶名称
地域
桶所在的内地域代码,例如 cn-beijing。
地域
端点
你的域名,例如 https://oss.example.com;地址方式选「自定义域名 CNAME」。
Endpoint
密钥
刚才那个 RAM 子用户的 AccessKey ID 与 Secret。
AccessKey ID 与 Secret

怎么知道成了

  • 孤云返回成功并列出桶的根目录;空桶返回空列表也算成功。
  • 再上传、下载、删除一个小文件,确认这个域名既能读也能写。
  • 连接报错时,到常见错误对照排查。

回到孤云,点「测试连接并保存」。