AberSheeran
Aber Sheeran

在 1C 1G 的服务器上跑 mastodon

起笔自
所属文集: 程序杂记
共计 3460 个字符
落笔于

Oracle 给了我两个 1C 1G 的永久免费服务器,正好用来搭建 mastodon,也把 fuckyou.plus 这个域名用上。

mastodon 给出的 docker-compose.yml 里有三个服务,其中较为吃内存的是使用 ruby 编写的 web 和 sidekiq,streaming 用了 nodejs 所以在轻负载情况下占用的资源并不多。

为了最大化的降低这两个资源大户的需求,我寻求了 new bing 的帮助,知道了将 WEB_CONCURRENCY 设置为 0 的时候,Puma 将会从集群模式变为单进程模式。然后根据 mastodon 配置文档MAX_THREADS 设置为了 2,这是限制 Puma 进程最多只能有两个线程。再把 docker-compose.yml 里 sidekiq 的启动命令修改为 bundle exec sidekiq -c 1,根据 mastodon 文档的说明这会让队列只运行一个线程。

到这里其实已经可以在一台 1C 1G 的服务器上运行 mastodon 了。只是我有两台,所以我将 sidekiq 的线程数量上调之后放到了另一台服务器单独运行,把 docker-compose.yaml 拆解为多个,一个里运行 web 和 streaming,它们和 postgresql、redis 以及前置的 caddy 反向代理服务器一起运行;一个运行 sidekiq。

version: '3'

services:
  postgres:
    image: postgres:14
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - 5432:5432
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'postgres']
    volumes:
      - ./data:/var/lib/postgresql/data
    restart: always
version: '3'

services:
 redis:
    image: "redis:7-alpine"
    command: /bin/sh -c "redis-server --requirepass $$REDIS_PASSWORD"
    environment:
      REDIS_PASSWORD: password
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
    restart: always
version: '3'

services:
  web:
    image: ghcr.io/mastodon/mastodon:v4.2.1
    restart: always
    env_file: .env.production
    command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
    healthcheck:
      test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1']
    ports:
      - '127.0.0.1:3000:3000'
    volumes:
      - ./public/system:/mastodon/public/system

  streaming:
    image: ghcr.io/mastodon/mastodon:v4.2.1
    restart: always
    env_file: .env.production
    command: node ./streaming
    healthcheck:
      test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1']
    ports:
      - '127.0.0.1:4000:4000'
version: '3'

services:
  sidekiq:
    image: ghcr.io/mastodon/mastodon:v4.2.1
    restart: always
    env_file: .env.production
    command: bundle exec sidekiq -c 1
    volumes:
      - ./public/system:/mastodon/public/system
    healthcheck:
      test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]

执行步骤

  1. git clone https://github.com/mastodon/mastodon,复制 .env.production.sample 文件到 .env.production 并将 WEB_CONCURRENCY=0MAX_THREADS=2 写入到头部。
  2. 启动 postgresql 和 redis 服务。
  3. 运行 docker run --rm -it ghcr.io/mastodon/mastodon:v4.2.1 /bin/bash
    1. 在里面使用 bundle exec rake mastodon:setup 按照提示填入配置信息与数据库信息,并初始化数据库与管理员账号。
    2. 复制 bundle exec rake mastodon:setup 命令最终生成的对应配置文件字段到宿主机的 .env.production 文件中。
  4. 修改一些配置,例如 LOCAL_DOMAINSTREAMING_API_BASE_URL,然后使用 docker-compose up -d 启动 web 和 streaming 服务。
  5. 复制 .env.production 文件到另一台服务器放在 docker-compose.yml 同目录下,使用 docker-compose up -d 启动 sidekiq 服务。
  6. 配置 caddy 服务,并通过浏览器登录管理员账号进行站点配置。

其他配置技巧

来自其他服务器的缓存

mastodon 不允许你关闭来自其他服务器的缓存,而当我订阅中继服务器之后,三天时间创建了接近 10 Gb 的 S3 缓存,成本非常高。

偶然的巧合下,我发现把 sidekiq 服务里的 S3 关闭,仅开启 web 和 streaming 服务的 S3,就可以让来自其他服务器的缓存下载在 sidekiq 所在的服务器上,仅自身服务的媒体文件存在 S3 中。

清理其他服务器的旧数据

从数据库中删除未被引用的嘟文,例如来自中继的或来自本地用户不再关注的用户的嘟文,同时没有被回复的或以其他方式与之互动的:docker-compose exec -d sidekiq tootctl statuses remove --days 7

移除本地缓存的其它实例媒体附件:docker-compose exec -d sidekiq tootctl media remove --days 7

如果你觉得本文值得,不妨赏杯茶
SO_REUSEADDR 和 SO_REUSEPORT
让一份代码同时支持同步与异步