2021年8月

typecho一直都是用的mysql作为数据库存储,最近因为服务器到期需要迁移网站,所有的服务都转到docker了,迁移起来略显麻烦,因此就想抛弃mysql了,直接使用sqlite作为存储。这样迁移网站只要复制一下db文件就可以了,不用每次都得搭个mysql或者容器,简单方便。

typecho本身就是支持sqlite的,只不过在安装的时候如果选择了mysql,就没有办法在界面上更改数据库类型了,要修改只能通过改代码配置来完成。数据库的配置放在网站根路径下的config.inc.php文件中,有这么一段:

/** 定义数据库参数 */
$db = new Typecho_Db('Pdo_Mysql', 'tp_');
$db->addServer(array (
  'host' => 'db',
  'user' => 'xxxxx',
  'password' => 'xxxxxx',
  'charset' => 'utf8',
  'port' => '3306',
  'database' => 'typecho',
), Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);

要想改成sqlite的方式,只需修改配置为以下内容即可:

/** 定义数据库参数 */
$db = new Typecho_Db('Pdo_SQLite', 'tp_');
$db->addServer(array (
  'file' => '/xx/xx/xx/xx.db',
), Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);

修改之后即可生效,但这里还缺少了重要的一步:迁移数据。如何迁移数据可参考使用Navicate迁移Mysql到Sqlite

迁移完成后的几处安全建议:

  1. 不要将db文件放到网站目录内,可能导致db文件通过外部链接下载
  2. db文件命名尽量随机,不要轻易被人猜出
  3. 如果db文件放在网站目录内,要在nginx配置设置访问db文件直接返回404

迁移之后如何验证切换成功了:

  1. 确认网站可以正常访问
  2. 每查看一次网站,都会导致db文件更新,可通过后台查看文件更新时间是不是最新

第一步:创建sqlite文件

点击左上角的连接按钮,选择sqlite,在弹出的窗口中选择新建sqlite3,然后设置好各项配置:

最后选择保存即可创建sqlite文件

第二步:连接mysql

再次点击左上角按钮连接,选择mysql,在弹出的窗口中配置好连接信息:

第三步:数据同步

在工具栏,点击工具-数据传输,左边选择mysql连接和数据库,右边选择sqlite连接和数据库:

注意:传输到sqlite中的数据库使用默认的main就好了,不要

然后一直选择下一步就行了,之后执行完成后就会生成sqlite文件了。

因为家里宽带申请到了公网IP,希望可以直接通过公网IP访问回家。但是公网IP并不是固定的,每隔一段时间就会变化一下,导致需要频繁变化访问回家的公网IP,着实不爽。于是就想着使用ddns来解决这个问题。本想着是自己写个程序,通过dnspod的api接口来动态更新ip,但是程序写到一半后发现群晖已经就有这个功能了,于是干脆就直接用群晖的功能来做dns了。

群晖的ddns配置在控制面板-外部访问中,默认支持了多家云厂商的ddns,国内常见的如:

  • dnspod
  • 花生壳

因为我的域名都托管在了腾讯云,腾讯云的dns解析就是dnspod,因此可以直接使用dnspod.cn来配置ddns。

首先,进入到dnspod控制台页面,点击右上角个人头像,选择“API密钥“:

进入到API密钥页面,将tab栏切换到DNSPod Token(注意,不是腾讯云API密钥),然后点击下面的创建密钥来生成token:

创建完成token后,会分配一个ID和Token:

这里要注意的是需要将token保存下载,因为系统不会保存token信息,以后在控制台也无法查到,所以务必要妥善保存。

将id和token分别填入到群晖中的用户名和密码栏目,主机名称填写对应的域名,如www.xxxx.com,服务供应商选择DNSPod.cn(不要选DNSPod.com了)。提交即可完成ddns配置:

如果配置成功,在控制面板中就能看到ddns的状态是正常,此时说明ddns就生效了:

随着https的不断普及,目前几乎所有的网站都开启了https,但是有时候网站内的部分资源还是http的,此时因为浏览器的安全策略,浏览器默认会拦截这些资源。导致网站无法正常显示,出现报错:

Mixed Content: The page at 'https://www.xxx.com/' was loaded over HTTPS, but requested an insecure stylesheet 'http://www.xxx.com/xxx.css'. This request has been blocked; the content must be served over HTTPS.

解决方案

http协议中提供了一个头部:

Content-Security-Policy: upgrade-insecure-requests

当它被设置的时候,浏览器会自动将https网站内部的http资源请求升级为https,避免出现mixed content问题。

nginx配置方式:

add_header Content-Security-Policy upgrade-insecure-requests;

参考:Mixed Content

使用Dockerfile构建完镜像后,发现镜像特别大:

[cherry@k8s-yasuo:~]$ docker image ls 
REPOSITORY                                TAG                  IMAGE ID       CREATED             SIZE
php-fpm                                   7.4.0-alpine-ext     d9c182c6c1ae   18 minutes ago      447MB

这是一个基于alpine构建的php-fpm镜像,构建前镜像大小是90M,被我魔改后竟然达到了450M,简直不可思议。不觉明厉之下,决定研究一下为什么镜像达到了这么大。

使用docker history image可以查看镜像的每一层的构建大小:

最上面的三条就是我新增的三个RUN指令生成出来的层,可以看到,2b5947710812这个层是占用了350M,因此可以断定这个指令执行有问题。这个指令执行的是更新alpine的源然后安装上一些php的库:

RUN set -eux; \
    echo "https://mirrors.tencent.com/alpine/v3.14/community/" >>/etc/apk/repositories; \
    apk add --no-cache ghostscript imagemagick; \
    apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
        freetype-dev imagemagick-dev libjpeg-turbo-dev libpng-dev libzip-dev;

本来我期望是在这个RUN执行完成之后再执行一条apk del的命令来删除新增的库:

RUN apk del --no-network .build-deps

但是我忽略了一个问题,docker构建镜像时,每个RUN指令都会生成一个层,后面的指令生成的层是基于上个层来的。也就是说,即使第二个RUN指令删除上个RUN指令添加的文件,此时依旧还是包含了上一个层生成的数据。

解决办法:把两个RUN指令合成为一个。

alpine无法安装imagemagick问题

使用alpine的docker镜像安装imagemagick时报错:

bash-5.1# apk add imagemagick
fetch https://mirrors.tencent.com/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
ERROR: unable to select packages:
  imagemagick (no such package):
    required by: world[imagemagick]

问题原因:imagemagick属于community包,仓库源中没有配置community的源。

解决方案:在/etc/apk/repositories中添加community源,如:

https://mirrors.tencent.com/alpine/v3.14/community/