满心记 我在人间混日子

博客应用部署历程

这篇文章与其说是分享,不如直接说是我部署过程的记录,虽然文中写到的东西在其他博客都能找到,但是我仍然还是记录下我使用到的部署流程,方便我以后换服务器,或是其他特殊原因,需要重新部署时查阅

前言

昨天心血来潮,把服务器又折腾了一番,之前采用Nginx + Docker方式部署,所有映射及转发都采用手动配置,当然这些对于我来说并没什么难度,而现在采用baota + Nginx + Docker方式部署,目前使用的是静态博客,以及fcircle + twikoo部署都更为便捷,下面分享内容主要以文字为主,可能不会截图,这部分部署相信大家都会

安装

由于我的服务器并不是纯净系统,所以不能直接安装宝塔,当然网络上也有人说可以通过 docker 安装 centos 方式来安装,但是我没试,而采用粗暴方式,重装系统(记得备份),我这里选择宝塔专享版的镜像直接安装

安装完后,发现这个专享版什么也不带,需要自己安装Apache、Nginx,当然php也不能少

部署

部署 hexo

源代码拉到服务器,然后hexo g编译,宝塔配置目录绑定即可,eg:/www/wwwroot/hexo_blog/public

部署 fcircle 鱼塘

之前部署在vercle上,总感觉不太稳定,现改为私有部署,我这里采用 docker 部署,官网

部署docker

  • 安装 Docker CE 之前需要删除 Docker 旧版本

    yum remove docker docker-common docker-selinux docker-engine
  • 安装 Docker 所需的软件包

    yum install -y yum-utils device-mapper-persistent-data lvm2
  • 设置 docker yum 源

    yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  • 安装 DOCKER CE

    yum install docker-ce
    yum list docker-ce --showduplicates | sort -r    #要安装特定版本的Docker CE,请列出repo中的可用版本
  • 启动 Docker

    systemctl start docker
    systemctl status  docker

安装git

yum install -y git

宝塔中自带python,在软件商店直接安装即可,我这里采用服务器安装模式

  • 安装依赖

    yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel yum vim gcc
  • 安装 python

    wget https://www.python.org/ftp/python/3.8.8/Python-3.8.8.tgz
    tar -zxf Python-3.8.8.tgz && cd Python-3.8.8
    ./configure --prefix=/usr/local/python3
    make && make install
  • 建立软连接

    ln -s /usr/local/python3/bin/python3.8 /usr/bin/python3
    ln -s /usr/local/python3/bin/pip3.8 /usr/bin/pip3
  • 验证(出现版本号即安装成功)

    python3 --version
  • 安装 yaml

    pip3 install pyyaml

停止运行

找到进程号,杀掉即可

ps aux

kill 掉 PID 即可,也可通过fcircle项目中python3 deploy.py脚本一键取消运行

部署后端

  • 克隆仓库
git clone https://github.com/Rock-Candy-Tea/hexo-circle-of-friends
  • 拉取镜像
docker pull yyyzyyyz/fcircle:latest
  • 运行部署脚本
    进入hexo-circle-of-friends根目录,运行一下脚本,选择docker -> 部署即可
python3 deploy.py

尝试访问:curl 127.0.0.1:8000/all,有数据即为部署成功,再使用域名反向代理即可

部署前端

官网heoakilar安知鱼

部署 twikoo

官网

  • 拉取镜像

    docker pull imaegoo/twikoo
  • 运行容器

    docker run --name twikoo -e TWIKOO_THROTTLE=1000 -p 8080:8080 -v /root/twikoo/data:/app/data -d imaegoo/twikoo

部署卜算子

  • 搭建docker + docker-compose环境;
  • 宝塔添加静态页面,绑定域名busuanzi.lovelu.top,别忘记添加解析;
  • 进入/www/wwwroot/busuanzi.lovelu.top下,新建docker-compose.yaml,内容如下;
version: "2"
services:
  redis:
    image: "redis:alpine"
    volumes:
      - /root/busuanzi/redis:/data

  bsz:
    image: "xcsoft/busuanzi:latest"
    ports:
      - "8999:8080"
    volumes:
      - /root/busuanzi:/app/expose
    links:
      - redis
    depends_on:
      - redis
    environment:
      LOG_ENABLE: true
      API_SERVER: http:\/\/127.0.0.1:8999\/api

端口根据自己需要,因为我 8080 占用,所以改用 8999,记得添加解析,以及防火墙配置
其中你需要修改API_SERVER为你的地址,例如你的网址为busuanzi.lovelu.top,那么就需要填写https://busuanzi.lovelu.top/api
修改完成后,执行docker-compose up -d 4. 宝塔设置反代
http://127.0.0.1:8999进行代理即可

另外有个坑,记录一下
这个的 id 名为:busuanzi_page_pv
我的原来是:busuanzi_value_page_pv
如果你的也是busuanzi_value_site_pv,需要更改一下。butterfly 主题可以到themes/butterfly/layout/includes/header/post-info.pug文件中修改

部署百度统计

  • 网站域名根目录,新建info.php,内容如下
<?php

// 设置允许所有来源的请求
header("Access-Control-Allow-Origin: *");

// 设置API密钥和网站ID
$apiKey = '';
$secretKey = '';
$siteId = '';
$code = '';

// 通过授权码获取Access Token函数
function getAccessToken($apiKey, $secretKey, $code) {
    $url = "https://openapi.baidu.com/oauth/2.0/token";
    $params = array(
        'grant_type' => 'authorization_code',
        'code' => $code,
        'client_id' => $apiKey,
        'client_secret' => $secretKey,
        'redirect_uri' => 'oob',
    );

    $query = http_build_query($params);
    $response = file_get_contents($url . '?' . $query);
    if ($response === false) {
        die('Error fetching access token.');
    }
    $data = json_decode($response, true);

    return $data;
}

// 刷新Access Token函数
function refreshAccessToken($apiKey, $secretKey, $refreshToken) {
    $url = "https://openapi.baidu.com/oauth/2.0/token";
    $params = array(
        'grant_type' => 'refresh_token',
        'refresh_token' => $refreshToken,
        'client_id' => $apiKey,
        'client_secret' => $secretKey,
    );

    $query = http_build_query($params);
    $response = file_get_contents($url . '?' . $query);
    if ($response === false) {
        die('Error refreshing access token.');
    }
    $data = json_decode($response, true);

    return $data;
}

// 持久化存储令牌
function saveTokens($accessToken, $refreshToken) {
    file_put_contents('tokens.json', json_encode(array(
        'access_token' => $accessToken,
        'refresh_token' => $refreshToken,
    )));
}

// 从文件中加载令牌
function loadTokens() {
    if (!file_exists('tokens.json')) {
        return null;
    }
    return json_decode(file_get_contents('tokens.json'), true);
}

// 检查并刷新令牌
function checkAndRefreshTokens($apiKey, $secretKey) {
    $tokens = loadTokens();
    if ($tokens === null) {
        global $code;
        $tokens = getAccessToken($apiKey, $secretKey, $code);
        saveTokens($tokens['access_token'], $tokens['refresh_token']);
    } else {
        $tokens = refreshAccessToken($apiKey, $secretKey, $tokens['refresh_token']);
        saveTokens($tokens['access_token'], $tokens['refresh_token']);
    }
    return $tokens;
}

// 定义获取数据的函数
function getData($startDate, $endDate, $metrics, $accessToken, $siteId) {
    $url = "https://openapi.baidu.com/rest/2.0/tongji/report/getData";
    $params = array(
        'access_token' => $accessToken,
        'site_id' => $siteId,
        'method' => 'overview/getTimeTrendRpt',
        'start_date' => $startDate,
        'end_date' => $endDate,
        'metrics' => $metrics,
    );

    $query = http_build_query($params);
    $fullUrl = $url . '?' . $query;

    $response = file_get_contents($fullUrl);
    if ($response === false) {
        die('Error fetching data.');
    }
    return json_decode($response, true);
}

// 定义缓存文件路径
$cacheFile = 'data_cache.json';
$cacheTime = 60; // 缓存时间,单位:秒

// 获取Access Token并刷新令牌
$tokens = checkAndRefreshTokens($apiKey, $secretKey);
$accessToken = $tokens['access_token'];

// 检查缓存文件是否存在且未过期
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTime)) {
    $data = json_decode(file_get_contents($cacheFile), true);
} else {
    // 准备数据
    $data = array(
        'today_uv' => null,
        'today_pv' => null,
        'yesterday_uv' => null,
        'yesterday_pv' => null,
        'last_month_pv' => null,
        'last_year_pv' => null,
    );

    // 获取最近31天的数据
    $startDate = date('Ymd', strtotime('-31 days'));
    $endDate = date('Ymd');
    $monthData = getData($startDate, $endDate, 'pv_count,visitor_count', $accessToken, $siteId);

    // 处理并提取最近31天的数据
    $last31DaysPV = 0;
    if (isset($monthData['result']['items'][1])) {
        $dataPoints = $monthData['result']['items'][1];
        foreach ($dataPoints as $point) {
            // $last31DaysPV += $point[0];
            $last31DaysPV += intval($point[0]);
        }
    }

    // 获取一整年的数据
    $startDate = date('Ymd', strtotime('-1 year'));
    $endDate = date('Ymd');
    $yearData = getData($startDate, $endDate, 'pv_count,visitor_count', $accessToken, $siteId);

    // 处理并提取所需数据
    if (isset($yearData['result']['items'][1])) {
        $dataPoints = $yearData['result']['items'][1];
        $today = date('Y/m/d');
        $yesterday = date('Y/m/d', strtotime('-1 day'));
        $lastMonth = date('Y/m/d', strtotime('-30 days'));
        
        foreach ($yearData['result']['items'][0] as $index => $date) {
            if ($date[0] == $today) {
                $data['today_uv'] = $dataPoints[$index][1];
                $data['today_pv'] = $dataPoints[$index][0];
            } elseif ($date[0] == $yesterday) {
                $data['yesterday_uv'] = $dataPoints[$index][1];
                $data['yesterday_pv'] = $dataPoints[$index][0];
            } elseif ($date[0] == $lastMonth) {
                $data['last_month_pv'] = $dataPoints[$index][0];
            }
        }
        
        $data['last_year_pv'] = array_sum(array_column($dataPoints, 0));
    }

    // 添加最近31天的PV总和
    $data['last_month_pv'] = $last31DaysPV;

    // 保存数据到缓存文件
    file_put_contents($cacheFile, json_encode($data));
}

// 返回JSON数据
header('Content-Type: application/json');
echo json_encode($data);

?>
  • 再来说说页头几个参数怎么获取

获取apiKey和secretKey数据导出服务

获取code,将其中{CLIENT_ID}替换为你的apiKey

http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri=oob&scope=basic&display=popup

获取siteId,siteid为你的网站id,查看百度统计报告的url中会显示siteid

以上信息修改完后,立即访问一次,防止过期

  • 防止泄露token

宝塔站点中添加访问限制

名称:禁止访问tokens
后缀:tokens.json
目录:baidutongji

然后尝试访问一次tokens.json,如果访问失败了就大功告成。

一套部署下来,服务器内存占用还是比较客观,下面再去部署一个图床吧

参考:HeoAkilar安知鱼

以上我的部署就完成了,剩下就是配置反向代理以及 SSL 了

发表评论

提交评论