Mastodon: 将媒体文件存放在本地(docker 版)

本攻略适用于——

  • 自建 mastodon(非大站)
  • 使用 docker compose
  • 将媒体文件直接保存在服务器上,而不使用 s3 外部存储

这个搭配虽然不多见,但其实用起来满爽的。很多人用的 s3 服务都是在薅羊毛,而 mastodon 那个变态的,把别人家的媒体文件缓存到自家的架构,流量的吞吐其实很大的(开了 relay 就更夸张),薅羊毛时很容易就超出了。反而是 vps 本身的流量上限很高。对于个人建站而言,媒体文件总量通常 <50GB,某些 vps 自带 200GB 硬盘,足够用了。

缺点是,除了数据库定期备份外,也要考虑媒体文件的异地备份问题。但其实只需要备份存储本地附件的 media_attachments,而 cache 是不需要备份的,所以工作量也不大。

两年前我把媒体文件转移到本地时,参照了 antisocial science 的设置。但因为我用 docker,官方默认的设置,docker 内外权限不一致,无法将媒体文件写到本地。于是匆匆又在本地建了个 minio s3 来中转……这样其实很浪费资源了,minio 的开销也不小。所以最近趁着搬家,又试了一下,终于把 docker + 本地存储 跑通了。


1. 在 docker-compose.yml 里,

web 和 sidekiq 容器中,已经预设了媒体文件的卷映射

volumes:
- ./public/system:/mastodon/public/system

这个不用动。——也可以改成其它的路径,但要和后面的设置一致(本文用相同的颜色标明)。

2. 修改 .env.production

S3_ENABLED=false
PAPERCLIP_ROOT_PATH=/mastodon/public/system
PAPERCLIP_ROOT_URL=/fivestone-mastodon-media

PAPERCLIP_ROOT_URL 是服务器的所有媒体文件链接的子文件夹名称,形如:

https://mastodon.fivest.one/fivestone-mastodon-media/media_attachments/.../x.jpg

默认值是 /system;但是建议改成独特一些的名字,而且建议和 S3_BUCKET 一致。以后需要在本地存储和 s3 之间转换时,可以省一点心。(所以要独特一些,防止回头在 s3 上和别人撞名)

3. 修改 nginx 的域名配置文件

参照官方的配置,把域名文件夹里的 proxy_pass ,直接改成本地的 alias

server 
{
  server_name mastodon.fivest.one;
# ......

  location /fivestone-mastodon-media/
  {
    alias /path-to...docker-compose-folder/public/system/ ;

    proxy_cache CACHE;
    proxy_cache_valid 200 48h;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_lock on;

    expires 1y;
    add_header Cache-Control public;
    add_header 'Access-Control-Allow-Origin' '*';
    add_header X-Cache-Status $upstream_cache_status;
    add_header X-Content-Type-Options nosniff;
    add_header Content-Security-Policy "default-src 'none'; form-action 'none'";
  }
}

然后重启 nginx

sudo systemctl reload nginx.service

4. 通过 docker 设置媒体文件夹的权限

在 docker 内部,是以 mastodon 用户的身份,来运行程序的,所以要把媒体文件夹的所有者改成(docker 内部的)mastodon:

sudo docker-compose run --user=root --rm web chown -R mastodon /mastodon/public/system

如果是从 s3 迁移到本地,把媒体文件移入这个本地文件夹(/path-to…docker-compose-folder/public/system/)后,也要再执行一遍上面这条命令。

或者在 mastodon docker 服务已经启动的情况下,执行:

sudo docker exec -u 0 mastodon_container_web chown -R mastodon /mastodon/public/system

但在这条命令执行结束之前,mastodon 在后台写入媒体文件时,仍然可能出现文件夹权限不足,无法写入的问题。

WordPress 使用 SQLite 数据库

之前写了一半的,如何在轻量级个人 VPS 上搭建各种服务的帖子。一时懒得去把坑填完了。但前几天突然发现自己落入了思维误区:为了配合 Mastodon 或 Pleroma,总想着如何把 WordPress 从 MySQL 迁移到 PostgreSQL。——但是,其实完全可以用 SQLite 啊!对于偶尔才更新一篇的个人 blog 用户,把数据库放在一个 SQLite 文件里,不需要另外安装数据库服务,完全是可行的。

用 Docker 观察内存开销。对于新建的 wordpress 站点,wordpress 本身(包括 php-fpm、nginx)占用内存大约是 40-100M(使用缓存插件后会减少);MySQL 数据库占用内存 200M,随着渐渐使用,有着近千篇文章和评论的 blog 站点,MySQL 占用内存会达到 500M 甚至更多。 ——数据库的这部分内存,使用 SQLite 后,完全是可以省下的。

可以通过 SQLite Integration 插件,安装基于 SQLite 的 WordPress。

WordPress 官网的插件页面,因为作者失联而停更。但隐藏的插件下载链接,一直都还有效:

https://downloads.wordpress.org/plugin/sqlite-integration.1.8.1.zip

UPDATE:上面这个原作者已经停更了的代码,只支持到 php 7.4,在 php 8 里已经失效了。大家可以继续用,但要注意 wordpress 的 php 环境版本。推荐使用 Github 上这个插件的分支,已经被好心人升级到了 php 8.1。

使用非常简单,就是把 db.php 复制到 wp-content 目录里,同时确保你的系统安装了 php-sqlite3 模块。这里有篇攻略。现有的站点,可以通过 Duplicator 之类的 wordpress 备份插件,或者 wordpress 自身的导入导出功能,进行迁移,不需要进行数据库级别的转换操作。

注意事项:

1. 最重要的,数据库的文件的存放位置,这个一定要改!默认的数据库位置是在 wp-content/database/.ht.sqlite,是会被人通过浏览器从 http://website/wp-content/database/.ht.sqlite 直接下载的!虽然插件在 database 文件里添加了 .htaccess 权限控制,但对于如今大家用的 Nginx,是默认无效的。

在 wp-config.php 里添加设置:

define('DB_DIR', '/absolute/custom/path/to/directory/for/sqlite/database/file/');
define('DB_FILE', 'custom_filename_for_sqlite_database');

可以更改数据库文件的存放位置。强烈建议把数据库文件,放到无法直接用网址从外部访问的目录(记得给那个文件夹授权可写)。

2. SQLite 不适合多线程的高并发使用。如果网站会有多个用户同时在后台编辑,那么网站不适合使用 SQLlite;如果只有一个写作者自己编辑 blog,就很合适。但要避免使用那些,在一般访客浏览网站时,也会导致对数据库进行写入的插件,如:

  • WP Statistics 这样的访客统计插件,会把来访者的每一次点击,都记录到本机数据库里。建议使用 Google Analysis 之类的外置统计软件(Google 给 wordpress 做了个官方插件 Site Kit by Google),通过在页面嵌入 js ,发送访客数据到 Google 服务器,不会写入本地数据库。
  • 官方的防垃圾评论插件 Akismet Anti-Spam,其实也是先把每条评论写入本地数据库,再判断是否垃圾的。如果被机器人大量发送垃圾评论,也会造成数据库写入的压力。建议使用 WP Captcha 之类的验证码插件(可以单独使用或配合 Akismet 一起用),把大多数垃圾评论在写入数据库之前就过滤掉。

3. 使用 WP Super Cache 插件,为网站生成缓存文件,可以极大地减少对数据库的读取操作。个人用户完全可以在插件设置里,关闭默认的 Garbage Collection 功能。


网上搜到的 WordPress + SQLite 的 docker images(12),Wordpress 和 php 的版本都有些过时了,本身也有一些小问题(如数据库文件夹的权限设置),建议修改 Dockerfile 然后自行编译。回头有时间我去改个试试。