Alibaba Cloud OSS
About 10 minutes and no cost: prepare a bucket on Alibaba Cloud and a pair of keys that cover that one bucket, so Guyun can use Alibaba Cloud OSS. This is the official Guyun guide; where the console has moved on, the console wins.
New to this? Start with an overseas region such as Hong Kong (cn-hongkong): no domain, ICP filing or certificate is involved. For mainland speed, read the two hard constraints first.
What you need
- An Alibaba Cloud account. If you do not have one, register and verify your identity first (individuals can use an ID card).
- A payment method on file. Activating OSS costs ¥0.00; you pay only for stored bytes, requests and public traffic.
- A globally unique bucket name such as
your-bucket-name: 3–63 lowercase letters, digits and hyphens, starting and ending with a letter or digit. - For a mainland region only: an ICP-filed domain, an HTTPS certificate, and a qualifying mainland server (Simple Application Server or ECS, prepaid for 3 months or more with public bandwidth) to claim a filing service code.
- A computer, ideally: the RAM and AccessKey consoles are much easier to use on a desktop.
On an overseas region you need no domain, no filing, no certificate and no extra server.
Step by step
-
Step 1
Register an Alibaba Cloud account and verify your identity
- Open the Alibaba Cloud sign-up page and register with a phone number or email address.
- Complete identity verification — individuals can use an ID card. OSS can only be activated once it passes.
- For a mainland region, keep the domain, the filing and OSS on the same account; that saves a step later.
-
Step 2
Activate Object Storage Service
- Search the console for Object Storage Service and choose Activate.
- The activation page lists a ¥0.00 order. Tick the agreement checkbox — you cannot continue without it — then continue to payment.
- The amount due is ¥0.00; confirm it and open the console. Activation itself is free.
-
Step 3
Create a bucket
- In the bucket list, choose Create bucket.
- The name is globally unique, for example
your-bucket-name: 3–63 lowercase letters, digits and hyphens, starting and ending with a letter or digit. - Pick the region closest to you and your users. Overseas, Hong Kong (
cn-hongkong) is a good default; for a mainland region read the hard constraints below first. - Set access to private and leave block public access on.
- Use the Standard storage class and leave versioning off — Guyun does not use it.
-
Step 4
Create a RAM user and get its AccessKey
- Open Access Control (RAM) → Identities → Users and choose Create user.
- Tick programmatic access (OpenAPI / permanent AccessKey); on newer consoles it reads “Access via permanent AccessKey”. Do not enable console logon.
- The AccessKey ID and secret are shown once. Copy both immediately; the secret cannot be shown again.
- Never use the root account key, and do not attach
AliyunOSSFullAccess.
-
Step 5
Attach the least-privilege policy
- Under Permissions → Policies, create a custom policy and switch to the script (JSON) editor.
- Paste the policy below and replace
your-bucket-namewith your real bucket name. - Open the user again and attach the new custom policy to it.
- Do not narrow the resource down to one folder. Guyun also writes the trash manifest, device records and cross-device handoff records under the
.guyun/prefix (.guyun/handoff/); narrowing it makes those writes fail. - Do not grant
oss:*, bucket deletion, Bucket ACL changes or version management. Thumbnails areoss:GetObjectand need nothing extra.
-
Step 6
Enter the four values in Guyun
- Open Guyun's Add storage screen and choose Alibaba Cloud OSS.
- Fill in the bucket name, the region (for example
cn-hongkong), the endpoint (https://oss-{region}.aliyuncs.com) and the AccessKey ID and secret. - On an overseas region use the virtual host addressing mode; if you bound a custom domain, set the endpoint to that domain and choose custom domain (CNAME).
- The key stays in this device's Keychain. It is never uploaded or synced — do not paste it into a chat, a document or a repository.
-
Step 7
Test the connection and save
- Go back to Guyun and choose Test connection & save; it only calls ListObjectsV2 to list the root once.
- Reading is not writing. Create a temporary folder in the bucket, then upload, download and delete one file before removing the folder.
- If it fails, match the error against Common errors below.
Four routes
Pick the route that matches what you already have — the work differs a lot.
| Route | What you need | What it costs you | Who it suits |
|---|---|---|---|
Overseas region (e.g. Hong Kong cn-hongkong) | Only OSS and a key pair | Cross-border access from the mainland is a little slower | Recommended for beginners — no ICP filing |
| Mainland region + custom domain | An ICP-filed domain, an HTTPS certificate, and a qualifying mainland server for the filing service code | 1–20 working days for the filing, plus a server you would not otherwise buy | You own a domain and want mainland speed |
| Mainland region + default domain | Only for accounts that activated OSS before 2025-03-20 | Unusable for new accounts; returns PublicEndpointForbidden | Older accounts |
| Skip all this and use ROS | Only OSS | Two extra clicks (copy and paste the template) | You want it done quickly |
Least-privilege RAM policy
Paste this JSON into the custom policy you are creating. It grants read and write on this one bucket and nothing else, and no bucket administration.
{
"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/*"]
}
]
}
Replace your-bucket-name with your real bucket name — missing this one replacement is the most common cause of a 403 for newcomers.
Three rules when attaching the policy
Do not narrow the resource range to one folder. Besides your own files, Guyun writes the trash manifest, device records and short-lived cross-device handoff records under the .guyun/ prefix (.guyun/handoff/). Narrowing it makes those writes fail.
Do not grant oss:* or AliyunOSSFullAccess, and do not allow bucket deletion, Bucket ACL changes or version management. Thumbnails are oss:GetObject; the policy above is enough.
Do not use the root account key. Create a separate RAM user for Guyun and scope it to this one bucket.
The two hard constraints in a mainland region
1. Filing service code: OSS does not provide one. An ICP filing for an OSS domain needs a filing service code, and only qualifying mainland server products hand those out (Simple Application Server or ECS, mainland node, prepaid for 3 months or more with public bandwidth). OSS is not on that list, and trial or pay-as-you-go ECS does not qualify. If the domain is registered with an overseas registrar (GoDaddy, Namecheap, Cloudflare …), transfer it to a mainland registrar first.
2. PublicEndpointForbidden: the default domain is refused. For accounts that activated OSS on or after 2025-03-20, accessing a mainland bucket's data APIs (uploads and downloads included) through a default public endpoint such as oss-cn-hangzhou.aliyuncs.com is rejected. It limits the domain, not the permissions: a private bucket with public access blocked and no shared links is still refused. The test is when OSS was activated, not when the bucket was created, and the S3-compatible endpoint s3.oss-{region}.aliyuncs.com is refused too.
To stay in a mainland region you must bind an ICP-filed custom domain and serve it over HTTPS. Otherwise move the bucket to Hong Kong or another overseas region, where the default endpoint is not restricted.
One-shot route with ROS
If you would rather not click through every step, let Resource Orchestration Service (ROS) build it from the template below in one go: a private bucket with public access blocked, a RAM user limited to that bucket, and that user's AccessKey. Copy the AccessKey ID and secret from the stack outputs when it finishes.
- Open the ROS console at
https://ros.console.aliyun.com/. On an international-site account useros.console.alibabacloud.com. - Copy the whole template below, choose Specify template → Enter template on the create page, set the format to ROS + JSON, paste it in and continue.
- Pitfall 1: dependencies must be explicit. Where the template names the RAM user for the policy and the AccessKey, taking that name from a parameter with
Refdoes not make ROS create a dependency; the template must sayDependsOn: AppUserexplicitly. This one does, and it references the resource attribute withFn::GetAtt. Drop either and creation fails with a validation error such asThe user … is not exists. - Pitfall 2: RAM's
DisplayNameis capped at 12 characters (the documentation says 1–128; the API allows 12, with a Chinese character counting as one). Anything longer is rejected during validation. This template uses the fixed value孤云存储and keeps the bucket name in the comment field. - Pitfall 3: there is a safety confirmation checkbox at the bottom of the create page (“I confirm that Alibaba Cloud ROS may create RAM resources”). Creation is blocked until you tick it. Leave the stack name at its generated default (something like
guyun_2026-09-11_xxxx). - When it fails, open the stack's Events: a taken bucket name is the most common cause;
The Parameter (BucketName) was not defined in templatemeans the template was not pasted (go back to step 1); a missing safety confirmation also blocks creation. - When you build a second bucket in the same account, change the
RAM user nameon the create page from the defaultguyun-appto something else (for exampleguyun-{bucket}); creation fails if that user already exists. - Deleting the stack deletes the bucket and the RAM user with it, so do not delete it once the bucket holds data.
ROS template (verbatim)
Copy the whole thing and paste it into the Enter template box on the ROS create page.
{
"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"
]
}
}
}
This template produces exactly the same resources and permissions as doing it by hand: a private bucket with public access blocked, a policy limited to that bucket, and an AccessKey for that user. The text is right here on the page, so nothing has to be trusted from a third-party host.
Official sources
Console wording changes; these pages are the reference.
- Regions and endpoints (opens in a new tab)
- Access buckets via custom domain names (default-endpoint restriction) (opens in a new tab)
- How to get a filing service code (OSS is not eligible) (opens in a new tab)
- ICP filing for OSS custom domains and subdomains (opens in a new tab)
- PublicEndpointForbidden error (opens in a new tab)
- Use AWS SDKs to access OSS (the S3-compatible endpoint is restricted too) (opens in a new tab)
- Create a RAM user (opens in a new tab)
- ROS: custom stack creation page (opens in a new tab)
- Open the ROS console (opens in a new tab)
The four values to copy
These four go into Guyun's Add storage screen:
| This value | Where it goes in Guyun |
|---|---|
Bucket nameyour-bucket-name (your real bucket) | Bucket name |
Regioncn-hongkong | Region |
Endpointhttps://oss-cn-hongkong.aliyuncs.com | Endpoint |
| Credentials the RAM user's AccessKey ID and secret | AccessKey ID and secret |
How to tell it worked
- Guyun's test connection succeeds and lists the bucket root — an empty bucket returning an empty list counts as success.
- For a full check, create a temporary folder, then upload a file, download it and delete it. All three passing means read and write are both in place.
- None of the common errors appear: no 403, no
PublicEndpointForbidden, noSignatureDoesNotMatch.
Go back to Guyun and choose Test connection & save.
Common errors
Match the code from the test connection against this table.
| Symptom / code | What it means | What to do |
|---|---|---|
403 AccessDenied | The key lacks permission, or the bucket name in the custom policy was never replaced; the policy may also not be attached to this user | Check step 5: that your-bucket-name was replaced, that the policy is attached to this user, and that the key belongs to that user |
PublicEndpointForbidden | Mainland region, default public endpoint, and OSS activated on or after 2025-03-20 | Bind an ICP-filed custom domain (the endpoint becomes that domain and the addressing mode becomes CNAME), or move the bucket to Hong Kong or another overseas region |
SignatureDoesNotMatch / InvalidAccessKeyId | The key was copied wrong, or the secret was never saved when it was shown once; the ID and secret may also come from two different pairs | Create a fresh AccessKey on the RAM user and copy both values into Guyun together |
| Connection test passes but uploads fail | The test only called ListObjectsV2 — reading is not writing | Check that the policy grants oss:PutObject / oss:DeleteObject, then upload, download and delete one file in a temporary folder |
If the code is not in the table, keep the full error text and the request ID — support tickets need them.