The CloudFront China Exit Method: S3 Static Sites to OSS + CDN
We rehearsed the full CloudFront China exit on live accounts — CDN front, S3-to-OSS migration, private origin auth, cache refresh — and verified it by byte parity between both endpoints.
Amazon has set the date: CloudFront in the AWS China partition stops working on May 31, 2027, and the partition stopped accepting new CloudFront customers on September 30, 2026 (official notice). AWS’s own migration guide is honest about the shape of the exit — pick a CDN from AWS Marketplace China, keep your origins, switch DNS — and silent about everything that actually breaks on the way: origin Host semantics, private-bucket authentication, metadata parity, cache-key behavior, and how you prove the copy is complete.
So we ran the exit as a rehearsal, on live accounts, end to end: an S3 static website in the Beijing region, moved to Alibaba Cloud OSS with a CDN in front, private origin authentication on, HTTPS via Let’s Encrypt, every stage measured. Both endpoints of that rehearsal are still live and byte-identical:
- The origin side, fronted by a new CDN: https://demo.aws.launchready.cn/index.html
- The migrated side, OSS + CDN with private origin auth: https://demo.aliyun.launchready.cn/index.html
Open both. Same bytes, two completely different delivery stacks. The rest of this article is the method that got there, and the numbers we recorded on the way.
A note on where this piece stands. AWS’s own migration guide routes exiting customers to two CDN partners in AWS Marketplace China (Cloudsway and BaishanCloud at the time of writing) — both are valid, AWS-supported destinations, and we declare no winner among them. Alibaba Cloud is simply the first stack we took through the full method end to end; a Tencent Cloud rehearsal of the same method is planned next. Chinaready remains vendor-neutral across Alibaba Cloud, Tencent Cloud, and the AWS China regions — the choice of stack belongs to you, and our job is to measure what each one actually does.

Before you plan anything: measure the gate
The first thing we measured was whether “keep your origins, swap the CDN” is even available the obvious way. It is not. On an AWS China account with zero prior distributions, CreateDistribution with a valid minimal configuration — S3 REST origin, GET/HEAD only — returned Throttling (rate exceeded) on five consecutive attempts across roughly ten minutes, while read APIs on the same account responded normally. A control run with no custom domain attached throttled identically, so the block is on distribution creation itself, not on alias or filing checks. The reading: the new-customer cutoff is enforced, and it presents as a persistent rate limit rather than an explicit rejection.
That single measurement sets the strategy for everyone in the same position: you are not extending CloudFront, you are re-fronting your origins. The good news is that the re-fronting is the fastest stage of the whole method.
The method, stage by stage
| Stage | What you do | What proves it worked |
|---|---|---|
| 0 — Inventory | List origins, objects, per-object metadata (Content-Type, Cache-Control), and the website configuration you must reproduce | A manifest you can diff against later |
| 1 — CDN front | Put a new CDN domain on the untouched origin; fix origin Host; HTTPS on | The old origin serves through the new edge with origin headers intact |
| 2 — Data migration | Copy S3 → OSS; keep per-object metadata; incremental sync until cutover | Header parity on both sides; counts and byte comparison |
| 3 — Private origin | Restrict the OSS bucket and authorize the CDN to read it | Edge responses carry the authorized-fetch marker |
| 4 — Cache and refresh | Mirror cache policy by content type; wire the refresh workflow | HIT on second read; forced revalidation after refresh |
| 5 — Verify and cut | Byte-parity check across endpoints, then move DNS | cmp returns identical on all endpoints; rollback stays one DNS change away |
Stage 1 — Put a CDN front on the origin first
Before any data moves, put the replacement CDN directly in front of the existing S3 origin. This is AWS’s own guidance, and it works: our demo origin is an S3 bucket in cn-north-1, and it now serves through an Alibaba Cloud CDN domain with HTTPS back-to-origin on the 443 port.
One trap owns this stage. S3 answers by the Host header it receives — virtual-hosted addressing — and a CDN edge that forwards the accelerated domain as Host will make S3 look for a bucket named after your domain and return NoSuchBucket. The fix is an explicit origin-Host rule pointing at the bucket’s REST endpoint hostname. Every S3-to-CDN integration in China hits this within the first hour; it is cheap to fix and expensive to discover in production.
HTTPS for the interim domain is routine from the DNS side: a DNS-01-validated certificate (we used Let’s Encrypt, issued against the DNS API in about a minute) uploaded to the CDN, with HTTP-to-HTTPS redirect enabled. From this point the origin is safe behind a working edge, and the remaining stages cannot make it unreachable.
Stage 2 — Move the data, keep the metadata
The copy itself is the least interesting part, which is exactly why its failure modes hide in the details. What we verified, because it is what breaks silently:
- Metadata parity. Every object kept its Content-Type and its differentiated Cache-Control through the copy — 3600 s for HTML, 86400 s for CSS, 30 days for images — confirmed by comparing signed-read response headers on the source bucket and the destination bucket side by side. Migration tooling documents metadata preservation; verify it anyway, per object class, before cutover.
- ETags do not survive. The destination computes new ones. Any reconciliation logic keyed on ETags will report false failures; use content comparison instead.
- Incremental semantics. The sync should transfer only changed objects. In our rehearsal, a content update to four of six objects moved exactly four files and left the untouched image alone — the property that makes “migrate early, sync until cutover” a safe schedule instead of a big-bang.
Stage 3 — Lock the origin down (private-bucket back-to-origin)
A public-read bucket is a migration-stage compromise, not an architecture. The end state is a private OSS bucket with the CDN authorized to read it — the CDN edge presents credentials on each origin fetch, and the bucket itself stays dark to the internet. The rehearsal runs this way today: bucket ACL private, authorization role attached, and the edge response carrying the authorized-fetch marker on every origin-served object.
This is also where the S3 website-config semantics lose one piece: see the traps below.
Stage 4 — Cache rules and the refresh workflow
Cache policy moves from origin headers to a deliberate split: long TTLs by file type at the edge (we set 30 days for image and style assets), short-lived or header-driven behavior for HTML. The operational half of this stage is the refresh workflow — the replacement for invalidations:
- Object-level and directory-level refresh APIs both exist and take the CDN’s documented five-to-six minutes for full propagation as a ceiling.
- Measured in the rehearsal: a submitted refresh produced TCP_REFRESH_MISS on the next request within about thirty seconds — a forced revalidation against origin — and returned to memory hits (
TCP_MEM_HIT) on the request after. - Note the precedence difference from CloudFront: console-configured edge rules take priority over origin cache headers unless you explicitly configure otherwise, and error-status caching is configured separately from content caching. Budget an afternoon to re-derive your cache behavior table rather than assuming it ports.
Stage 5 — Verify by byte parity, then cut over
The strongest completion check we know is also the cheapest: fetch the same path from the origin endpoint, the CDN-fronted origin, and the migrated endpoint, and compare the bytes. In the rehearsal, cmp returns identical on all three for every object, including the HTML, the stylesheet, and the animated asset added late in the process. Counts, spot checks, and checksums are all weaker approximations of this.
Cutover is then a DNS change on your schedule, with rollback remaining one DNS change away — the origin never moved or stopped serving at any point in the method.
The traps we measured
- The creation gate (Stage 0): throttled
CreateDistributionfor accounts without prior distributions — five-for-five in ten minutes, reads unaffected. - Origin Host semantics (Stage 1): forwarded accelerated-domain Host produces
NoSuchBucket; fix with an explicit origin-Host rule. - Root-path index loss (Stage 3): under authorized origin fetches, the bare
/is a list-bucket call, so the index-document setting never engages — the edge returns 403 on/while/index.htmlworks and error documents behave correctly. Choose an edge rewrite, a public-read website configuration, or explicit index links. CloudFront’s default-root-object setting has no like-for-like on a plain CDN. - Cache precedence inversion (Stage 4): edge rules beat origin headers by default; 404 caching is a separate rule.
- ETag churn (Stage 2): new tags on the destination; reconcile by content, not by ETag.
What the traffic economics look like
Unit prices from the official pricing pages at rehearsal time — mainland China list prices, converted to US dollars at approximately 7.1 RMB per USD and rounded:
| Line item | Source side | Migrated side |
|---|---|---|
| Origin egress per GB | S3 internet out ≈ $0.13 | OSS CDN-origin outflow ≈ $0.02 |
| Standard storage per GB-month | ≈ $0.03 (Beijing) | ≈ $0.02 |
| CDN downstream per GB | — | ≈ $0.03 (first tier) |
At 10 TB/month delivered with 90% cache hit (1 TB re-originated), the migrated stack runs roughly 24% cheaper on flow plus storage than S3-egress-plus-CDN, and the gap widens as hit rate falls. The one-time cost is the migration egress itself — about $0.13 per GB copied out of S3 once — which the monthly saving repays in a little over a month at that scale. Different traffic shapes move these numbers; the structure of the comparison does not change.
When this is not your path
Two honest branches. If your data must stay on AWS, stop after Stage 1 — the CDN-front pattern is a complete architecture on its own, and the origin never has to move. If you want a single vendor to hold both the objects and the edge, note that Tencent Cloud’s CDN also documents third-party object-storage origins with key authentication for AWS S3; we have not yet verified its signing compatibility with the China partition’s SigV4-only endpoints, so treat that branch as promising but unmeasured.
Run the rehearsal yourself
The method is deliberately reproducible. Every measurement above names its API, the read-only and write operations are cleanly separable, and the rehearsal cost of the whole thing — two small buckets, two CDN domains, certificates, and refreshes — lands under the price of a coffee. If you are running production traffic, the same stages apply with capacity math and a cutover window on top; the verification gate does not change.
For the background partition measurements behind this piece — service parity, quotas, and pricing across the AWS China regions — see our AWS China partition benchmark, the AWS China orientation guide, and our CloudFront China end-of-support briefing.
Sources
- CloudFront China discontinuation notice and FAQ — https://www.amazonaws.cn/en/cloudfront/features/ , https://www.amazonaws.cn/en/cloudfront/faqs/
- AWS CloudFront China migration guide — https://www.amazonaws.cn/en/cloudfront/migration-guide/
- AWS China S3 pricing — https://www.amazonaws.cn/en/s3/pricing/
- Alibaba Cloud OSS pricing — https://www.aliyun.com/price/detail/oss
- Alibaba Cloud CDN billing rules — https://help.aliyun.com/zh/cdn/product-overview/billing-rules-of-basic-services
- Alibaba Cloud online migration, S3 to OSS — https://help.aliyun.com/zh/data-online-migration/user-guide/migrate-data-from-amazon-s3-to-oss
- Alibaba Cloud CDN private-bucket back-to-origin — https://help.aliyun.com/zh/cdn/user-guide/grant-alibaba-cloud-cdn-access-permissions-on-private-oss-buckets
- Alibaba Cloud CDN cache-expiration configuration — https://help.aliyun.com/zh/cdn/user-guide/configure-the-cdn-cache-expiration-time
Frequently asked questions
Can I still create a new CloudFront distribution in the China partition?
Not on an account that never used CloudFront there. Our test account — zero prior distributions — attempted CreateDistribution five times across roughly ten minutes with a valid configuration, and every attempt returned Throttling (rate exceeded) while read APIs stayed healthy; a no-alias control run throttled identically. The official cutoff for new customers passed on September 30, 2026, and existing distributions stop working on May 31, 2027. Treat the API as closed to new tenants and plan the exit, not the exception.
Does object metadata survive the S3-to-OSS copy?
Content-Type and Cache-Control did, in our rehearsal, on every object — verified by comparing response headers on both sides with signed reads. ETags do not survive: the migration path recomputes them, so reconciliation belongs to content checksums or byte comparison, never to ETag matching.
Why does the root path on the migrated site need an explicit /index.html?
Under authorized origin fetches, a request for the bare slash is interpreted by the object store as a list-bucket call, so the bucket's index-document setting never engages and the edge returns 403. Error documents behave correctly. The fixes are an edge rewrite of the slash to the index key, a public-read website configuration if your content model allows it, or explicit index links — the same trade-off CloudFront's default-root-object setting used to absorb.
How quickly do cache refreshes take effect?
The CDN's documented ceiling is five to six minutes for full propagation. In the rehearsal, object-level and directory-level refreshes both produced a forced revalidation within about thirty seconds, visible as TCP_REFRESH_MISS on the next request and a return to memory hits on the one after.
Is the live demo still running?
Yes. Both endpoints are public — the CDN-fronted S3 origin and the migrated OSS + private-origin CDN serve byte-identical pages, so you can compare response headers and content yourself. Links appear in the article body.


