Vercel域名加密策略:彻底禁用默认域名
背景
自从2020年Cloudflare Pages上线[1]以来,其已经成为大多数用例下比Vercel更理想的静态网站托管平台。相较于Vercel,Cloudflare Pages主要优势有:
- 无限流量
Cloudflare Pages对于免费计划托管的静态网站未做流量限制。
Vercel免费计划仅允许300GiB,现降为100GiB。 - 允许商用
Cloudflare Pages允许免费计划托管商业网站。
Vercel禁止免费计划托管商业网站。 - 更好的网络分发(相对)
Cloudflare Pages国内可直连访问。
Vercel DNS曾被和谐[2],*.vercel.app
已被和谐,相对于Cloudflare更不稳定。
但Cloudflare Pages免费计划仅允许每月500次的部署数量上限[3],这对于在线写作、频繁预览的场景并不太够,特别是使用基于Git工作流、采用零本地环境、实现全在线编辑的Decap-CMS作为在线编辑器,更易产生频繁的git commit
,频繁触发预览构建,500次确实不太够。
相对的,Vercel提供每日100次的部署次数上限,以及每月100小时的构建时间上限[4],专用于预览部署更加合适。
但Vercel和Cloudflare Pages均存在一个问题:无法禁用默认域名。Vercel会在部署时自动创建以下域名[5]:
1 | <project-name>-<unique-hash>-<username>.vercel.app |
且不提供任何禁用默认域名的开关。因此,即使为Vercel绑定了自定义域名,仍有可能被通过*.vercel.app
访问生产部署或预览部署,甚至会被搜索引擎索引[6],以用户不期望的方式泄露并影响SEO。
本文给出彻底禁用Vercel默认域名的访问策略,且提供更加灵活的高级访问策略配置,包括:
- 屏蔽指定域名
- 屏蔽指定路径
- 屏蔽过期部署
- 双向鉴权
- (可自行实现)地理位置屏蔽、IP屏蔽……
访问控制策略可分为禁止访问(返回404等错误码)和跳转(302跳转至指定域名),实现原理类似。
本文使用Vercel以提供预览URL为主,因此下文仅提供禁止访问策略。如有需要,可自行微调代码实现302跳转。
访问控制策略
以下策略基于Vercel Middleware功能[7]实现。
Vercel Middleware在Vercel部署的每个访问请求之前被调用,可用于实现各种访问控制策略。
屏蔽指定域名
需求场景
- 需要屏蔽全部来自Vercel默认域名的访问
- 需要仅放行来自特定域名的访问
代码
在项目根目录中添加middleware.ts
:
1 | export default function middleware(request: Request) { |
屏蔽指定路径
需求场景
- 仅需要屏蔽部分敏感目录的访问(如预览环境中的
/admin*
)
代码
1 | export default function middleware(request: Request) { |
屏蔽过期部署
需求场景
- 需要部署(如预览部署)在指定时间后失效无法访问,避免预览环境被意外泄漏/抓取
代码
实现思路:
在Middleware中添加构建时间戳,基于请求访问时刻进行访问控制;
构建时自动触发脚本,向Middleware注入硬编码时间戳。
1 | export default function middleware(request: Request) { |
1 | const fs = require('fs'); |
在正式构建前启动replace.js
:修改package.json
:
1 | { |
修改Vercel构建指令为expirable-build
:
Vercel项目 -> Settings -> Build & Development Settings -> Build Command -> npm run expirable-build
(需要重新触发构建)
双向鉴权
需求场景
- 仅允许特定来源的请求代理访问
- 针对上述基于
request.url
进行访问限制判断的策略,加密避免伪造Request header绕过访问限制策略 - 屏蔽意外的Vercel响应,例如Vercel本身的404错误页面,或等待部署完成的页面:
代码
实现思路:
在Middleware中对Request header鉴权;
在反向代理方(如Cloudflare workers)对Response header鉴权。
1 | export default function middleware(request: Request) { |
在Cloudflare中创建一个Workers反向代理:
1 | export default { |
现在Vercel部署仅可通过Cloudflare workers路由反向代理访问,如*.workers.dev
或自定义Workers路由。
集成
同时启用上述所有访问控制策略:
1 | export default function middleware(request: Request) { |
注意事项
- 无法影响Vercel历史的部署
如果担心泄漏,可手动删除历史部署,或批量删除(移除Vercel项目并重新添加Vercel项目); - 注意修改Vercel项目设置,避免泄漏Vercel信息
Settings -> General -> Comments -> Off
Settings -> Domains -> 删除Vercel默认分配的随机域名
Settings -> Deployment Protection -> Vercel Authentication -> Disabled(访问预览部署时无需登录)
Q&A
Vercel提供的域名URL是否会在证书提供商处泄漏?
(应该)不会。与Cloudflare Pages的*.pages.dev
不同,Vercel对*.vercel.app
域名申请了共享证书,并不会为其中的每个子域名申请证书,因此不会泄漏URL地址。
- 1.Introducing Cloudflare Pages: the best way to build JAMstack websites ↩
- 2.Vercel - Errors Accessing From China (14/May/21) ↩
- 3.Limits · Cloudflare Pages docs ↩
- 4.Pricing - Vercel ↩
- 5.Accessing Deployments through Generated URLs - Vercel ↩
- 6.Exposed vercel preview deploys · vercel/vercel · Discussion #5711 ↩
- 7.Edge Middleware API Reference - Vercel ↩