本文不再更新,新的更新內(nèi)容一律放原文鏈接
前言
直到今天我見過很多網(wǎng)站還是傾向使用獨(dú)立的服務(wù)器部署自己的網(wǎng)站。但是在云服務(wù)更加完善的今天,已經(jīng)有更好的選擇。本文將介紹使用阿里云的OSS+CDN部署自己的前端頁面,以及加速靜態(tài)資源。
直接使用阿里云的OSS+CDN的方案有幾大好處:
- 成本低廉。OSS+CDN部署自己的網(wǎng)站每個(gè)月的花費(fèi)遠(yuǎn)比自己買ECS服務(wù)器部署網(wǎng)站花費(fèi)要少得多
- 大幅降低運(yùn)維成本。直接使用現(xiàn)成的云服務(wù)了,無需花精力去維護(hù)ECS了。
- 極高的可用性。無論阿里云的OSS還是CDN,都已經(jīng)做好了高可用性,幾乎可以保證網(wǎng)站始終可訪問
- 極高的訪問速度。ECS帶寬畢竟有限的,高帶寬意味著超高的費(fèi)用。但是用OSS+CDN這種天然分布式的架構(gòu)部署網(wǎng)站很輕松的解決了帶寬問題,極大地提升了用戶的訪問體驗(yàn)。
部署準(zhǔn)備
- 備案過的域名
- 足夠的余額(流量不大的話100元余額都?jí)蛴煤脦讉€(gè)月,比ECS便宜得多)
阿里云CDN需要綁定自己的域名,國內(nèi)要求必須備案,所以務(wù)必先備案自己的域名。如果這個(gè)域名在阿里云購買的更好,幾乎可以做到不用手改域名解析記錄,阿里云會(huì)自動(dòng)處理。
OSS和CDN都是后付費(fèi)的服務(wù),因此需要保證賬戶有足夠的余額。價(jià)格方案: https://cn.aliyun.com/price/product#/oss/detail
注意: 網(wǎng)站鏈接需要特別注意,阿里云OSS的網(wǎng)站托管是兼容Angular的路由的,也就是根目錄只有一個(gè)
index.html
,其他目錄的訪問都應(yīng)該rewrite到/index.html
。所以如果你的靜態(tài)資源不是通過Angular build出來的,不應(yīng)該使用/location/
這種路徑頁面跳轉(zhuǎn),應(yīng)該使用/location/index.html
這種路徑,否則訪問/location/
將顯示/index.html
中的內(nèi)容。具體的細(xì)則請(qǐng)參考阿里云的官方文檔: 配置靜態(tài)網(wǎng)站托管
部署步驟
開通OSS與CDN服務(wù)
這兩個(gè)服務(wù)都是按量付費(fèi)的,開通是不需要費(fèi)用的。
OSS創(chuàng)建bucket
每個(gè)獨(dú)立的bucket可以當(dāng)做一個(gè)獨(dú)立的網(wǎng)盤對(duì)待,要求bucket name全局唯一,不能重名。創(chuàng)建一個(gè)前端托管的bucket參考配置如下:
配置bucket
bucket創(chuàng)建之后,默認(rèn)的bucket配置是不具有靜態(tài)網(wǎng)站托管的功能的,因此需要做一些配置。參考配置如下:
啟用CDN加速
OSS目前的策略限制了不能通過OSS自己的域名直接打開index.html
,會(huì)變成下載。因此無論是否使用CDN,都必須綁定自己的域名。由于啟用CDN之后會(huì)加速OSS,并且回源流量半價(jià),還是挺劃算的,因此建議啟用CDN。啟用CDN的辦法如下:
稍等片刻之后,等待CDN配置之后,轉(zhuǎn)到CDN控制臺(tái)就可以看到這個(gè)域名了:
此時(shí)基本配置就已經(jīng)結(jié)束了,之后你可以上傳你的靜態(tài)網(wǎng)站到這個(gè)bucket的根目錄下了。不過在此之前可以做一些CDN的優(yōu)化配置
CDN的一些優(yōu)化配置(可選)
CDN支持定制HTTP響應(yīng)頭的功能,一個(gè)比較常見的設(shè)置是直接在http頭中添加瀏覽器緩存的頭(cache-control
),這個(gè)功能可以在緩存配置
這里直接配置緩存規(guī)則:
目前全站https已經(jīng)是趨勢(shì)了而且免費(fèi)的證書服務(wù)目前也比較多了。阿里云CDN就支持申請(qǐng)DigiCert免費(fèi)證書,并且自動(dòng)續(xù)期。下面的HTTP/2
也建議啟用:
上面的DigiCert免費(fèi)證書申請(qǐng)需要特別注意,如果你的主機(jī)頭是www
,必須將空主機(jī)頭@
也CNAME
也解析到CDN上才能申請(qǐng)成功。
此外,性能優(yōu)化個(gè)人建議全部勾選,可以減少部分帶寬:
上傳/更新網(wǎng)站
到此為止OSS+CDN的部分已經(jīng)配置完畢了,只要把靜態(tài)頁面上傳到OSS上就搞定了。建議通過oss客戶端上傳,可以支持批量拖拽上傳,而不是在OSS控制臺(tái)上一個(gè)一個(gè)上傳。
這里我推薦阿里云官方的開源項(xiàng)目oss-browser,因?yàn)檫@個(gè)客戶端可以跨平臺(tái),并且支持記錄AK,使用上很方便。
使用前需要開啟賬戶的AccessKey,或者專門創(chuàng)建一個(gè)低權(quán)限的子賬戶管理OSS。
每次更新網(wǎng)站的時(shí)候,可能需要手工刷新下CDN(盡管OSS配置中有個(gè)自動(dòng)刷新CDN的功能,但我發(fā)現(xiàn)使用客戶端是上傳的時(shí)候無效。疑似通過API上傳的文件不會(huì)觸發(fā)CDN刷新)。進(jìn)入CDN的控制臺(tái),點(diǎn)擊刷新,輸入一下要刷新的URL路徑即可:
這里分享一下我個(gè)人的deploy.sh
腳本,拼接阿里云接口參數(shù)的函數(shù)部分改動(dòng)自acem.sh這個(gè)項(xiàng)目,在此之上做了一些擴(kuò)充,感謝貢獻(xiàn)者:
#!/bin/bash -e
_urlencode() {
# urlencode <string>
old_lc_collate=$LC_COLLATE
LC_COLLATE=C
length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
LC_COLLATE=$old_lc_collate
}
_ali_nonce() {
date +"%s%N"
}
_timestamp() {
date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
}
_ali_urlencode() {
_str="$1"
_str_len=${#_str}
_u_i=1
while [ "$_u_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
case $_str_c in [a-zA-Z0-9.~_-])
printf "%s" "$_str_c"
;;
*)
printf "%%%02X" "'$_str_c"
;;
esac
_u_i="$(($_u_i + 1))"
done
}
_ali_signature() {
sorted_query=$(printf "%s" "${query}" | tr '&' '\n' | sort | paste -s -d '&')
string_to_sign=$(printf "%s" "GET&%2F&$(_ali_urlencode "${sorted_query}")")
signature=$(printf "%s" "${string_to_sign}" | openssl sha1 -binary -hmac "${ACCESS_KEY_SECRET}&" | base64)
_ali_urlencode "${signature}"
}
aliyun_request_builder() {
query="Format=json&AccessKeyId=${ACCESS_KEY_ID}&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&Version=${version}"
query="${query}&SignatureNonce=$(_ali_nonce)&Timestamp=$(_timestamp)"
for q in "$@"; do
query="${query}&${q%%=*}=$(_ali_urlencode "${q#*=}")"
done
query="${query}&Signature=$(_ali_signature "${query}")"
echo "${query}"
}
aliyun_rest() {
query="${1}"
curl -fs "${aliyun_endpoint}?${query}"
}
aliyun_cdn_refresh() {
ACCESS_KEY_ID="${CDN_ACCESS_KEY_ID}"
ACCESS_KEY_SECRET="${CDN_ACCESS_KEY_SECRET}"
if [ -z "${ACCESS_KEY_ID}" ] && [ -z "${ACCESS_KEY_SECRTE}" ]; then
echo "請(qǐng)?jiān)O(shè)置CDN_ACCESS_KEY_ID,CDN_ACCESS_KEY_SECRET環(huán)境變量"
exit 1
fi
aliyun_endpoint="https://cdn.aliyuncs.com/"
version="2014-11-11"
request_query="$(aliyun_request_builder \
Action=RefreshObjectCaches \
"ObjectPath=${1}" \
ObjectType=File)"
aliyun_rest "${request_query}"
}
_oss_upload_one_file() {
file="${1}"
if [ -z "${OSS_ACCESS_KEY_ID}" ] && [ -z "${OSS_ACCESS_KEY_SECRET}" ] && [ -z "${OSS_BUCKET}" ]; then
echo "請(qǐng)?jiān)O(shè)置OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, OSS_BUCKET三個(gè)環(huán)境變量"
exit 1
fi
upload_path="${OSS_BASE_PATH:-/}"
host="${OSS_BUCKET}.oss-cn-hangzhou.aliyuncs.com"
Date="$(LC_ALL=C TZ=GMT date +'%a, %d %b %Y %T %Z')"
Content_MD5=`openssl md5 -binary < "${file}" | base64`
extension="${file##*.}"
case "${extension,,}" in
js)
Content_Type=application/javascript
;;
css)
Content_Type=text/css
;;
json)
Content_Type=application/json
;;
woff)
Content_Type=font/woff
;;
woff2)
Content_Type=font/woff2
;;
*)
Content_Type=$(file -b --mime-type "${file}")
;;
esac
storage_path="${upload_path}${file}"
CanonicalizedResource="/${OSS_BUCKET}${storage_path}"
SignString="PUT\n${Content_MD5}\n${Content_Type}\n${Date}\n${CanonicalizedResource}"
Signature=`echo -ne "$SignString" | openssl sha1 -binary -hmac "${OSS_ACCESS_KEY_SECRET}" | base64`
Authorization="OSS ${OSS_ACCESS_KEY_ID}:${Signature}"
echo "Uploading '${file}' to bucket: '${OSS_BUCKET}' path: '${storage_path}', content-type: '${Content_Type}'"
curl -XPUT -sfLkT "${file}" \
-H "Content-Type: ${Content_Type}" \
-H "Date: ${Date}" -H "Content-Md5: ${Content_MD5}" \
-H "Authorization: ${Authorization}" "https://${host}${storage_path}"
}
export -f _oss_upload_one_file
oss_upload() {
src="${1}"
cd "${src}"
find -type f -printf "%P\0" | xargs -0 -I{} --no-run-if-empty -P10 bash -ec "_oss_upload_one_file {}"
}
main() {
oss_upload "${1}"
if [ -n "${CDN_URL}" ]; then
echo "Refreshing CDN: '${CDN_URL}'"
aliyun_cdn_refresh "${CDN_URL}"
fi
}
main
AK信息配置到環(huán)境變量中:
export OSS_ACCESS_KEY_ID=xxxxxxx
export OSS_ACCESS_KEY_SECRET=xxxxxxx
export OSS_BUCKET=your-bucket
# 如果沒有啟用阿里云的CDN,下面三個(gè)環(huán)境變量可以不賦值
export CDN_URL=https://www.domain.com/ # 阿里云的CDN刷新地址要求路徑最后的/不能省略
export CDN_ACCESS_KEY_ID=xxxxxxx
export CDN_ACCESS_KEY_SECRET=xxxxxxx
./deploy.sh /path/to/website/
注意點(diǎn):
- 使用的oss endpoint為杭州節(jié)點(diǎn),其他節(jié)點(diǎn)可以自行修改
host="${OSS_BUCKET}.oss-cn-hangzhou.aliyuncs.com"
這一行 - 考慮到OSS和CDN可能會(huì)分成兩個(gè)子賬戶管理,因此將OSS和CDN的賬戶AK信息分成兩組環(huán)境變量存儲(chǔ)
- 如果
CDN_URL
不存在,則不會(huì)在上傳后自動(dòng)刷新CDN路徑 - 刷新CDN方案使用的刷新類型是
URL
,上述配置只刷新了/
這一個(gè)訪問地址。因此期望整個(gè)網(wǎng)站使用CDN友好(即每次更新資源之后,文件名或引用路徑會(huì)改變,比如Angular或Vue的產(chǎn)品環(huán)境編譯)