GoToSocial 搭建与备份心得
GTS 的安装#
因为开到了甲骨文,所以决定搭建一个自己的 Fediverse 实例,思来想去选了 GoToSocial, 比较轻量级,也可以使用各种兼容 Mastodon API 的客户端,美中不足就是比较 bareminimum,像表情回应和引用之类的功能是没有的。
GTS 官方的 docker-compose.yaml 长这样:
wget https://codeberg.org/superseriousbusiness/gotosocial/raw/branch/main/example/docker-compose/docker-compose.yaml
services:
gotosocial:
image: docker.io/superseriousbusiness/gotosocial:latest
container_name: gotosocial
user: 1000:1000
networks:
- gotosocial
environment:
# Change this to your actual host value.
GTS_HOST: example.org
GTS_DB_TYPE: sqlite
# Path in the GtS Docker container where
# the sqlite.db file will be stored.
GTS_DB_ADDRESS: /gotosocial/storage/sqlite.db
# Change this to true if you're not running
# GoToSocial behind a reverse proxy.
GTS_LETSENCRYPT_ENABLED: "false"
# Set your email address here if you
# want to receive letsencrypt notices.
GTS_LETSENCRYPT_EMAIL_ADDRESS: ""
# Path in the GtS Docker container where the
# Wazero compilation cache will be stored.
GTS_WAZERO_COMPILATION_CACHE: /gotosocial/.cache
## For reverse proxy setups:
GTS_TRUSTED_PROXIES: "172.18.0.1/16"
## Set the timezone of your server:
#TZ: UTC
ports:
- "443:8080"
## For letsencrypt:
#- "80:80"
## For reverse proxy setups:
#- "127.0.0.1:8080:8080"
volumes:
# Your data volume, for your
# sqlite.db file and media files.
- ~/gotosocial/data:/gotosocial/storage
# OPTIONAL: To mount volume for the WAZERO
# compilation cache, for speedier restart
# times, uncomment the below line:
#- ~/gotosocial/.cache:/gotosocial/.cache
restart: "always"
networks:
gotosocial:
ipam:
driver: default
config:
- subnet: "172.18.0.0/16"
gateway: "172.18.0.1"
我自己用的时候,因为机器上已经有运行着的 Caddy,就把关于反向代理的部分都注释掉了。
然后在 environment 底下加了几行(GTS 有个单独的 config 文件用来调整环境变量,但是你不想挂载出来的话可以直接在 compose.yml 里面写,只要把变量名全部大写, - 换成 _,在前面加上 GTS_ 就好了,参考此处):
GTS_ACCOUNTS_ALLOW_CUSTOM_CSS: true # 允许自定义 CSS
TZ: Europe/Berlin
GTS_INSTANCE_LANGUAGES: "zh,en,nl,de,fr,ja"
在 volumes 下面挂载了自定义字体:
- /home/ubuntu/gotosocial/fonts/GeistPixel-Square.woff2:/gotosocial/web/assets/fonts/GeistPixel-Square.woff2:ro
这样做之后,就可以在 CSS 中调用啦。
CSS 美化#
GTS 用户资料主题的来源有两个,一个是管理员上传主题作为备选项,另一个是用户自行编辑 CSS。这两个效果会叠加。
全站的 CSS 也是可以自定义的,我用了 Catppuccin Frappé 和 Geist Pixel Square, Fusion Pixel 的组合。
数据库和媒体的备份#
说实话我对自建实例这件事一直很犹豫,因为我对自己的备份没什么信心,如果数据库损坏,签署信息的密钥会丢失,想要从这个域名重新加入联邦会非常非常麻烦。
GTS 文档里面有关于备份和恢复的详细教程,其中推荐的数据库备份法是 Borgmatic。不过我比较懒,在写这篇之前没有看这部分所以我没用
备份媒体和数据库我用的是 S3 桶,通过 rclone 挂载。
当然可以把 docker 映射到本机的文件夹里的内容一股脑全部上传,不过这样不太优雅,因为媒体文件包含远端实例的缓存,这些东西吃掉的空间比较多,但并没有备份的必要,只需要保存本实例的媒体即可。
GTS CLI tools 有 gotosocial admin media list-attachments 和 gotosocial admin media list-emojis, 只要在运行的时候加上 --local-only 的 flag 即可只列出本地媒体文件。
输出类似于这样:
/gotosocial/062G5WYKY35KKD12EMSM3F8PJ8/attachment/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg
/gotosocial/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg
/gotosocial/01F8MH5ZK5VRH73AKHQM6Y9VNX/attachment/original/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpg
/gotosocial/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg
/gotosocial/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH7TDVANYKWVE8VVKFPJTJ.gif
/gotosocial/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg
/gotosocial/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH58A357CV5K7R7TJMSH6S.jpg
/gotosocial/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01CDR64G398ADCHXK08WWTHEZ5.gif
利用这个功能,我们可以在定时备份的时候对媒体文件根据本地账号进行筛选。
以 rclone 备份 docker 容器映射到宿主机的文件夹为例:
/usr/local/bin/rclone-backup-optimized.sh
#!/usr/bin/env bash
set -uo pipefail
SRC="/home/ubuntu/gotosocial/data"
MEDIA_DST="remote:bucket/media"
DB_DST="remote:bucket/db"
CONF="/home/ubuntu/.config/rclone/rclone.conf"
COMPOSE_FILE="/home/ubuntu/gotosocial/docker-compose.yaml"
SERVICE="gotosocial" # 容器名称
GTS_BIN="/gotosocial/gotosocial"
DB_FILE="/home/ubuntu/gotosocial/data/sqlite.db"
# SQLite (vacuum into snapshot)
DB_OK=1; DB_OUT=""
SNAPDIR=$(mktemp -d); SNAP="$SNAPDIR/sqlite.db"
if DB_OUT=$(sqlite3 "$DB_FILE" "PRAGMA busy_timeout=10000; VACUUM INTO '$SNAP'" 2>&1); then
CHK=$(sqlite3 "$SNAP" "PRAGMA integrity_check" 2>&1)
if [ "$CHK" = "ok" ]; then
if DB_OUT=$(rclone copy "$SNAP" "$DB_DST/" --config "$CONF" 2>&1); then
DB_OK=0
fi
else
DB_OUT="Snapshot integrity failed: $CHK"
fi
fi
rm -rf "$SNAPDIR"
# list local account id
get_ids() {
sudo docker exec "$SERVICE" \
"$GTS_BIN" admin media "$1" --local-only 2>/dev/null \
| grep -oE '/[0-9A-HJKMNP-TV-Z]{26}/(attachment|emoji)/' \
| grep -oE '[0-9A-HJKMNP-TV-Z]{26}'
}
IDS=$( { get_ids list-attachments; get_ids list-emojis; } | sort -u )
# sync media
FILTER=$(mktemp)
while IFS= read -r id; do printf '+ /%s/**\n' "$id"; done <<< "$IDS" >> "$FILTER"
printf -- '- **\n' >> "$FILTER"
MEDIA_OUT=$(rclone sync "$SRC" "$MEDIA_DST" --filter-from "$FILTER" --config "$CONF" 2>&1)
MEDIA_CODE=$?
rm -f "$FILTER"
每次备份完后,也可以用 Discord Webhook 发送提醒,防止备份失败自己不知道。
所以我在脚本中加上了:
WEBHOOK="https://discord.com/api/webhooks/.../..."
notify() { # $1=title $2=color $3=description
local payload
payload=$(jq -n --arg t "$1" --arg d "$3" --arg h "$(hostname)" --argjson c "$2" \
'{embeds:[{title:$t, description:$d, color:$c, footer:{text:$h}, timestamp:(now|todate)}]}')
curl -sf -H "Content-Type: application/json" -d "$payload" "$WEBHOOK" >/dev/null
}
NUM=$(printf '%s\n' "$IDS" | wc -l | tr -d ' ')
[ "$DB_OK" -eq 0 ] && DB_LINE="Database: success" || DB_LINE="Database: failed ($(printf '%s' "$DB_OUT" | tail -c 300))"
[ "$MEDIA_CODE" -eq 0 ] && MEDIA_LINE="Media: success (${NUM} local account directory/ies)" || MEDIA_LINE="Media: failed (exit $MEDIA_CODE)"
if [ "$DB_OK" -eq 0 ] && [ "$MEDIA_CODE" -eq 0 ]; then
TITLE="GtS backup success"; COLOR=3066993
else
TITLE="GtS backup failed"; COLOR=15158332
fi
TAIL=$(printf '%s' "$MEDIA_OUT" | tail -c 1000)
DESC=$(printf '%s\n%s\n```\n%s\n```' "$DB_LINE" "$MEDIA_LINE" "${TAIL:-(Media no output)}")
notify "$TITLE" "$COLOR" "$DESC"
好看好用的前端 Phanpy#
Phanpy 的安装很懒人,因为它是纯静态的,可以直接下载 release 之后用 web server 反代,不过官方并不推荐这么做,推荐的做法是 custom build。
克隆仓库之后类似这样:
PHANPY_DEFAULT_INSTANCE=social.obsp.de \
PHANPY_CLIENT_NAME="Observer's Space Social" \
PHANPY_WEBSITE="https://phanpy.obsp.de"
PHANPY_PRIVACY_POLICY_URL=https://social.obsp.de/about \
npm run build
dist 文件夹里就会有我们想要的东西。
目前 Phanpy 还不支持实例白名单,所以我稍微修改了一下 src/pages/login.jsx,只能从一个特定实例登录。
Comments on Giscus
Comments on Mailing List
Don't feel like using GitHub? Don't worry, we have a mailing list hosted on SourceHut. Just send an email to ~yuki/obsp-inbox@lists.sr.ht to join the discussion!
Comments on Fediverse
With an account on the Fediverse, you can respond to this post. Since ActivityPub is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.
Learn how this is implemented here.