最近做了几个纯前端项目,每次到部署阶段都得折腾服务器——装 Nginx、配证书、设反向袋里……说实话,对于静态站点来说,这套组合拳确实有点重。后来换成了 OSS + CDN 的方案,不光省掉了维护服务器的琐碎事,整体访问速度也跟着提了一截。这篇把实际搭建的流程掰开揉碎整理出来,给有同样需求的朋友做个参考。

一、为什么选 OSS 托管静态站点
先看看常见的静态站点部署方案,各有各的脾气:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 自建 Nginx | 灵活 | 需要维护服务器、手动配证书 |
| GitHub Pages | 免费 | 国内访问慢、无法自定义后端逻辑 |
| Vercel / Netlify | 体验好 | 海外节点,国内延迟不稳定 |
| OSS + CDN | 稳定、国内速度快、按量计费 | 需要一点配置成本 |
OSS 的核心优势在于:它是对象存储,天生适合放 HTML / CSS / JS / 图片这类静态资源。再配上阿里云 CDN,全国各省都有边缘节点加速,访问延迟基本能压在 50ms 以内。对于以静态内容为主的项目来说,这套组合的性价比和体验都很能打。
二、环境准备
动手之前,先确认几样东西到位了:
- 阿里云账号(已实名认证)
- 一个构建好的前端项目(本文以 Vite + React 为例)
- 自定义域名(可选,但建议配一个)
准备工作就绪,接下来一步步搭建。
三、Step 1:创建 OSS Bucket
登录阿里云控制台 → 对象存储 OSS → 创建 Bucket:
- Bucket 名称:全局唯一,建议用项目名,比如
my-project-static - 地域:选离目标用户近的节点,华东或华北都行
- 读写权限:改成「公共读」——静态网站需要匿名访问
- 版本控制:可以开启,方便回滚
创建完成后,进入 Bucket → 基础设置 → 静态网站托管:
- 默认首页:填
index.html - 默认 404 页(对于 SPA 应用):同样填
index.html,这样前端路由才能正常工作
这一步的关键是让 OSS 知道怎么处理入口文件和路由回退,不然刷新页面容易 404。
四、Step 2:上传构建产物
先在本地把项目构建好:
npm run build
# 构建产物默认在 dist/ 目录
上传方式有三种,按场景选:
方案 A:控制台手动上传(适合小项目)
直接把 dist/ 目录内容拖进 Bucket 文件管理界面,简单直接。
方案 B:使用阿里云 OSS CLI 工具(推荐)
# 安装 ossutil(macOS / Linux)
curl https://gosspublic.alicdn.com/ossutil/1.7.19/ossutil64 -o ossutil
chmod +x ossutil
# 配置 AK/SK(从 RAM 子账号获取,不要用主账号)
./ossutil config
# 增量同步 dist/ 到 Bucket
./ossutil sync dist/ oss://my-project-static/ \
--delete # 删除 OSS 中 dist/ 里已不存在的文件
--force # 不弹出确认提示
--jobs 10 # 并发上传数
关于 RAM 子账号的权限:建议单独创建一个只有 OSS 特定 Bucket 写权限的子账号,把 AK/SK 写进 CI/CD 环境变量。主账号的 AK 一旦泄露,损失会大很多,分开管理更安全。
方案 C:GitHub Actions 自动部署
# .github/workflows/deploy.yml
name: Deploy to OSS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
- name: Build
run: npm ci && npm run build
- name: Upload to OSS
uses: manyuanrong/setup-ossutil@v2.0
with:
endpoint: oss-cn-hangzhou.aliyuncs.com
access-key-id: ${{ secrets.OSS_ACCESS_KEY_ID }}
access-key-secret: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
- run: ossutil sync dist/ oss://my-project-static/ --delete --force
这套配置配好后,每次 push 到 main 分支都会自动构建并同步到 OSS,省心不少。
五、Step 3:绑定自定义域名 + HTTPS
在 Bucket → 域名管理 → 绑定用户域名,添加你的域名(比如 www.example.com),然后在 DNS 服务商处把该域名 CNAME 解析到 OSS 提供的 Endpoint 地址。
HTTPS 证书直接用阿里云免费的 DV 证书就行(SSL 证书服务 → 免费证书),上传到 Bucket 绑定域名处即可,免去手动续签的麻烦。这一步配好之后,站点就能用 HTTPS 访问了,安全性和可用性都上一个台阶。
六、Step 4:接入 CDN 加速
OSS 本身没有 CDN 加速能力,如果用户分布在全国各地,建议再套一层 CDN:
控制台 → CDN → 添加加速域名 → 源站选「OSS 域名」→ 选择刚才的 Bucket 即可。
缓存策略可以参考下面这套:
# 带 hash 的静态资源(JS / CSS):强缓存
*.js, *.css → Cache-Control: max-age=31536000, immutable
# HTML 文件:不缓存(每次都要最新版本)
*.html → Cache-Control: no-cache
# 图片资源:中等缓存
*.png, *.jpg, *.webp → Cache-Control: max-age=604800
这个策略的核心逻辑是:Vite / webpack 构建出来的 JS / CSS 文件名里带内容 hash(比如 main.a3f9b2.js),内容变了文件名就变了,可以放心强缓存;而 HTML 作为入口文件必须保持最新,不能缓存。配好之后,用户加载速度会有明显提升,同时发布新版本也不会出现缓存没刷新的问题。
七、踩坑记录
几个容易踩的坑,提前说清楚:
坑 1:跨域问题
如果你的站点需要通过 JS 访问 OSS 上的资源(比如直接请求图片或文件),需要在 Bucket 设置跨域规则(CORS):
{
"AllowedOrigins": ["https://www.example.com"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
这个配置配好之后,浏览器就不会因为跨域问题报错了。
坑 2:上传大文件超时
单文件超过 100MB 建议开启分片上传(Multipart Upload)。ossutil 默认超过 100MB 会自动分片,但如果用 SDK 自己写上传逻辑,记得手动实现分片逻辑,否则容易超时失败。
坑 3:CDN 缓存刷新
每次发布新版本后,记得去 CDN 控制台刷新 HTML 文件缓存(或者通过 CDN API 把这步自动化)。否则用户拿到的还是旧 HTML,加载到的也是旧 JS,相当于发布了个寂寞。这一步容易忘,建议加到部署脚本里。
八、成本估算
以一个中型项目为例——月访问量 10 万次,存储 2GB 静态资源,流出流量 50GB:
| 费用项 | 大致费用 |
|---|---|
| OSS 存储(2GB) | ≈ ¥0.12 / 月 |
| OSS 请求次数(10 万次) | ≈ ¥0.01 / 月 |
| CDN 流量(50GB) | ≈ ¥17.5 / 月 |
| 合计 | ≈ ¥18 / 月 |
相比一台最低配 ECS(约 ¥100 / 月),省了不少,而且还省去了运维成本。如果想知道自己项目的具体费用,可以参考阿里云 OSS 价格页的官方计费说明,按实际用量算下来基本都在这个量级。
九、总结
OSS + CDN 做静态站点托管这套方案,用下来整体体验不错,适合以下场景:
- 前端 SPA 应用(React / Vue / Angular)
- 文档站点(VitePress / Docusaurus 生成的 HTML)
- 营销落地页、活动页
- 图床 / 资源 CDN
不太适合的场景是那些需要服务端渲染(SSR)、有数据库交互的动态应用——这类还是得上 ECS 或者函数计算。
如果也有类似的静态站点部署需求,不妨试试这套方案。评论区欢迎交流踩过的坑,一起把流程优化得更顺。
