步骤/目录:
1.方法一:独立镜像、network连接
    (1)准备工作
    (2)运行容器与测试
    (3)收尾与总结
2.方法二:docker-compose
    (1)准备工作
    (2)编写文件并运行项目
    (3)收尾与总结
3.实战:编写易移植的typecho博客并使用https
    (1)准备工作
    (2)编写nginx配置及compose模板
    (3)运行项目并测试
    (4)问题及其他
        a.博客迁移
        b.安装完成后无法登录
        c.typecho镜像选择
        d.typecho插件及其他
    (5)后续
    (6)为typecho添加其它功能
        a.在文章页面添加最新文章
        b.添加侧边栏目录索引
        c.添加Sitemap
    (7)使用其它主题

本文首发于个人博客https://lisper517.top/index.php/archives/22/,转载请注明出处。
本文的目的是使用docker、docker-compose在树莓派上运行Typecho。
本文实验日期为2022年7月26日。本文使用的是树莓派4B(内存8G版),系统为Pi OS 64位桌面版(2022年4月4日更新,镜像名 2022-04-04-raspios-bullseye-arm64.img )。

之前的文章中曾介绍过Typecho,详见 树莓派搭建个人博客 。简单来说,Typecho是LNMP环境下运行的个人博客。学习Docker后,发现docker官网有typecho官方维护的镜像,于是试着用docker运行typecho。

另外,这个镜像的下载量为100K+,但更新时间为3年前。官方镜像虽然只有50K下载,但最近更新比较勤(据说之前typecho五年没更新,docker镜像就更不会更新了),所以下面还是使用官方镜像。

在typecho官方镜像页可以看到后缀不同的镜像,这些镜像的命名格式是:nightly-php版本号-后缀。php的版本主要有7.3、7.4、8.0,后缀主要有 空后缀、cli、fpm、apache、alpine 。本文选用的镜像是nightly-php8.0-apache。

1.方法一:独立镜像、network连接

主要思路是使用nightly-php8.0-apache镜像(apache和nginx作用一样,也是网页服务器),搭配docker-mysql。两个容器独立运行,使用docker network连接。需要注意typecho设置时如何填写数据库地址。
在这种方式中,可以不用Dockerfile或docker-compose。

(1)准备工作

准备文件夹并拉取镜像:

mkdir -p /test/mysql/data
mkdir /test/mysql/conf
docker network create -d bridge net_test
docker pull mysql:8.0.29
docker pull joyqi/typecho:nightly-php8.0-apache

拉取typecho镜像时比较慢,需要耐心等待。感觉白天镜像下的快一点。

(2)运行容器与测试

进行如下操作:

docker run -itd --name mysql_test -v /test/mysql/data:/var/lib/mysql -v /test/mysql/conf:/etc/mysql/conf.d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0.29
docker run -d --name typecho_test -p 80:80 joyqi/typecho:nightly-php8.0-apache
docker network connect net_test mysql_test
docker network connect net_test typecho_test

笔者实验时宿主机的80、3306端口没有被占用,有占用的话需自行更改。
另外,typecho初始化时使用的数据库需要提前创建。进行如下操作:

docker exec -it mysql_test bash
mysql -uroot -p
#这里连不上库可以参考 <strong>Docker树莓派实践——LNMP</strong> 中的附录
create database test;
show databases;
exit
exit

顺便也可以查看mysql容器是否运行正常。如果不想进入mysql容器,也可在mysql容器启动命令中指定MYSQL_DATABASE

docker run -itd --name mysql_test -v /test/mysql/data:/var/lib/mysql -v /test/mysql/conf:/etc/mysql/conf.d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=test mysql:8.0.29

下面进入typecho页面进行第一次访问的初始化。
浏览器访问 树莓派ip ,出现typecho初始化页面。跟着引导走即可,需要注意的是数据库地址要填容器名,本例中为mysql_test,容器id、容器ip(使用docker network inspect net_test查看,注意不要带/后面的数字)也可以。另外,数据库名称填刚才创建的test。设置完成后即可正常访问。

(3)收尾与总结

进行删除等收尾工作:

docker stop mysql_test
docker stop typecho_test
docker container ls -a
docker container rm mysql_test
docker container rm typecho_test
docker container ls -a
docker images
docker image rm mysql:8.0.29
docker image rm joyqi/typecho:nightly-php8.0-apache
docker images
docker network rm net_test
cd /
rm -r /test

两个镜像如果后续需要的话,也可以不删。

总结一下,这种方法使用了两个独立的镜像,typecho镜像自带了php、apache,另开了一个mysql容器。两个容器通过docker network连接,能够正常工作。这种方法较为简单易行。

2.方法二:docker-compose

刚才的方法两个容器需要分别配置,移植性不够好,下面使用compose进行配置。这里还是使用nightly-php8.0-apache这个镜像,搭配nginx和mysql,其中nginx用来反向代理。

(1)准备工作

准备文件夹并拉取镜像:

mkdir -p /test/data/mysql
mkdir -p /test/conf/mysql
mkdir /test/conf/nginx
mkdir /test/conf/typecho
docker pull mysql:8.0.29
docker pull nginx:1.23.1
docker pull joyqi/typecho:nightly-php8.0-apache

typecho的个性化设置目录在容器/app/usr下,等下准备将/test/conf/typecho挂载到该目录。/app/usr目录下主要是插件、主题等自定义博客的一些配置。

(2)编写文件并运行项目

编写compose模板:

nano /test/docker-compose.yml

写入以下内容:

version: "3.9"

services:
  nginx:
    image: nginx:1.23.1
    ports:
      - "443:443/tcp"
      - "443:443/udp"
      - "80:80"
    volumes:
      - /test/conf/nginx:/etc/nginx/conf.d
    depends_on:
      - typecho
    logging: 
      driver: syslog
    restart: always
  
  mysql:
    image: mysql:8.0.29
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: typecho
    command:
      - mysqld
      - --character-set-server=utf8mb4
      - --default-authentication-plugin=mysql_native_password
    volumes:
      - /test/data/mysql:/var/lib/mysql
      - /test/conf/mysql:/etc/mysql/conf.d
    logging: 
      driver: syslog
    restart: always

  typecho:
    image: joyqi/typecho:nightly-php8.0-apache
    volumes:
      - /test/conf/typecho:/app/usr
    logging: 
      driver: syslog
    restart: always

然后编写nginx配置:

nano /test/conf/nginx/default.conf

写入以下内容:

server {
    listen       80;
    server_name  localhost;

    location / {
        proxy_pass http://typecho:80;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

nginx配置参考了这个问题
然后就可以运行项目:

cd /test
docker-compose config
docker-compose up

浏览器访问 树莓派ip ,出现typecho初始化页面。同样注意数据库地址填服务容器名或容器全名,本例中为mysqltest_mysql_1,容器id、容器ip应该也可以。另外,数据库名这里填compose模板里指定创建的typecho。设置完成后即可正常访问。

(3)收尾与总结

进行删除等收尾工作:

docker stop test_nginx_1
docker stop test_mysql_1
docker stop test_typecho_1
docker container ls -a
docker container rm test_nginx_1
docker container rm test_mysql_1
docker container rm test_typecho_1
docker container ls -a
docker images
docker image rm nginx:1.23.1
docker image rm mysql:8.0.29
docker image rm joyqi/typecho:nightly-php8.0-apache
docker images
docker network rm test_default
cd /
rm -r /test

这三个镜像如果后续需要的话,也可以不删。

总结一下,这种方法使用了三个镜像并使用docker-compose管理,typecho镜像自带了php、apache,另开了mysql容器和nginx容器。这种方法加以修改,就能很方便地在更换服务器时移植博客。

最后,除了上面使用的两种方法,还有很多其他方式搭建,这里就不介绍了,下面进行实战。

3.实战:编写易移植的typecho博客并使用https

有时候树莓派因更换或其他原因需要从头配置,想移植博客到新的环境中。使用docker-compose可以简化这个过程。
下面还是使用nightly-php8.0-apache这个镜像,搭配nginx和mysql,nginx用于反向代理。
另外还需要一台云服务器、一个域名、https认证证书,并且在服务器运行frps、在树莓派运行frpc。
在树莓派运行frpc详见 Docker树莓派实践——frpc在树莓派上设置frp穿透
在服务器运行frps详见 在树莓派上设置frp穿透
域名、https认证证书等可自行搜索资料,或参考 树莓派搭建个人博客 (少量提及)。

(1)准备工作

这里将树莓派系统上所有docker项目相关的文件都放在/docker中:

mkdir -p /docker/typecho/data/mysql
mkdir -p /docker/typecho/conf/mysql
mkdir /docker/typecho/conf/nginx
mkdir /docker/typecho/conf/typecho
mkdir /docker/typecho/ssl_certificate
docker pull mysql:8.0.29
docker pull nginx:1.23.1
docker pull joyqi/typecho:nightly-php8.0-apache

/docker/typecho/ssl_certificate用来存放https相关的证书、密钥,可以使用WinSCP等工具上传到树莓派。
另外再次提醒,typecho的个性化设置目录在容器/app/usr下,等下会将/docker/typecho/conf/typecho挂载到该目录。/app/usr目录下主要是插件、主题等自定义博客的一些配置。
然后修改一下frpc.ini:

[common]
server_addr = 云服务器ip地址
server_port = 7000
token = 你的密码
login_fail_exit = false

[pi4B-blog-http-1]
type = tcp
local_ip = localhost
local_port = 80
remote_port = 80

[pi4B-blog-https-1]
type = tcp
local_ip = localhost
local_port = 443
remote_port = 443

(2)编写nginx配置及compose模板

nano /docker/typecho/conf/nginx/default.conf

配置中写入以下内容(配置参考了这个问题):

server {
    listen 80;
    server_name www.lisper517.top;
    rewrite ^(.*)$ https://$host$1 permanent;
}

server {
    listen 443 ssl;
    server_name www.lisper517.top;
    ssl_certificate .pem文件路径;
    ssl_certificate_key .key文件路径; 
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_prefer_server_ciphers on;
    location / {
        proxy_pass  http://typecho:80;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-Ip $remote_addr;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
}

记得把 www.lisper517.top 换成自己的域名。该配置将http请求改写成https后再处理。
或者也可写入:

server {
    listen 80;
    listen 443 ssl;
    server_name www.lisper517.top;
    ssl on;
    ssl_certificate .pem文件路径;
    ssl_certificate_key .key文件路径;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    location / {
        proxy_pass  http://typecho:80;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-Ip $remote_addr;
        proxy_set_header X-NginX-Proxy true;
        #proxy_redirect off;
    }
    error_page 497 https://$host$request_uri;
}

同样注意把 www.lisper517.top 换成自己的域名。
第二种配置的原理是http请求发到https端口后nginx会产生497错误,通过改写错误页面实现http请求返回https协议。
两种配置通过不同的方法,使得即使用 http://博客地址 访问typecho博客,也会跳转到https页面。
需要注意两种配置中的 proxy_pass http://typecho:80; ,这里同样是容器名。

然后是compose模板:

nano /docker/typecho/docker-compose.yml

写入以下内容:

version: "3.9"

services:
  nginx:
    image: nginx:1.23.1
    ports:
      - "443:443/tcp"
      - "443:443/udp"
      - "80:80"
    volumes:
      - /docker/typecho/conf/nginx:/etc/nginx/conf.d
      - /docker/typecho/ssl_certificate:/ssl_certificate
    depends_on:
      - typecho
    logging: 
      driver: syslog
    restart: always
  
  mysql:
    image: mysql:8.0.29
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: typecho
    command:
      - mysqld
      - --character-set-server=utf8mb4
      - --default-authentication-plugin=mysql_native_password
    volumes:
      - /docker/typecho/data/mysql:/var/lib/mysql
      - /docker/typecho/conf/mysql:/etc/mysql/conf.d
    logging: 
      driver: syslog
    restart: always

  typecho:
    image: joyqi/typecho:nightly-php8.0-apache
    volumes:
      - /docker/typecho/conf/typecho:/app/usr
    logging: 
      driver: syslog
    restart: always

最后运行项目:

cd /docker/typecho
docker-compose config
docker-compose up

(3)运行项目并测试

在浏览器访问自己的域名(如果没有绑定域名就访问服务器ip),即可看到typecho初始页面。跟随引导对typecho进行初始化设置,在本例中,数据库地址填服务容器名或容器全名(mysql或typecho_mysql_1),数据库用户名root、密码123456,数据库名typecho(数据库需要提前创建。本例中通过MYSQL_DATABASE: typecho创建了该库)。如果在本过程中遇到问题,可以参考下一条 (4)问题及其他

(4)问题及其他

第三次提醒,typecho的个性化设置(比如主题、插件等)在typecho根目录的/usr下,joyqi/typecho:nightly-php8.0-apache容器中则是在/app/usr(/app就是typecho在容器中的根目录,不同typecho镜像可能有所差别)。另外,typecho的配置在typecho根目录下的config.inc.php中,里面存有数据库用户密码和其他设置。
下面整理了一些常见的问题。

a.博客迁移

方法一是登入后台,在 控制台-备份 中操作,适用于文章较少时。这样生成的.dat文件只是文章、评论、注册的用户等,/app/usr目录、config.inc.php也可以备份一下。
方法二是从mysql备份typecho使用的数据库,可用于文章较多时。同样,也可以备份一下/app/usr目录和config.inc.php。
使用mysql导出、导入数据见 MySQL 导出数据MySQL 导入数据
另外,joyqi/typecho镜像支持通过docker-compose里的environment(或Dockerfile的ENV命令)设置一些环境变量,来达到第一次登录typecho时无需手动初始化的效果。支持的环境变量名可参考 镜像详情页 。或者也可以直接备份config.inc.php文件。
最后,如果需要,可以写自动备份typecho几个目录的脚本、使用crontab等定时备份。这部分可自行探索,或参考本文最后。

b.安装完成后无法登录

笔者按照 3.实战:编写易移植的typecho并使用https 中的方法完成安装,可以从 www.lisper517.top 访问到博客,进行初始化后却无法登录,表现为在登录页面输入正确的用户密码后该登录页面会刷新、密码一栏清空,打开的其他页面也还是未登录状态;输入错误的用户密码后页面上方则会显示 用户名或密码错误 ,说明typecho能识别正确的用户密码,但无法跳转到登录后的页面。除了不能正常登录,评论、查看文章的功能都正常。
后来笔者修改了nginx配置、去掉了https相关设置,如下:

server {
    listen 80;
    server_name www.lisper517.top;
    
    location / {
        proxy_pass  http://typecho:80;
    }
}

重启nginx容器后可以正常登录。然后把nginx配置改回使用https的配置,登录状态保持,但无法退出。这时可以正常使用备份、撰写/修改文章等用户功能。
期间参考 该镜像github下的提问 ,在 config.inc.php 最后加上一行 define('__TYPECHO_SECURE__',true); ,没有解决问题。该设置大概是让typecho使用https协议。

后来树莓派断电并使用其他Pi OS系统(换sd卡),大概3小时后重新使用该系统,又可以从https登录typecho后台了。用新的树莓派系统按本文配置从头装docker-typecho也没有复现问题,笔者便没有深入研究。估计可能是frps和云服务器的问题。

遇到同样的问题或其他难以解决的问题,推荐重启云服务器,或使用docker-LNMP加树莓派本地运行typecho,把typecho根目录挂载到nginx的网页根目录。可参考笔者之前的 Docker树莓派实践——LNMP树莓派搭建个人博客 ,或 这篇文章

c.typecho镜像选择

之前提到过,joyqi/typecho镜像命名规则为nightly-php版本号-后缀,后缀主要有 空后缀、cli、fpm、apache、alpine 。由于笔者并非CS出身,对php、nginx实际上不太了解,只会用apache镜像+nginx反向代理。有会使用fpm或其他镜像的希望在下方评论不吝赐教。

d.typecho插件及其他

树莓派搭建个人博客 中最后提到了添加备案号、修改允许上传的附件大小。这里再推荐两种插件。
一是文章浏览次数统计插件,如ViewsCounter、PageViews,其使用可参考 ViewsCounter项目地址PageViews使用参考
二是可通过邮件提醒评论回复的插件,如Comment2Mail,安装后,如果用户或游客在文章下方的评论有新的回复,会自动发邮件提醒,当然该插件需要游客留下邮箱。但是需要提醒,由于typecho突然诈尸更新了1.2.0,语法大改,目前以前的插件有些用不了,Comment2Mail就是其中之一。如果用的是typecho 1.2.0之前的版本,使用Comment2Mail可参考 Comment2Mail项目地址typecho官网 。若使用typecho 1.2.0,笔者在 typecho官方论坛 找到一款替代插件CommentNotifier,该插件基于Comment2Mail但按照typecho 1.2.0的新语法打造。详见 CommentNotifier项目地址

使用CommentNotifier,以SMTP、qq邮箱为例, SMTP服务器地址 为 smtp.qq.com , SMTP登录用户 和 SMTP邮箱地址 都填 自己的qq邮箱 , SMTP登录密码 则是 qq邮箱SMTP授权码(登录qq邮箱,在 设置-账户 里选择开启IMAP/SMTP服务,经过验证后可得到一个授权码), SMTP 加密模式 选 SSL加密 , SMTP服务端口 为 465 。另外CommentNotifier自带的邮件模板比较简陋,可自行编写,或使用以下配置(参考 这篇文章 中的配置稍微修改):

<meta charset="utf-8">
<div style="position:relative;width:450px;height:auto;margin:0 auto;padding-bottom:5px;border:rgb(224, 221, 224) solid 1px;border-radius:10px">
    <div style="background-image:url(https://ae01.alicdn.com/kf/UTB8uTIaPSnEXKJk43Ubq6zLppXaW.jpg);width:100%;height:300px;background-size:cover;background-repeat:no-repeat;border-radius:10px 10px 0px 0px"></div>
    <div style="width:40%;height:40px;background-color:rgb(231, 145, 145);margin-top:-20px;margin-left:20px;color:#fff;text-align:center;line-height:40px;border-radius:30px">
        亲爱的:{Pname} !
    </div>
    <div style="line-height:180%;padding:0 15px 12px;width:90%;margin:auto;margin-bottom:0px;font-size:12px">
        <div style="border-bottom:1px solid rgb(216, 213, 213);font-size:13px;margin:10px 0px;padding:10px 0px">
            <span style="color:#12ADDB;font-weight:bold">&gt;&nbsp;</span>
            <span>您在</span>
            <a style="text-decoration:none;color:#12ADDB;font-weight:bold;" href="{permalink}" target="_blank">《{title}》</a>
            <span>下的评论有了新回复呢!</span>
        </div>
        <div style="padding:0 10px 0 10px;margin-top:18px">
            <p>您的评论:</p>
            <p style="padding:10px 15px;margin:18px 0;border-radius:30px;background-color:rgb(255, 240, 240);">{Ptext}</p>
            <p><strong>{author}</strong>&nbsp;给您的回复:</p>
            <p style="padding:10px 15px;margin:18px 0;border-radius:30px;background-color:rgb(240, 240, 255);">{commentText}</p>
        </div>
    </div>
    <div
        style="color:#8c8c8c;font-size:8px;width:93%;margin:auto;margin-top:-30px">
        <p style="padding:20px;">不战斗便无法存活,不战斗便无法生存! ——石森章太郎 《假面骑士龙骑》</p>
    </div>
    <a style="text-decoration:none;background-color:rgb(155, 151, 221);color:#FFF;width:40%;text-align:center;height:40px;line-height:40px;box-shadow:5px 5px 5px rgba(0,0,0,0.2);margin:-10px auto;display:block;border-radius:30px" href="{permalink}" target="_blank">点击查看完整回复內容</a>
    <div style="color:#8c8c8c;font-size:8px;width:100%;text-align:center;margin-top:30px">
        <p>本邮件为系统自动发送,请勿直接回复哦!</p>
    </div>
    <div style="color:#8c8c8c;font-size:8px;width:100%;text-align:center">
        <p>Copyright © {siteUrl}. All Rights Reserved.</p>
    </div>
</div>

替换插件根目录里的 theme/reply.html (Comment2Mail)或 template/default/guest.html (CommentNotifier)即可。注意笔者这里修改了一些变量名,该模板只能用于CommentNotifier。有需要的可自行更改,或到 参考文章 中复制原配置。

(5)后续

docker-typecho的typecho根目录就是/app,只挂载/app/usr的话会为/app创建匿名卷。为了尽量减少匿名卷的生成,把typecho的挂载中 - /docker/typecho/conf/typecho:/app/usr 改成了 - /docker/typecho/conf/typecho/app:/app 。并且为了保证博客24h运行,笔者取消了使用树莓派运行typecho+frp内网穿透,而是直接把typecho运行在了云服务器上。如果以后云服务器涨价,也许会考虑申请动态公网ip+DDNS或其他方式。

另外,为了保证博客及时备份(对/docker/typecho文件夹备份),笔者使用crontab定时备份,操作如下:

mkdir -p /backup/typecho
crontab -e

输入如下内容:

0 0 * * * /usr/bin/zip -r /backup/typecho/backup.zip /docker/typecho

zip命令写绝对路径是怕cron运行时的env里PATH不包括/usr/bin,实际上应该尽量都写绝对路径。用whereis zip可查找zip的路径。
这样每天0点0分就会备份整个docker-typecho。笔者实验时backup.zip仅16MB,解压后的文件夹则有209MB,还是很节约空间的。
最后,可以在树莓派上也设置每天1点拷贝服务器上的/backup/typecho/backup.zip备份文件,具体操作如下:

mkdir -p /backup/typecho
mkdir /backup/key #存放密钥
crontab -e

输入如下内容:

0 1 * * * /usr/bin/scp -i /backup/key/alicloud-backup root@lisper517.top:/backup/typecho/backup.zip /backup/typecho

另外记得打开树莓派的crontab日志功能:

nano /etc/rsyslog.conf

将其中的#cron.* /var/log/cron.log前的#去掉,之后重启树莓派。在笔者的云服务器上cron日志则是/var/log/cron,默认打开。
最后,笔者使用时发现云服务器上的crontab日志里的时间和本地时间一致,但树莓派上则不一致,比如现在是本地时间8:00,crontab里有8点的定时任务,但查看树莓派的cron.log发现crontab的时间可能还是凌晨2点。可以查看一下树莓派系统用的是哪里的时间:

date
#输出时间和本地时间不一致
ls -l /etc/localtime
#输出结果
... /etc/localtime -> /usr/share/zoneinfo/Europe/London

把树莓派的时区改成本地:

rm /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
date
#输出时间和本地时间一致

即可。最后重启rsyslog和cron,再看一下cron.log,时间就是本地时间:

service restart rsyslog
service restart cron
tail -f /var/log/cron.log

(6)为typecho添加其它功能

可以自己修改主题的php,达到美观的功能。如果typecho容器运行时修改php,可能会卡死,重启一下容器就行了。

a.在文章页面添加最新文章

这个其实是上面提到的 ViewsCounter 的一种用法。如下操作:

vim /docker/typecho/conf/typecho/app/usr/themes/default/sidebar.php

在合适的地方加入以下内容:

        <section class="widget">
            <h3 class="widget-title"><?php _e('热门文章'); ?></h3>
            <?php foreach (ViewsCounter_Plugin::getMostViewed() as $post): ?>
                <ul class="widget-list">
                <a href="<?php echo $post['permalink'] ?>"><?php echo $post['title'] ?></a>
                </ul>
            <?php endforeach; ?>
        </section>

即可在侧边栏显示浏览数最多的文章。这个显示的个数也可在插件里设置。

b.添加侧边栏目录索引

参考了 这篇文章

vim /docker/typecho/conf/typecho/app/usr/themes/default/functions.php

添加3个函数:

/* 文章目录开始 */
function createCatalog($obj) {
    //为文章标题添加锚点
    global $catalog;
    global $catalog_count;
    $catalog = array();
    $catalog_count = 0;
    $obj = preg_replace_callback('/<h([1-6])(.*?)>(.*?)<\/h\1>/i', function ($obj) {
        global $catalog;
        global $catalog_count;
        $catalog_count++;
        $catalog[] = array('text' => trim(strip_tags($obj[3])), 'depth' => $obj[1], 'count' => $catalog_count);
        return '<h' . $obj[1] . $obj[2] . '><a name="cl-' . $catalog_count . '"></a>' . $obj[3] . '</h' . $obj[1] . '>';
    }, $obj);
    return $obj;
}

function getCatalog() {
    //输出文章目录容器
    global $catalog;
    $index = '';
    if ($catalog) {
        $index = '<ul>' . "\n";
        $prev_depth = '';
        $to_depth = 0;
        foreach ($catalog as $catalog_item) {
            $catalog_depth = $catalog_item['depth'];
            if ($prev_depth) {
                if ($catalog_depth == $prev_depth) {
                    $index .= '</li>' . "\n";
                } elseif ($catalog_depth > $prev_depth) {
                    $to_depth++;
                    $index .= '<ul>' . "\n";
                } else {
                    $to_depth2 = ($to_depth > ($prev_depth - $catalog_depth)) ? ($prev_depth - $catalog_depth) : $to_depth;
                    if ($to_depth2) {
                        for ($i = 0; $i < $to_depth2; $i++) {
                            $index .= '</li>' . "\n" . '</ul>' . "\n";
                            $to_depth--;
                        }
                    }
                    $index .= '</li>';
                }
            }
            $index .= '<li><a href="#cl-' . $catalog_item['count'] . '">' . $catalog_item['text'] . '</a>';
            $prev_depth = $catalog_item['depth'];
        }
        for ($i = 0; $i <= $to_depth; $i++) {
            $index .= '</li>' . "\n" . '</ul>' . "\n";
        }
        $index = '<div title="目录树" class="gottree glyphicon glyphicon-list"></div>' .
            '<div id="toc-container">' . "\n" .
            $index .
            '</div>' . "\n";
    }
    echo $index;
}

function themeInit($archive) {
    if ($archive->is('single')) {
        $archive->content = createCatalog($archive->content);
    }
}

/* 文章目录结束 */

然后在页面内添加相应的代码,比如也加在侧边栏:

vim /docker/typecho/conf/typecho/app/usr/themes/default/sidebar.php

添加一行即可:

<span style="position:fixed;background:#F3F3F3"><? php getCatalog(); ?></span>

这样就实现了在侧边栏悬浮固定的目录索引,还为标题添加了超链,会前端的可以再精修一下。

c.添加Sitemap

目的是生成一个 你的博客域名/sitemap.xml ,对博客网页进行归类整理,便于谷歌、bing、百度的爬虫访问。
你可以自己写一个爬虫,或者使用typecho插件。笔者找到了一款适用typecho 1.2的插件: Sitemap-For-Typecho ,使用方法如下(参考 插件作者文章一插件作者文章二 ):

首先设置typecho的伪静态,在typecho的后台, 设置-永久链接 里,启用 地址重写功能 。如果出现红字 重写功能检测失败,请检查你的服务器设置 ,则勾选下面的 如果你仍想启用此功能,请勾选这里 。如果还是不行,就放弃从typecho设置伪静态,而是在nginx中添加配置:

    if (!-e $request_filename) {
        rewrite ^(.*)$ /index.php$1 last;
    }

如果用apache则添加:

RewriteEngine On
RewriteBase / 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]

设置完伪静态,就可以添加sitemap插件。在 github<> Code - Download ZIP 中下载zip文件,解压后把里面的Sitemap文件夹放到typecho的 app/usr/plugins 目录下,并且用 chmod 777 -R Sitemap 把该插件目录改成777(不改的话,启用插件时会出现一个好像以 fwrite() 开头的错误报告)。重启docker-typecho,在后台管理插件处打开该插件设置,推荐把 自动更新Sitemap 打开(这样会在每次有新文章时更新Sitemap,但是发布新文章时可能会卡一下,因为要先运行这个插件);也可以在Sitemap更新时自动推送到baidu,但是笔者觉得没有这个必要,因为从后台数据来看,根本没有人从baidu跳转到本博客。

如果不打开 自动更新Sitemap ,那么每次发布新文章后都要到该插件后台管理处手动更新Sitemap。刚安装好插件后可以手动更新一下,访问 你的博客域名/sitemap.xml 看看效果。另外可以在robots.txt中收录一下,添加一行: Sitemap: 你的域名/sitemap.xml

(7)使用其它主题

typecho自带的主题其实已经足够使用,笔者一向认为内容大于形式,但是看久了总会审美疲劳。很多人为typecho开发了各种主题,本文介绍一下 Joe ,搭建后的效果参考 这个演示站点 ,比较花里胡哨。

Joe 的项目地址下载zip包,放到 /docker/typecho/conf/typecho/app/usr/themes 目录,然后就可以使用了。需要注意的是,由于采用了Joe的那一套php页面,所以需要再次手动添加目录索引、备案号。

标签: 树莓派, docker, docker-compose, Typecho, crontab

已有 8 条评论

  1. zurica

    作者大大你好,看了你的教程,感觉非常棒,细节很充实,非常契合我这种同样爱折腾 docker 的玩家。有一个疑问:如果已经使用了Nginx作为反代工具,是否typecho的版本不需要选用apache的了?关于不同版本之间的区别,官方并没有任何说明~~看到你操作的结尾也有删除清理工作,看来是跟我一样有赛博洁癖的人啊!其实用一条命令就能解决了 docker system prune -a

    1. 我是实践的时候不会用fpm后缀的包,所以只能用apache包+nginx反代。github上看到有怎么用fpm包的问题,但是没有人回答。我是纯兴趣爱好,如果互联网找不到资料也束手无策。
      如果感兴趣的话可以看看我其他教程。

      1. zurica

        我也是纯兴趣爱好非本行业,感谢答复,有机会再交流~~

  2. zurica

    老哥你好,我已经搞定了用fpm版镜像的配置,就是用Nginx通过fastcgi协议反向代理php伪静态网页,同时还需要把typecho的容器目录完全映射到宿主机给Nginx读取。其实如果你用了apache版的镜像,也可以不用再装Nginx了

    1. 好,过几天我也试一下,后面加上

      1. zurica

        嗯,我到时候把详细配置发你,现在还在调试

  3. [...]TypechoDocker树莓派实践——Typecho及其备份 - 西区代码小仓库Docker安装typecho - 云子墨 - 博客园docker nginx -v 挂载配置文件问题\_10-listen-on-ipv6-by-default.sh: info: /etc/nginx/-CSDN博客部署nginx时如果挂载了配置路径,配置文件就不会生成了。先临时启动一个nginx拿到配置,然后拷[...]

    1. 感谢阅读我的文章!最新的文章介绍了用nginx proxy manager管理所有子域名(typecho这里就可以不用nginx了),以及用plausible监控自己博客每天的访问量,有兴趣可以看看

添加新评论