💦从零开始搭建站点 - 前后端

某日,心血来潮,想将hexo搭建的站点移除,从零开始搭建自己的站点。

涉及的内容包含👇:

  • 购买服务器

  • 站点前后端分析

  • 服务器环境搭建

  • 发布前端项目

  • 发布后端项目

  • 关联域名

站点提前体验地址:

戳地址:jimmyarea.com

购买服务器

这里选择了腾讯云的服务器,你也可以选择阿里云之类的。

相关的云服务器的配置如下:

# 操作系统
CentOS 7.5 64位

# CPU
1核

# 内存    
2GB

# 公网带宽  
1Mbps

基础配置(1核2GB)的机型适合有一定的访问量的网站;当然,也可以选择入门配置(1核1GB)的机型,它适用起步阶段的个人网站。

PS:本次的搭建没有特殊说明均在腾讯云上完成✅,并基于CentOS 7.5 64位

站点前后端分析

站点采用前后端分离思想,前后端独立上线,方便开发和维护等~

站点前端

目前的功能有

✅ 登陆

✅ 注册

✅ 重置密码

✅ 社交列表

✅ 个人简介

✅ 文章列表

✅ 留言功能

❌ 技能图 COMING SOON

❌ 发表文章功能【管理端】COMING SOON

ETC

前端使用了业界成熟的UI框架 -- ANT DESING。

弹性布局,能兼容移动端设备~

项目使用ANT DESIGN PRO V5进行初始化,直接对请求的request进行抽离改造,利于维护。

# src/utils/request.ts

// 默认的框架请求
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: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队(异步任务)。',
  204: '删除数据成功。',
  400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限(令牌、邮箱、密码错误)。',
  403: '用户得到授权,但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  405: '请求方法不被允许。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除,且不会再得到的。',
  422: '当创建一个对象时,发生一个验证错误。',
  500: '服务器发生错误,请检查服务器。',
  502: '网关错误。',
  503: '服务不可用,服务器暂时过载或维护。',
  504: '网关超时。',
};

/**
 * 异常处理程序
 */
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: `请求错误 ${status}`,
      description: errorText,
    });
  }

  if (!response) {
    notification.error({
      description: '您的网络发生异常,无法连接服务器',
      message: '网络异常',
    });
  }
  throw error;
};

/**
 * 配置request请求时的默认参数
 */
const request = extend({
  errorHandler, // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
  timeout: 5000,
  prefix: '',
});

// 请求拦截器
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;

对授权登陆进行移除等,形成一个纯净的,符合设计的jimmyarea站点的功能需求。

前端开发完,运行脚手架自带的命令行yarn run build 或者 npm run build 生成一个dist文件。这个文件就是你要发布到服务器上的文件了~

当然,完成前端的开发,如果你对性能有所要求,可以进行相关的优化。这里,我对moment.js进行了优化,剔除不必要的local,压缩了相关的图片等等...具体的你可以通过运行yarn run analyze来观察优化

Nginx上开启了gzip 别忘了哦

站点后端

后端使用的是KOA2框架去开发,本地使用nodemon运行服务调试,线上采用pm2来启动服务。

目前的接口有:

✅ 登陆

✅ 注册

✅ 加密盐

✅ 重置密码

✅ 社交列表

✅ 文章列表

✅ 留言功能

✅ 邮件发送

❌ 发表文章功能【管理端】COMING SOON

ETC

我们从零开始搭建一个NODE的服务端项目,目录结构如下:

 backend
 ├── config 
 |    ├── default.json 
 |    ├── production.json # 生产环境的配置
 |    └── test.json # 测试环境配置
 ├── src # 主要代码存放地方
 |    ├── controllers 
 |    |    ├── user.js
 |    |    └── ...
 |    ├── middlewares 
 |    |    ├── auth.js
 |    |    └── ... 
 |    ├── models 
 |    |    └── mongo
 |    |        ├── schema
 |    |        |    ├── User.js
 |    |        |    └── ... 
 |    |        └── index.js
 |    ├── router
 |    |    └── index.js
 |    ├── service # 第三方服务
 |    |    └── index.js
 |    ├── utils
 |    |    ├── bcrypt.js
 |    |    └── ...
 |    ├── app.js
 |    └── index.js # 入口文件
 ├── .babelrc # 处理babel
 ├── apidoc.json # 生成接口文档的配置 
 ├── package.json # 依赖
 ├── pm2.json # pm2 线上运行的配置
 └── README.md 项目说明

其中, package.json的内容如下:

 {
  "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"
  }
}

当然,你也可以使用成熟的框架EGGJS

数据库是MongoDB,对象模型工具Mongoose

下面是一个连接数据库查询文章列表的接口:

# src/models/mongo/schema/Article.js
 
const mongoose = require('mongoose')
const Schema = mongoose.Schema

// 定义文章字段
let ArticleSchema = new Schema({
  title: String, //  文章标题
  url: String, // 文章url
  count: String, // 文章阅读量
  thumb: String, // 文章点赞量
  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 ,感兴趣的话可以点击此链接感受下。

嗯~到这里,我们服务器也买了,本地上前端项目和后端项目都跑起来了,那么,我们可以考虑将我们的项目上线了。

服务器环境搭建

在项目上线前,我们得做好准备,这涉及Nginx代理,数据库,后端node等环境。

安装数据库MongoDB

基于成本的考虑,我们将数据库和应用都放在同一台云服务器上面。

如果是公司企业的话,建议购买云数据库等

演示的是:服务器操作系统为 CentOS 7.5 64位

mongodb的安装教程: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/

当然,你也可以在文章Linux Centos 7安装MongoDB(简单!详细!) 按照指引完成数据库的安装。

安装完数据库之后,建议开启权限验证及设置用户名密码,不然什么人都可以访问你的数据库,那很是尴尬😅

比如:

db.createUser(
    {
    user: "simpleUser",
    pwd: “123456”,
    roles: [“readWrite”,”dbAdmin”,”userAdmin”]
    }
)

安装Nginx

基于centosyum源操作

# 安装nginx 卸载[yum -y remove nginx]
yum -y install nginx

# 查看版本
nginx -v

# 启动nginx
systemctl start nginx.service

# 访问 默认端口是80
your_ip:80

# 配置
cd /etc/nginx/conf.d
... 有待补充

# 以下是nginx常用命令
# 启动nginx服务
systemctl start nginx.service
# 停止nginx服务
systemctl stop nginx.service
# 重启nginx服务
systemctl restart nginx.service
# 重新读取nginx配置(这个最常用, 不用停止nginx服务就能使修改的配置生效)
systemctl reload nginx.service
  • 相关启动命令也可如下
nginx -t                        #测试配置文件是否有语法错误
nginx -s reopen                 #重启Nginx
nginx -s reload                  #重新加载Nginx配置文件,然后以优雅的方式重启Nginx
nginx -s stop                   #强制停止Nginx服务
nginx -s quit                       #优雅地停止Nginx服务(即处理完所有请求后再停止服务)
nginx -c [配置文件路径]       #为 Nginx 指定配置文件

配置Nginx

查看Nginx配置文件nginx.conf

vi /etc/nginx/nginx.conf

检查是否有如下语句:

include /etc/nginx/conf.d/*.conf

如果存在,说明nginx的配置文件均设置在conf.d文件夹下,我们进入到conf.d文件夹

cd /etc/nginx/conf.d/ 

在 conf.d 目录下新建一个站点的配置文件,例如:test.com.conf:

vi test.com.conf 

配置内容这样设置(按Insert键进入编辑模式):

server {
         # 监听80端口
         listen 80;
         # 服务器名称(随意)
         server_name www.test.com test.com; 

         # 路由匹配
         location / {
                 # 文件目录,即你存放静态资源的地方
                 root /usr/share/nginx/test.com;
                 # 设置首页为根目录下index.html文件
                 index index.html;         
         }
} 

写好后,按ESC键退出编辑模式,输入 :wq 保存并退出编辑

:wq 

检查配置文件是否有误

nginx -t

重启Nginx服务

systemctl start nginx 

或者

nginx -s reload

接着我们将静态资源存放在定义的 /usr/share/nginx/test.com 目录下。

这里我们仅做测试,于是在该目录下创建一个测试网页index.html文件,你可以尝试下,看浏览器页面地址有没有访问到这个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;
    }
} 

发布前端项目

第一种方式

将前端项目打包,生成dist文件夹,之后放在/usr/share/nginx指定的目录中即可。

第一种方式比较繁琐,我们用第二种方式。

第二种方式

方式二:直接拉取代码仓库,打包即可

现在,我们用github为进行项目托管,那么我们可以在自己都买的服务环境中将GitGithub进行SSH连接。

首先在服务器上面安装版本控制系统GIT

yum install git

之后配置git与github关联

git config --global user.name "your_name"
git config --global user.email "your_email"

然后用ssh生成公钥

ssh-keygen -t rsa -C "your_email"

之后一直回车即可(如果你要更改文件命名,可按提示修改)。

最后,将公钥添加到github中

  1. .ssh文件夹中找到id_rsa.pub这个文件,复制里面的所有内容。

  2. 登陆github账号,点击头像旁的小三角展开,点击Settings - SSH and GPG keys - New SSH key,在Title中取一个名字(任意),Key中粘贴你刚刚复制的内容。然后点击Add SSH key即可。

详细内容可以直接戳官方教程使用 SSH 连接到 GitHub

完成之后,我们可以在/usr/share/nginx下指定的目录进行操作:

# clone 
git clone your_github_repository_url

# 安装依赖
yarn install || npm install

# 打包
yarn run build 

后期如果有新文件加入,重新拉取打包即可。

发布后端项目

这里是NODE项目,那么我们得先准备自己相关的NODE环境。

安装包文件nodejs

# 使用EPEL安装
yum install epel-release

# 安装node js
sudo yum install nodejs

# 查看安装版本
node -v
# v6.13.3

# 版本过低,升级到最新稳定版
# 安装n,n是nodejs管理工具
npm install -g n

# 安装nodejs最新版本
n latest
# 稳定版 n node的稳定版版本号

# 之后切换nodejs版本即可
n

上面是一种安装方式,读者可以尝试其他的安装方式,这里不展开了

其他安装

  • 安装yarn包管理器,比npm性能优越 npm install -g yarn

  • 安装pm2的node进程管理工具 npm install pm2 -gyarn global add pm2 pm2 让 Nodejs 服务常驻

配置nginx反向代理

比如:

upstream api {
      server 127.0.0.1:6000;
      keepalive 2000;
}

server {
    location /api {
            proxy_pass http://api;
      }
}

发布

发布的操作也是通过git拉区在github上的后端项目,然后运行本项目自定义的yarn run pm2pro启动项目即可。

你可以通过命令行pm2 list查看服务运行的情况。

pm2 list
id name mode status cpu memory
0 jimmy-server cluster 880 online 0% 56.5mb

关联域名

我们成功发布了前后端项目,配置好nginx代理之后,项目就能够通过 IP 地址进行访问了,本项目的服务器的ip地址是111.230.192.27

为了用户友好体验,我们是不是考虑买个域名了呢?

这里我购买的域名是jimmyarea.com, 还顺带买了证书 - 用于开启https

购买域名

这里使用的是腾讯云提供的服务。

购买完域名后,根据指引去实名进行认证。运营商有很详细的操作指南,毕竟要用户,这里不详细说明。

域名解析

这里采用的是腾讯云服务器和腾讯域名,你可以参考这个 - 快速添加域名解析 来完成✅

Nginx并配置SSL证书

  • https证书申请

  • 将证书上传到服务器的指定目录

# 用命令行上传
scp -r local_dir username@servername:remote_dir

# 例子
scp -r test root@192.168.0.101:/var/www/ 把当前目录下的test目录上传到服务器的/var/www/ 目录

具体可以参考官方- Nginx 服务器 SSL 证书安装部署 进行操作,这里不赘述。

  • 域名备案,以腾讯为例,域名申请n个自然日后可以提交申请备案了。域名不备案,通过域名访问不稳定~囧 😅

亲测域名备案前后需要两个星期 审核-修改-审核

后话

至此,可以美滋滋地对项目进行迭代开发--上线。当然,如果你想更加工程化,方便点,你可以引入jenkins啥的 从零开始搭建JENKINS+GITHUB持续集成环境【多图】,docker啥的。

成品地址: jimmyarea.com,感兴趣可以体验下。

仓库代码地址不公开,毕竟里面涉及到数据库账号密码等个人信息,我全部设置为privacy了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容