某日布蔗,心血來潮,想將hexo
搭建的站點(diǎn)移除纵揍,從零開始搭建自己的站點(diǎn)泽谨。
涉及的內(nèi)容包含??:
購(gòu)買服務(wù)器
站點(diǎn)前后端分析
服務(wù)器環(huán)境搭建
發(fā)布前端項(xiàng)目
發(fā)布后端項(xiàng)目
關(guān)聯(lián)域名
站點(diǎn)提前體驗(yàn)地址:
戳地址:jimmyarea.com
購(gòu)買服務(wù)器
這里選擇了騰訊云的服務(wù)器,你也可以選擇阿里云之類的骨杂。
相關(guān)的云服務(wù)器的配置如下:
# 操作系統(tǒng)
CentOS 7.5 64位
# CPU
1核
# 內(nèi)存
2GB
# 公網(wǎng)帶寬
1Mbps
基礎(chǔ)配置(1核2GB)的機(jī)型適合有一定的訪問量的網(wǎng)站搓蚪;當(dāng)然丁鹉,也可以選擇入門配置(1核1GB)的機(jī)型揣钦,它適用起步階段的個(gè)人網(wǎng)站。
PS:本次的搭建沒有特殊說明均在騰訊云上完成?谎亩,并基于CentOS 7.5 64位
站點(diǎn)前后端分析
站點(diǎn)采用前后端分離思想团驱,前后端獨(dú)立上線空凸,方便開發(fā)和維護(hù)等~
站點(diǎn)前端
目前的功能有
? 登陸
? 注冊(cè)
? 重置密碼
? 社交列表
? 個(gè)人簡(jiǎn)介
? 文章列表
? 留言功能
? 技能圖 COMING SOON
? 發(fā)表文章功能【管理端】COMING SOON
ETC
前端使用了業(yè)界成熟的UI框架 -- ANT DESING呀洲。
彈性布局道逗,能兼容移動(dòng)端設(shè)備~
項(xiàng)目使用ANT DESIGN PRO V5
進(jìn)行初始化献烦,直接對(duì)請(qǐng)求的request
進(jìn)行抽離改造巩那,利于維護(hù)此蜈。
# src/utils/request.ts
// 默認(rèn)的框架請(qǐng)求
import { getStore } from '@/utils/storage';
import { extend } from 'umi-request';
import type { ResponseError } from 'umi-request';
import { notification } from 'antd';
// @see https://beta-pro.ant.design/docs/request-cn
const codeMessage = {
200: '服務(wù)器成功返回請(qǐng)求的數(shù)據(jù)裆赵。',
201: '新建或修改數(shù)據(jù)成功战授。',
202: '一個(gè)請(qǐng)求已經(jīng)進(jìn)入后臺(tái)排隊(duì)(異步任務(wù))桨嫁。',
204: '刪除數(shù)據(jù)成功璃吧。',
400: '發(fā)出的請(qǐng)求有錯(cuò)誤,服務(wù)器沒有進(jìn)行新建或修改數(shù)據(jù)的操作爷辙。',
401: '用戶沒有權(quán)限(令牌膝晾、郵箱务冕、密碼錯(cuò)誤)。',
403: '用戶得到授權(quán)臊旭,但是訪問是被禁止的离熏。',
404: '發(fā)出的請(qǐng)求針對(duì)的是不存在的記錄戴涝,服務(wù)器沒有進(jìn)行操作啥刻。',
405: '請(qǐng)求方法不被允許。',
406: '請(qǐng)求的格式不可得娄涩。',
410: '請(qǐng)求的資源被永久刪除映跟,且不會(huì)再得到的扬虚。',
422: '當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí)孔轴,發(fā)生一個(gè)驗(yàn)證錯(cuò)誤路鹰。',
500: '服務(wù)器發(fā)生錯(cuò)誤收厨,請(qǐng)檢查服務(wù)器。',
502: '網(wǎng)關(guān)錯(cuò)誤雁竞。',
503: '服務(wù)不可用碑诉,服務(wù)器暫時(shí)過載或維護(hù)侥锦。',
504: '網(wǎng)關(guān)超時(shí)恭垦。',
};
/**
* 異常處理程序
*/
const errorHandler = (error: ResponseError) => {
const { response, data } = error;
if (response && response.status) {
const errorText = data.msg || codeMessage[response.status] || response.statusText;
// const { status, url } = response;
const { status } = response;
notification.error({
message: `請(qǐng)求錯(cuò)誤 ${status}`,
description: errorText,
});
}
if (!response) {
notification.error({
description: '您的網(wǎng)絡(luò)發(fā)生異常番挺,無法連接服務(wù)器',
message: '網(wǎng)絡(luò)異常',
});
}
throw error;
};
/**
* 配置request請(qǐng)求時(shí)的默認(rèn)參數(shù)
*/
const request = extend({
errorHandler, // 默認(rèn)錯(cuò)誤處理
credentials: 'include', // 默認(rèn)請(qǐng)求是否帶上cookie
timeout: 5000,
prefix: '',
});
// 請(qǐng)求攔截器
request.interceptors.request.use((url, options) => {
const token = getStore('token') || '';
const theOptions = options || {};
if (token) {
theOptions.headers = {
// 處理header中的token
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${token}`,
};
}
return {
url,
options: { ...theOptions },
};
});
request.interceptors.response.use(async (response: any) => response);
export default request;
對(duì)授權(quán)登陸進(jìn)行移除等玄柏,形成一個(gè)純凈的,符合設(shè)計(jì)的jimmyarea站點(diǎn)的功能需求右蒲。
前端開發(fā)完,運(yùn)行腳手架自帶的命令行yarn run build
或者 npm run build
生成一個(gè)dist
文件陷嘴。這個(gè)文件就是你要發(fā)布到服務(wù)器上的文件了~
當(dāng)然,完成前端的開發(fā)邑退,如果你對(duì)性能有所要求,可以進(jìn)行相關(guān)的優(yōu)化蜈七。這里莫矗,我對(duì)moment.js
進(jìn)行了優(yōu)化作谚,剔除不必要的local,壓縮了相關(guān)的圖片等等...具體的你可以通過運(yùn)行yarn run analyze
來觀察優(yōu)化
Nginx上開啟了gzip 別忘了哦
站點(diǎn)后端
后端使用的是KOA2
框架去開發(fā)雀监,本地使用nodemon
運(yùn)行服務(wù)調(diào)試会前,線上采用pm2
來啟動(dòng)服務(wù)匾竿。
目前的接口有:
? 登陸
? 注冊(cè)
? 加密鹽
? 重置密碼
? 社交列表
? 文章列表
? 留言功能
? 郵件發(fā)送
? 發(fā)表文章功能【管理端】COMING SOON
ETC
我們從零開始搭建一個(gè)NODE
的服務(wù)端項(xiàng)目,目錄結(jié)構(gòu)如下:
backend
├── config
| ├── default.json
| ├── production.json # 生產(chǎn)環(huán)境的配置
| └── test.json # 測(cè)試環(huán)境配置
├── src # 主要代碼存放地方
| ├── controllers
| | ├── user.js
| | └── ...
| ├── middlewares
| | ├── auth.js
| | └── ...
| ├── models
| | └── mongo
| | ├── schema
| | | ├── User.js
| | | └── ...
| | └── index.js
| ├── router
| | └── index.js
| ├── service # 第三方服務(wù)
| | └── index.js
| ├── utils
| | ├── bcrypt.js
| | └── ...
| ├── app.js
| └── index.js # 入口文件
├── .babelrc # 處理babel
├── apidoc.json # 生成接口文檔的配置
├── package.json # 依賴
├── pm2.json # pm2 線上運(yùn)行的配置
└── README.md 項(xiàng)目說明
其中, package.json
的內(nèi)容如下:
{
"version": "1.0.0",
"author": "Jimmy",
"scripts": {
"start": "NODE_ENV=development node src/index.js",
"dev": "NODE_ENV=development nodemon src/index.js",
"nodepro": "yarn run build && NODE_ENV=production node app/index.js",
"pm2pro": "yarn run build && NODE_ENV=production pm2 start pm2.json",
"clean": "rm -rf app/",
"compile": "babel src/ --out-dir app/ --retain-lines",
"build": "yarn run clean && yarn run compile",
"docs": "apidoc -i src/controllers -o apidoc/"
},
"dependencies": {
"bcrypt": "^5.0.1",
"bluebird": "^3.7.2",
"config": "^3.3.6",
"jsonwebtoken": "^8.5.1",
"koa": "^2.13.1",
"koa-bodyparser": "^4.3.0",
"koa-convert": "^2.0.0",
"koa-json": "^2.0.2",
"koa-jwt": "^4.0.1",
"koa-logger": "^3.2.1",
"koa-router": "^10.0.0",
"koa-session": "^6.2.0",
"mongodb": "^3.6.7",
"mongoose": "^5.12.7",
"nodemailer": "^6.6.0",
"uuid": "^8.3.2",
"xss": "^1.0.8"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-plugin-add-module-exports": "^0.1.4",
"babel-plugin-transform-runtime": "^6.8.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2015-loose": "^7.0.0",
"babel-preset-stage-3": "^6.5.0",
"babel-register": "^6.26.0",
"nodemon": "^2.0.7"
}
}
當(dāng)然,你也可以使用成熟的框架EGGJS
苔巨。
數(shù)據(jù)庫(kù)是MongoDB
废离,對(duì)象模型工具Mongoose
。
下面是一個(gè)連接數(shù)據(jù)庫(kù)查詢文章列表的接口:
# src/models/mongo/schema/Article.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
// 定義文章字段
let ArticleSchema = new Schema({
title: String, // 文章標(biāo)題
url: String, // 文章url
count: String, // 文章閱讀量
thumb: String, // 文章點(diǎn)贊量
meta: {
createAt: {
type: Date,
default: Date.now()
},
updateAt: {
type: Date,
default: Date.now()
}
}
})
mongoose.model('Article', ArticleSchema)
# src/router/index.js
// 文章部分
router.get('/public/article', Article.getArticleData)
# src/controllers/article.js
let mongoose = require('mongoose')
let Article = mongoose.model('Article')
/**
* @apiGroup Article
* @api {get} /public/article 查看社交信息
* @apiVersion 1.0.0
*
*
* @apiSuccessExample {json} 返回成功
* HTTP/1.1 200
* {
* "code": 0,
* "msg": "ok",
* "data": [{
* "key": "value"
* }]
* }
*
* @apiSampleRequest off
*/
exports.getArticleData = async (ctx, next) => {
let data = await Article.find({})
ctx.body = {
results: data,
current: 1
}
}
上面示例,線上的接口地址是https://jimmyarea.com/api/public/article 肖方,感興趣的話可以點(diǎn)擊此鏈接感受下。
嗯~到這里析桥,我們服務(wù)器也買了泡仗,本地上前端項(xiàng)目和后端項(xiàng)目都跑起來了,那么搔课,我們可以考慮將我們的項(xiàng)目上線了截亦。
服務(wù)器環(huán)境搭建
在項(xiàng)目上線前魁巩,我們得做好準(zhǔn)備,這涉及Nginx代理葬馋,數(shù)據(jù)庫(kù)肾扰,后端node
等環(huán)境集晚。
安裝數(shù)據(jù)庫(kù)MongoDB
基于成本的考慮,我們將數(shù)據(jù)庫(kù)和應(yīng)用都放在同一臺(tái)云服務(wù)器上面蒋院。
如果是公司企業(yè)的話莲绰,建議購(gòu)買云數(shù)據(jù)庫(kù)等
演示的是:服務(wù)器操作系統(tǒng)為 CentOS 7.5 64位
mongodb的安裝教程: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/
當(dāng)然蛤签,你也可以在文章Linux Centos 7安裝MongoDB(簡(jiǎn)單!詳細(xì)3屏) 按照指引完成數(shù)據(jù)庫(kù)的安裝戳晌。
安裝完數(shù)據(jù)庫(kù)之后,建議開啟權(quán)限驗(yàn)證及設(shè)置用戶名密碼马昨,不然什么人都可以訪問你的數(shù)據(jù)庫(kù)扛施,那很是尷尬??
比如:
db.createUser(
{
user: "simpleUser",
pwd: “123456”,
roles: [“readWrite”,”dbAdmin”,”userAdmin”]
}
)
安裝Nginx
基于centos
的yum
源操作
# 安裝nginx 卸載[yum -y remove nginx]
yum -y install nginx
# 查看版本
nginx -v
# 啟動(dòng)nginx
systemctl start nginx.service
# 訪問 默認(rèn)端口是80
your_ip:80
# 配置
cd /etc/nginx/conf.d
... 有待補(bǔ)充
# 以下是nginx常用命令
# 啟動(dòng)nginx服務(wù)
systemctl start nginx.service
# 停止nginx服務(wù)
systemctl stop nginx.service
# 重啟nginx服務(wù)
systemctl restart nginx.service
# 重新讀取nginx配置(這個(gè)最常用, 不用停止nginx服務(wù)就能使修改的配置生效)
systemctl reload nginx.service
- 相關(guān)啟動(dòng)命令也可如下
nginx -t #測(cè)試配置文件是否有語(yǔ)法錯(cuò)誤
nginx -s reopen #重啟Nginx
nginx -s reload #重新加載Nginx配置文件疙渣,然后以優(yōu)雅的方式重啟Nginx
nginx -s stop #強(qiáng)制停止Nginx服務(wù)
nginx -s quit #優(yōu)雅地停止Nginx服務(wù)(即處理完所有請(qǐng)求后再停止服務(wù))
nginx -c [配置文件路徑] #為 Nginx 指定配置文件
配置Nginx
查看Nginx配置文件nginx.conf
vi /etc/nginx/nginx.conf
檢查是否有如下語(yǔ)句:
include /etc/nginx/conf.d/*.conf
如果存在妄荔,說明nginx的配置文件均設(shè)置在conf.d文件夾下,我們進(jìn)入到conf.d文件夾
cd /etc/nginx/conf.d/
在 conf.d 目錄下新建一個(gè)站點(diǎn)的配置文件哗伯,例如:test.com.conf:
vi test.com.conf
配置內(nèi)容這樣設(shè)置(按Insert鍵進(jìn)入編輯模式):
server {
# 監(jiān)聽80端口
listen 80;
# 服務(wù)器名稱(隨意)
server_name www.test.com test.com;
# 路由匹配
location / {
# 文件目錄焊刹,即你存放靜態(tài)資源的地方
root /usr/share/nginx/test.com;
# 設(shè)置首頁(yè)為根目錄下index.html文件
index index.html;
}
}
寫好后恳蹲,按ESC鍵退出編輯模式,輸入 :wq 保存并退出編輯
:wq
檢查配置文件是否有誤
nginx -t
重啟Nginx服務(wù)
systemctl start nginx
或者
nginx -s reload
接著我們將靜態(tài)資源存放在定義的 /usr/share/nginx/test.com 目錄下贺奠。
這里我們僅做測(cè)試儡率,于是在該目錄下創(chuàng)建一個(gè)測(cè)試網(wǎng)頁(yè)index.html
文件以清,你可以嘗試下,看瀏覽器頁(yè)面地址有沒有訪問到這個(gè)index.html
文件箕肃。
Nginx處理CORS
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
發(fā)布前端項(xiàng)目
第一種方式
將前端項(xiàng)目打包勺像,生成dist
文件夾错森,之后放在/usr/share/nginx指定的目錄中即可。
第一種方式比較繁瑣殃姓,我們用第二種方式。
第二種方式
方式二:直接拉取代碼倉(cāng)庫(kù)篷牌,打包即可
現(xiàn)在踏幻,我們用github
為進(jìn)行項(xiàng)目托管,那么我們可以在自己都買的服務(wù)環(huán)境中將Git
和Github
進(jìn)行SSH
連接夭苗。
首先在服務(wù)器上面安裝版本控制系統(tǒng)GIT
隔缀。
yum install git
之后配置git與github關(guān)聯(lián):
git config --global user.name "your_name"
git config --global user.email "your_email"
然后用ssh生成公鑰:
ssh-keygen -t rsa -C "your_email"
之后一直回車即可(如果你要更改文件命名猾瘸,可按提示修改)。
最后仔蝌,將公鑰添加到github中
在
.ssh
文件夾中找到id_rsa.pub
這個(gè)文件荒吏,復(fù)制里面的所有內(nèi)容绰更。登陸
github
賬號(hào),點(diǎn)擊頭像旁的小三角展開特恬,點(diǎn)擊Settings - SSH and GPG keys - New SSH key
徐钠,在Title
中取一個(gè)名字(任意),Key
中粘貼你剛剛復(fù)制的內(nèi)容显拜。然后點(diǎn)擊Add SSH key
即可远荠。
詳細(xì)內(nèi)容可以直接戳官方教程使用 SSH 連接到 GitHub
完成之后失息,我們可以在/usr/share/nginx
下指定的目錄進(jìn)行操作:
# clone
git clone your_github_repository_url
# 安裝依賴
yarn install || npm install
# 打包
yarn run build
后期如果有新文件加入档址,重新拉取打包即可守伸。
發(fā)布后端項(xiàng)目
這里是NODE
項(xiàng)目含友,那么我們得先準(zhǔn)備自己相關(guān)的NODE
環(huán)境校辩。
安裝包文件nodejs
# 使用EPEL安裝
yum install epel-release
# 安裝node js
sudo yum install nodejs
# 查看安裝版本
node -v
# v6.13.3
# 版本過低宜咒,升級(jí)到最新穩(wěn)定版
# 安裝n把鉴,n是nodejs管理工具
npm install -g n
# 安裝nodejs最新版本
n latest
# 穩(wěn)定版 n node的穩(wěn)定版版本號(hào)
# 之后切換nodejs版本即可
n
上面是一種安裝方式庭砍,讀者可以嘗試其他的安裝方式,這里不展開了
其他安裝
安裝yarn包管理器诗轻,比npm性能優(yōu)越
npm install -g yarn
安裝pm2的node進(jìn)程管理工具
npm install pm2 -g
或yarn global add pm2
pm2 讓 Nodejs 服務(wù)常駐
配置nginx反向代理
比如:
upstream api {
server 127.0.0.1:6000;
keepalive 2000;
}
server {
location /api {
proxy_pass http://api;
}
}
發(fā)布
發(fā)布的操作也是通過git拉區(qū)在github上的后端項(xiàng)目扳炬,然后運(yùn)行本項(xiàng)目自定義的yarn run pm2pro
啟動(dòng)項(xiàng)目即可。
你可以通過命令行pm2 list
查看服務(wù)運(yùn)行的情況恨樟。
pm2 list
id | name | mode | ? | status | cpu | memory |
---|---|---|---|---|---|---|
0 | jimmy-server | cluster | 880 | online | 0% | 56.5mb |
關(guān)聯(lián)域名
我們成功發(fā)布了前后端項(xiàng)目劝术,配置好nginx
代理之后呆奕,項(xiàng)目就能夠通過 IP
地址進(jìn)行訪問了,本項(xiàng)目的服務(wù)器的ip地址是111.230.192.27匙握。
為了用戶友好體驗(yàn)圈纺,我們是不是考慮買個(gè)域名了呢?
這里我購(gòu)買的域名是jimmyarea.com蛾娶, 還順帶買了證書 - 用于開啟https
。
購(gòu)買域名
這里使用的是騰訊云提供的服務(wù)胎许。
購(gòu)買完域名后罗售,根據(jù)指引去實(shí)名進(jìn)行認(rèn)證。運(yùn)營(yíng)商有很詳細(xì)的操作指南穆碎,畢竟要用戶所禀,這里不詳細(xì)說明放钦。
域名解析
這里采用的是騰訊云服務(wù)器和騰訊域名,你可以參考這個(gè) - 快速添加域名解析 來完成?
Nginx并配置SSL證書
https證書申請(qǐng)
將證書上傳到服務(wù)器的指定目錄
# 用命令行上傳
scp -r local_dir username@servername:remote_dir
# 例子
scp -r test root@192.168.0.101:/var/www/ 把當(dāng)前目錄下的test目錄上傳到服務(wù)器的/var/www/ 目錄
具體可以參考官方- Nginx 服務(wù)器 SSL 證書安裝部署 進(jìn)行操作褂策,這里不贅述辙培。
- 域名備案邢锯,以騰訊為例,域名申請(qǐng)n個(gè)自然日后可以提交申請(qǐng)備案了丹擎。域名不備案蒂培,通過域名訪問不穩(wěn)定~囧 ??
親測(cè)域名備案前后需要兩個(gè)星期 審核-修改-審核
后話
至此,可以美滋滋地對(duì)項(xiàng)目進(jìn)行迭代開發(fā)--上線翎冲。當(dāng)然媳荒,如果你想更加工程化驹饺,方便點(diǎn)赏壹,你可以引入jenkins
啥的 從零開始搭建JENKINS+GITHUB持續(xù)集成環(huán)境【多圖】衔沼,docker啥的。
成品地址: jimmyarea.com指蚁,感興趣可以體驗(yàn)下欣舵。
倉(cāng)庫(kù)代碼地址不公開,畢竟里面涉及到數(shù)據(jù)庫(kù)賬號(hào)密碼等個(gè)人信息,我全部設(shè)置為privacy
了袜蚕。