我接觸過很多博客平臺:WordPress、Jekyll、Hexo、Typecho和Vuepress,有的是靜態博客有的需要伺服器運維,玩過花裡胡哨後私以為博客最重要的是思考和記錄,而不是不停地裝飾。所以總結一些經驗可以讓大家快速把博客搭建起來,並且不會憂愁後續的維護。本文不是保姆教程,目標群體是有一定工作經驗的開發者需要開箱即用的博客發布方案,請準備好下列所需準備出發:
科學上網相關代碼和參考連結請查看文末
Github Actions部署VuePress使用前端庫Vue.js之前是由Hexo驅動的,但是Vue作者糾結於加載性能和SEO也為了更好地釋放Vue的用武之地創造了VuePress,我們接下來就是要創建這樣的博客。
安裝Node.js之後可以在命令行運行,yarn init的時候不需要輸入什麼一直按回車即可。
mkdir vuepress-blog && cd vuepress-blog
yarn init
yarn add -D vuepress
mkdir docs && echo '# Hello VuePress' > docs/README.mdpackage.json可以改成
{
"name": "vuepress-blog",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"vuepress": "^1.8.2"
},
"scripts": {
"dev": "vuepress dev docs",
"build": "vuepress build docs"
}
}運行yarn dev之後打開http://localhost:8080/ 只有一個很簡陋的「Hello VuePress」,不過對docs/.vuepress/config.js稍作修改和添加對應的目錄文件就可以上線見面了,每個欄位的含義參考VuePress文檔[1], 另外也可以基於我的博客[2]替換成自己的Markdown文檔和文件路徑。
markdown:配置markdown的渲染,如代碼塊的行號和插件、標題錨點、外鏈themeConfig:依賴的主題,nav配置右上方導航,sidebar為左側導航,對應著docs文件夾下的文件或者文件夾,記得sidebar數組最後一項/:的空字符串數組是不能丟的,因為這代表一張首頁的README.md。base:尤其重要,如果直接訪問https://[用戶名].github.io則默認不用填,我們上面的例子base要寫成"/vuepress-publish/",上傳後可訪問https://[用戶名].github.io/vuepress-publish參考代碼:vuepress-blog[3]和blog[4]
// config.js
module.exports = {
base: "/vuepress-publish/",
title: '灰熊の博客'
}
// https://github.com/huixiongyu/blog中docs/.vuepress/config.js的配置
module.exports = {
markdown: {
lineNumbers: true
},
title: '灰熊の博客',
description: '進擊的全棧Coder',
head: [
['link', { rel: 'icon', href: '/flower.ico' }],
],
themeConfig: {
nav: [
{
text: "博客",
link: "/blog/"
},
{
text: '閱讀',
link: "/book/"
},
{
text: 'Github',
link: 'https://github.com/huixiongyu/blog'
}
],
sidebar: {
'/blog/': [
'',
{
title: '生活',
collapsable: true,
children: [
'/blog/Life/my-action-list',
'/blog/Life/train-habit',
'/blog/Life/about-PG-entrance-exam',
'/blog/Life/graduation-thesis'
]
},
...
...
...
],
'/book/': [
'',
'plan-and-record',
{
title:'前端相關',
collapsable: true,
children:[
'/book/HTML&CSS/02-css-secrets'
]
},
...
...
...
],
'/': [
''
]
},
sidebarDepth: 2,
displayAllHeaders: true,
nextLinks: true,
prevLinks: true,
lastUpdated: '更新時間',
docsDir: 'docs',
editLinks: true,
editLinkText: '幫助我完善這篇內容🙏'
}
}
構建GitHub Page在GitHub上添加一個同名的私有倉庫vuepress-blog,然後再創建一個公開的倉庫vuepress-public,這裡的思路是博客的源文件(md文件和config.js等)是私有的保護文章不被搬運,我們提交代碼後GitHub會幫我們構建渲染成HTML等靜態文件推送到vuepress-public的gh-pages分支,用戶就可以通過https://[用戶名].github.io/vuepress-public訪問。我們直接commit、push代碼並不會自動構建部署,需要啟用到代碼倉庫上邊Actions一欄,點擊"set up a workflow yourself"創建一個.yml文件,名字不重要,點擊保存後會在代碼根目錄.github/workflow文件夾下出現,這裡建議先不保存,還有後續步驟,使用右鍵選擇「在新標籤頁中打開連結」操作我們接下來的步驟:申請Token和設置Secret。
Actions的代碼如下:
on記錄觸發的條件這裡是master分支push的時候執行;jobs下面是任務集合而build是一個jobs,你也可以在build的同一個層級(縮緊)多建一個jobs,名字取執行步驟的意義即可;runs-on是執行的虛擬機系統,有Ubuntu、Windows和macOS可選;steps是單個job的執行步驟,這裡是獲取代碼分支、運行vuepress部署;uses是選用官方或者第三方的action步驟,官方以actions/接名稱,非官方(用戶自發的)則是用[用戶名]/[倉庫名]來標註;env是依賴的action需要傳入環境變量,注意我們使用${{ secrets.XXX }}來引入不便於暴露的信息,如何配置就是我們下一步要做的。name: CI
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
# 在當前環境中拉取你倉庫然後進入到目錄,下面的步驟在倉庫的根目錄中進行
- name: Checkout
uses: actions/checkout@master
- name: vuepress-deploy
uses: jenkey2011/vuepress-deploy@master
env:
ACCESS_TOKEN: ${{ secrets.TOKEN }}
TARGET_REPO: huixiongyu/vuepress-publish
TARGET_BRANCH: gh-pages
BUILD_SCRIPT: yarn && yarn build
BUILD_DIR: docs/.vuepress/dist/
CNAME: ${{ secrets.CNAME }}Action中引入TOKEN的來自GitHub的授權。倉庫右上角頭像下拉選擇Settings跳轉後找到Developer settings,在Personal access Tokens創建,勾選repo就可以,如果長期使用要記得重新創建。提交後的token會馬上顯示,這時要及時複製,以後不會再出現。複製後回到倉庫vuepress-blog選擇Settings下Secrets可以新建一個密碼本,Name是Actions裡面${{ secrets.XXX }}的XXX,而Value就是真正要傳入的值。這裡我們在Name填入TOKEN然後Value直接粘貼剛剛申請的授權字符串。CNAME可以讓我們使用值裡面的域名直接訪問[用戶名].github.io的資源,如果你在阿里雲、namecheap、騰訊雲等已經購買域名,那麼可以在域名控制臺進行GitHub的CNAME配置[5]。如果沒有個人域名,可以將代碼中CNAME所在的行刪除即可。在設置了所有所需的Secrets就可以保存.yml的action文件了,此時點擊Actions標籤可以看到GitHub虛擬機執行actions的日誌,如果成功的話會有綠勾,不然就出現紅叉。並且代碼倉庫vuepress-publish的gh-pages分支會有更新。因為我設置了CNAME,https://www.hackslog.com/vuepress-publish/就可以訪問構建出來的網頁了,跟之前在本地http://localhost:8080/是一樣的,如果沒有設置CNAME,而我的GitHub用戶名是huixiongyu,訪問連結就是https://huixiongyu.github.io/vuepress-publish/。
部署到OSSOSS是阿里雲的對象存儲服務,也就是文件存儲,用戶上傳文件之後可以拿到公網可訪問的連結,配合CDN加速可以讓用戶快速訪問近距離的數據節點。阿里雲、七牛雲、華為雲等對象存儲產品使用方式基本一致,一年費用也就幾塊錢,可以放心使用。在OSS管理控制臺中可以隨意創建Bucket,對於個人網站可以一個網站用一個Bucket以防資源混亂。當使用控制臺上傳文件後,如果在文件詳情中沒有配置HTTP頭或者綁定自定義域名[6],文件會自動下載而不是直接瀏覽,另外想使用https訪問也是在控制臺->傳輸管理裡面配置,過程可以直接查提示文檔只要細心些就可以申請到免費的SSL證書。
回到vuepress-blog倉庫的Actions代碼,需要增加一個job將構建出的靜態網頁直接上傳的OSS,於是.github/workflows/main.yml的完整代碼如下:
name: CI
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
# 在當前環境中拉取你倉庫然後進入到目錄,下面的步驟在倉庫的根目錄中進行
- name: Checkout
uses: actions/checkout@master
- name: vuepress-deploy
uses: jenkey2011/vuepress-deploy@master
env:
ACCESS_TOKEN: ${{ secrets.TOKEN }}
TARGET_REPO: huixiongyu/vuepress-publish
TARGET_BRANCH: gh-pages
BUILD_SCRIPT: yarn && yarn build
BUILD_DIR: docs/.vuepress/dist/
CNAME: ${{ secrets.CNAME }}
build-to-OSS:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x'
- name: Build Web
run: |
node changeOssPath.js
yarn add -D vuepress
yarn install
yarn build
echo '${{ secrets.OSS_CNAME }}' > docs/.vuepress/dist/CNAME
mv docs/.vuepress/dist ./
- name: Upload to OSS
env:
OSS_REGION: ${{ secrets.OSS_REGION }}
OSS_BUCKET: ${{ secrets.OSS_BUCKET }}
OSS_KEY: ${{ secrets.OSS_KEY }}
OSS_SECRET: ${{ secrets.OSS_SECRET }}
OSS_URL: ${{ secrets.OSS_URL }}
run: |
ls
pwd
node ossSync.js
- name: Upload to Could Computer
uses: appleboy/scp-action@master
with:
host: ${{ secrets.IP_ADDRESS }}
username: ${{ secrets.SERVER_USER }}
port: "${{ secrets.SERVER_PORT }}"
key: ${{ secrets.SERVER_PRIVATE_KEY }}
source: "dist/**"
target: "${{ secrets.TARGET_PATH }}"不要急著保存代碼,我們還需要在Settings->Secret補充一些私密信息,其中OSS相關的可以在創建Bucket的控制臺和右上用戶頭像下拉後顯示的「AccessKey管理」獲取,AccessKey切勿直接寫入到代碼,因為有操作所有Bucket的完整權限,為了順利上傳我還寫了一些腳本,比如ossSync.js。Upload to Could Computer則是上傳到雲主機的步驟,不需要的可以刪除~
OSS_CNAME:使用OSS訪問時的自定義域名,跟Bucket綁定的一致OSS_REGION:Bucket所屬區域,比如我選的廣州,oss-cn-hangzhouOSS_REGION: Bucket自定義的名稱,比如huixiong-blogOSS_SECRET:AccessKey Id對應的密鑰OSS_URL:自定義域名,沒有的話寫默認的,比如huixiong-blog.oss-cn-guangzhou.aliyuncs.comSERVER_PRIVATE_KEY:對稱密鑰的私鑰,包含BEGIN RSA PRIVATE KEY
TARGET_PATH:傳輸到伺服器的目錄Secret和代碼保存後,很快Actions執行完了,並且OSS控制臺也看到的文件更新,網頁也可以正常訪問。深入ActionsGithub Actions是持續集成的過程,運維部署包含著很多的步驟比如拉取代碼、測試、構建成品、登錄遠程伺服器、在遠程伺服器運行命令等等,GitHub把這些稱為actions。並且GitHub發現了這些的任務的共同點,就是可以復用和隨意組合,於是他們定義了一些規則,比如統一一些常量的意義、限制私密信息的輸出,並統一用actions文件的格式,組件了一個官方市場[7]供大家免費使用,使用Actions的過程變成了用別人的腳本和自己寫腳本的過程。在Action運行的時候,使用了actions/checkout@master
構建,docs/.vuepress目錄下會出現dist文件夾
工作環境就是代碼的根目錄,如果是手動把vuepress-blog推到其他倉庫分支需要哪些命令呢?你大概會寫這麼多:yarn install
yarn build
cd docs/.vuepress/dist
ls
echo 'hackslog.com' > CNAME
git init
git config --global user.email "huixiongyu@gmail.com"
git config --global user.name "huixiongyu"
git add .
git commit -m "deploy"
git push --force "https://${{ secrets.TOKEN }}@github.com/huixiongyu/vuepress-publish.git" master:gh-pages剛開始的時候我也是一通操作在Actions裡面自己寫了一些腳本,但是試了二三十遍構建無論如何都無法把dist推上vuepress-publish,後來進插件市場一通搜索,copy配置一下變量就可以了。如果需要多個節點,稍作配置一會時間就可以輕鬆部署博客到Github、碼雲、Coding、Gitlab...
- name: vuepress-deploy
uses: jenkey2011/vuepress-deploy@master
env:
ACCESS_TOKEN: ${{ secrets.TOKEN }}
TARGET_REPO: huixiongyu/vuepress-publish
TARGET_BRANCH: gh-pages
BUILD_SCRIPT: yarn && yarn build
BUILD_DIR: docs/.vuepress/dist/
CNAME: ${{ secrets.CNAME }}上傳到OSS似乎找不到合適的腳本,於是我開始自己寫腳本。主要還是用了阿里雲提供的Node.js SDK,通過process.env獲取actions傳過來的密鑰初始化,getLocalFileList遍歷出要上傳到OSS的所有文件的名字,然後遍歷文件的數組用putOneFile一個個把發上去,如果OSS已經有重名的文件會被覆蓋。不過這個過程非常艱辛啊,遇到一個報錯是Error: EISDIR: illegal operation on a directory, read解決花了兩三個小時,只需要將fs.readfileSync替換掉fs.readdirSync。
const fs = require('fs')
const OSS = require('ali-oss')
const {
OSS_REGION,
OSS_BUCKET,
OSS_KEY,
OSS_SECRET,
OSS_URL,
} = process.env;
const client = new OSS({
region: OSS_REGION, // 創建 bucket 選擇的區域
bucket: OSS_BUCKET, // bucket名稱
accessKeyId: OSS_KEY, // accessKeyId
accessKeySecret: OSS_SECRET, // accessKeySecret
});
function getLocalFileList(basePath) {
console.log(`current path is:${basePath}`)
const fileNamelist = fs.readdirSync(basePath)
console.log(fileNamelist)
let result = []
fileNamelist.forEach(name => {
const file = basePath + name
const statsObj = fs.statSync(file);
if (statsObj.isFile()) {
result.push(file)
} else {
result = result.concat(getLocalFileList(file + '/'));
}
})
return result;
}
async function putOneFile(fileName, dir) {
try {
const result = await client.put(fileName, dir);
console.log(OSS_URL + result.name);
} catch (e) {
console.log(e);
}
}
async function main() {
console.log('ossSync working...')
const fileList = getLocalFileList(__dirname + '/dist/')
console.log(fileList)
for(const file of fileList) {
const tempList = file.split('/dist/')
const fileName = tempList[1]
await putOneFile(fileName, file)
}
console.log('ossSync completed!')
}
main()另外為了修bug還有一個腳本來解決部署到不同環境的問題,config.js原本沒有寫base: "/vuepress-publish/",這樣就會導致在某個環境中CSS樣式失效。如果你需要直接部署在[用戶名].github.io倉庫中就需要明白base的含義,可以把config.js中的base刪除掉,而部署在域名根目錄無論是OSS還是雲伺服器都可以保留著node changeOssPath.js一句。
// changeOssPath.js
const fs = require('fs')
let content = fs.readFileSync('docs/.vuepress/config.js', 'utf8')
content = content.replace(/base:\s["']{1}[\/A-Za-z0-9_-]*["']{1},/g, '')
console.log(content)
fs.writeFileSync('docs/.vuepress/config.js', content, { flag: 'w' })你可能還會質疑Actions的安全性,我通過實現在控制臺中輸出了自己配置Secret,結果都會替換成****,依賴的腳本變量由用戶提供,另外官方市場是通過安全驗證的腳本,而其他倉庫也是開源的,而Actions運行在自己的空間權限由GitHub的API管理,他們也沒有條件收集任何私有信息的條件。所以安全第一責任人是開發者自身,另外嘗試讀源碼,分享自己的代碼吧。
部署到雲伺服器把dist文件夾傳輸到個人的雲伺服器就是用Nginx反向代理該文件,這裡先講如何連接,下一節說Nginx。連接伺服器無非IP位址、用戶名、埠和密碼,但是密碼權限太高不建議使用,可以使用SSH密鑰對[8],進入到ECS的控制臺可以找到相應入口,生成的.cer文件跟Github Token一樣只有一次保存機會。
- name: Upload to Could Computer
uses: appleboy/scp-action@master
with:
host: ${{ secrets.IP_ADDRESS }}
username: ${{ secrets.SERVER_USER }}
port: "${{ secrets.SERVER_PORT }}"
key: ${{ secrets.SERVER_PRIVATE_KEY }}
source: "dist/**"
target: "${{ secrets.TARGET_PATH }}"以上是SCP文件上傳,如果還想需要在自己的雲伺服器中有更多的操作命令,還可以使用ssh-action[9]。
阿里雲效部署Hexo的使用如果想使用瀑布流效果的博客,可以嘗試Hexo[10]。這個平臺用戶基礎大,主題豐富,可以配置的東西多種多樣,比如Next[11]和fluid[12]
npm install -g hexo-cli
hexo init hexo-blog
cd hexo-blog
npm install新建完成後,指定文件夾的目錄如下,_config.yml是網站的配置[13]信息如網站名稱、主題、文件夾名稱,themes存放主題一般在這個文件夾clone倉庫,source包含草稿和發布的文章。
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes命令行:
hexo new "12月的計劃"在_posts文件夾下創建一篇題為「12月的計劃」文章hexo server預覽網站的效果,http://localhost:4000打開網頁hexo generate生成靜態文件,一般在部署前使用,靜態文件會生成在根目錄的public文件夾下雲效OSS部署阿里雲效是一款優秀的團隊協作平臺,免費可用的代碼存儲有5GB,有日程和看板追蹤任務,類似Confluence和Notion的塊級富文本編輯器、類似Jenkins但是更易用的流水線免費構建、成品倉庫、權限細分隔離的管理系統。值得注意的是同一臺電腦其實可以管理多個git帳號,方法是在使用ssh-keygen時注意輸入~/.ssh/目錄的文件名,然後分別用ssh-add添加這幾個文件比如ssh-add ~/.ssh/id_rsa_aliyun,雖然能夠識別不同的帳號,但是每次創建或者clone後需要config各自的username和email一通,後來我採用全局只用雲效,Github使用客戶端管理。Hexo部署前先把代碼上傳到倉庫,管理方式跟GitHub並沒有什麼差異:選擇方式二:點擊控制臺左側頂部的小方格,如雲效第一張圖紅框示點擊流水線然後創建流水線,有許多可選的模版,這裡選擇OSS。當展示下面的界面的時候直奔構建上傳,選擇Codeup是雲效的代碼倉庫,如果你的代碼在GitHub也可以通過他們平臺的Settings->Security申請授權。因為是阿里雲內部資源整合,代碼倉庫可以很快找到。代碼進入到虛擬雲主機之後,需要運行的命令是:
cnpm install
npm install hexo-cli -g
hexo g點擊服務授權以後可以選中博客所在的獨立bucket,Bucket Folder應該是空的才是上傳到根目錄,圖片僅僅是測試。點擊保存並運行,會自動把public上傳到public到根目錄,這時通過Bucket綁定的自定義域名就可以訪問網頁了,部署腳本都不用寫,是不是很方便呢?
雲效部署到伺服器部署到ECS和自有主機也是創建流水線後點擊對應的模板,構建上傳的命令還是跟之前一樣,不同的是public文件夾的文件會被打包送到伺服器自己設定的目錄,如果你有多條流水線執行到同一個主機需要改成不同的名字。阿里雲買的ECS可以很快選擇,如果是其他雲的主機選擇新建主機組就會有提示讓你到該主機運行一條安裝代理的命令。我的部署腳本如下:先刪除原有的文件,然後將上傳物解壓到目標文件夾下,如果目錄下不存在文件夾需要事先創建,不然將報錯失敗。
rm -rf /usr/local/nginx/hexo/*
tar zxvf /home/admin/app/hexo-package.tgz -C /usr/local/nginx/hexo保存並運行以後,連結上伺服器可以查看到文件更新了,現在就剩下配Nginx了。
Nginx安裝nginx,如果配置不通的話可以參考其他資源,nginx配置能夠通暢就可。
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar -xzf nginx-1.18.0.tar.gz
// cmake依賴
$ sudo apt-get update # 更新下apt源
$ sudo apt-get install gcc # Nginx必備
$ sudo apt-get install make # 編譯安裝需要make工具
$ sudo apt-get install libz-dev
$ sudo apt-get install libpcre3-dev
$ sudo apt-get install libssl-devnginx目錄在:/usr/local/nginx/啟動nginx
$ cd /usr/local/nginx/sbin
$ ./nginx
$ curl http://localhost # 這裡返回的是html的代碼代表成功nginx的常用命令有:
./nginx # 啟動
./nginx -v # 查看版本號
./nginx -t # 檢查nginx.conf配置是否正常
./nginx -s reload # 熱加載
./nginx -s stop # 停止
./nginx -s reopen # 重新打開日誌我的nginx配置文件在/usr/local/nginx/conf/nginx.conf下,使用Vim編輯vim nginx.conf,移動光標在http內按i插入如下內容按ESC輸入:wq
,然後進入sbin目錄熱夾在nginx./nginx -s reloadserver {
listen 80;
server_name hexo.hackslog.com;
location / {
root hexo;
index index.html;
}
}成功訪問!Hexo後續的優化折騰空間非常大,我當初就折騰了PV/UV統計、文章置頂、看板娘、Canvas背景、滑鼠點擊效果、回複評論等樂此不疲,新鮮過後還是需要寫文章的啊。
更好地寫作我一直想找一個舒舒服服寫Markdown而不用擔心排版的解決方案,分享目前幾個感覺不錯的。
Typora一款所見即所得的編輯器,國人所做,非常簡潔,本地編輯效果最佳。最近開始試行收費了,一百塊不夠買斷,謹慎考慮中。缺點是沒有考慮雲同步,需要結合iPic上傳費神。
墨滴我一直需要一款Markdown寫文章,不用怎麼排版就可以發公眾號的,真的找到了!叫做Markdown Nice,中文墨滴。發現很多關注的公眾號都在用,一共27個主題,代碼塊的Carbon效果自帶。只是貌似圖片上傳又沒做好啊,付費我也是願意的啊!
掘金最近打開掘金寫作中心,太舒服了!Markdown粘貼在編輯器中,他們會自動把圖片等靜態資源替換成他們伺服器的連結,本地寫作還可以直接上傳圖片,太方便了啊!而且這個開源在字節group下,掘金被收購了知識分享氛圍還是很不錯,他們家人才培養體系真的好。唯一缺憾,有本事把公眾號排版也做了?
參考資料[1]VuePress文檔: https://vuepress.vuejs.org/zh/config/#description
[2]我的博客: https://github.com/huixiongyu/blog
[3]vuepress-blog: https://oss.hackslog.com/article/frontend/002-Actions-Ali-CB/vuepress-blog-master.zip
[4]blog: https://oss.hackslog.com/article/frontend/002-Actions-Ali-CB/blog-master.zip
[5]用戶名].github.io`的資源,如果你在阿里雲、namecheap、騰訊雲等已經購買域名,那麼可以在域名控制臺進行[GitHub的CNAME配置: https://cloud.tencent.com/developer/article/1421879
[6]綁定自定義域名: https://help.aliyun.com/document_detail/31902.htm?spm=a2c4g.11186623.0.0.58f27fa82b0PbN
[7]官方市場: https://github.com/marketplace?type=actions
[8]SSH密鑰對: https://help.aliyun.com/document_detail/51796.html
[9]ssh-action: https://github.com/appleboy/ssh-action
[10]Hexo: https://hexo.io/zh-cn/docs/
[11]Next: http://theme-next.iissnan.com/getting-started.html
[12]fluid: https://github.com/fluid-dev/hexo-theme-fluid
[13]配置: https://hexo.io/zh-cn/docs/configuration