最近有点恶心 Twitter,在开始迁移到 Mastodon ,记录下今天自托管 Mastodon 实例的过程。
SSH 登录服务器,准备路径
cd && \
mkdir -p container/mastodon && \
cd container/mastodon
获取 .env.production 环境变量模板
wget https://blog.dejavu.moe/posts/selfhosted-mastodon-instance-with-docker/mastodon.env -O .env.production
sudo chown 991:991 .env.production
获取 docker-compose.yml 模板
wget https://blog.dejavu.moe/posts/selfhosted-mastodon-instance-with-docker/docker-compose.yml.sample -O docker-compose.yml
准备容器映射目录
mkdir -p mastodon/public \
&& sudo chown -R 991:991 mastodon/public \
&& mkdir elasticsearch \
&& sudo chown 1000:1000 -R elasticsearch
提前拉取最新的 Docker 镜像备用
sudo docker compose pull
不建议将 Mastodon 的媒体和文件保存到服务器本机,备份起来会很麻烦。Mastodon 支持使用 S3 或兼容 S3 API 的对象存储,比如 MinIO , Cloudflare R2 , Storj , Tebi.io …更多免费对象存储 在这里 查看。
这里以 Backblaze B2 为例,免费用户 10GB 对象存储,1GB 出站流量,兼容 S3 API,B2 和 Cloudflare 有「带宽联盟」豁免流量,对于单人 Mastodon 实例足够了。
在 Backblaze B2 注册帐号,新建 Bucket(存储桶)

记下 S3 Endpoint

接下来创建一个新的 Application Key

按照下图配置权限

记下 KeyID 和 applicationKey

在这个 Bucket 随便上传一个文件

点击上传的文件,可以看到 Friendly URL

在 Cloudflare DNS 解析里添加一条 CNAME 记录,指向 Friendly URL 的主机名(必须开启小云朵代理)

在 Cloudflare 规则选项卡里面的转换规则中,创建一条重写规则

编辑新创建的转换规则

重写资源路径

在规则设置里打开标准化传入

现在上传到 Backblaze B2 存储的资源可以通过自定义域名访问了,记得设置更长的浏览器缓存时间和边缘缓存时间。将 S3 API 相关配置写入环境变量文件 .env.production
vim .env.production
修改下面字段
# File Storage (optional)
# -----------------------
S3_ENABLED=true
S3_PROTOCOL=https # S3 使用的协议
S3_ENDPOINT=https://s3.xxx.com # S3 API Endpoint
S3_ALIAS_HOST=static.xxx.com # 这里填写您的自定义域名(上面解析用于重写的那个)
S3_BUCKET=<Bucket 名称> # Bucket 名称
AWS_ACCESS_KEY_ID=<S3 API 兼容访问 KeyID> # 对应 B2 KeyID
AWS_SECRET_ACCESS_KEY=<S3 API 兼容访问机密> # 对应 B2 applicationKey
先查看当前路径
pwd
# 比如我的就是
/home/dejavu/container/mastodon
初始化数据库,数据库卷映射目录为
/home/dejavu/container/mastodon/postgres
下面的密码要记好1
sudo docker run --name postgres14 -v $(pwd)/postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD='数据库管理密码' --rm -d postgres:14-alpine
进入 PostgreSQL 控制台
sudo docker exec -it postgres14 psql -U postgres
然后执行下列 SQL 语句
# 在 PostgreSQL 控制台中执行命令
/* 创建名为 mastodon 的用户并设置密码*/
CREATE USER mastodon WITH PASSWORD '密码' CREATEDB;
/* 创建名为 mastodon 的数据库*/
CREATE DATABASE mastodon;
/* 列出当前数据库 */
\l
/* 连接 mastodon 数据库*/
\c mastodon;
/* 出现下面的提示 */
You are now connected to database "mastodon" as user "postgres".
/* 继续执行 */
CREATE extension pg_stat_statements;
/* 退出 PostgreSQL 控制台 */
\q
完成后停止 PostgreSQL 容器
sudo docker stop postgres14
在「预部署」阶段的环境变量文件中,有四个机密信息
# Secrets
# -------
SECRET_KEY_BASE=<浏览器会话机密>
# MFA secret
OTP_SECRET=<多因素认证机密>
# -------
# Web Push
# --------
# Push notification private key
VAPID_PRIVATE_KEY=<推送通知私钥>
# Push notification public key
VAPID_PUBLIC_KEY=<推送通知公钥>
我们可以预先生成并保留备用
# 运行两次
# 一次作为 SECRET_KEY_BASE=<浏览器会话机密>
# 一次作为 OTP_SECRET=<多因素认证机密>
sudo docker compose run --rm web bundle exec rake secret
# 运行一次
# 包含 VAPID_PRIVATE_KEY=<推送通知私钥>
# 和 VAPID_PUBLIC_KEY=<推送通知公钥>
sudo docker compose run --rm web bundle exec rake mastodon:webpush:generate_vapid_key
将上面的信息写入环境变量文件
vim .env.production
完成填写前面的环境变量2 ,比如 SMTP 发信配置。有关更多配置项的说明,请查看 Mastodon 文档 。现在开始准备 Mastodon 的数据库
sudo docker compose run --rm -v $(pwd)/.env.production:/opt/mastodon/.env.production web bundle exec rake db:setup
完成后停止所有容器
sudo docker compose down
先部署相关数据库服务,等待 10s 启动所有服务
sudo docker compose up -d db redis \
&& sleep 10s \
&& sudo docker compose up -d
完成后,在 Cloudflare Zero Trust 控制台添加一个 Tunnel,然后编辑公共主机名(用于 Mastodon 主页,建议裸域)

在这个 Tunnel 上再添加一个公共主机名,这个用于 Mastodon Stream API

现在尝试访问绑定的 Mastodon 主页域名,应该可以正常访问了,那就 OK 了,先不要急着注册用户
直接使用 tootctl 工具来设置 Mastodon 实例管理员,这个帐号我们之后可以直接使用
# 注意修改
# 管理员用户名 username
# 管理员用户的邮箱 [email protected]
sudo docker exec mastodon-web tootctl accounts create "username" --email "[email protected]" --confirmed --role Owner
# 输出:
OK
New password: "初始密码"
上面的初始密码只会显示一次,如果不幸忘记了3 ,可以重置用户密码
sudo docker exec mastodon-web tootctl accounts modify "username" --email "[email protected]" --reset-password
# 输出:
OK
New password: "新的密码"
恭喜您!😎 您刚刚部署的 Mastodon 实例已经可以访问了,欢迎加入联邦宇宙!您也许想要看看 Mastodon 客户端 ?
参考信息
最近有点恶心 Twitter,在开始迁移到 Mastodon ,记录下今天自托管 Mastodon 实例的过程。
SSH 登录服务器,准备路径
cd && \
mkdir -p container/mastodon && \
cd container/mastodon
获取 .env.production 环境变量模板
wget https://blog.dejavu.moe/posts/selfhosted-mastodon-instance-with-docker/mastodon.env -O .env.production
sudo chown 991:991 .env.production
获取 docker-compose.yml 模板
wget https://blog.dejavu.moe/posts/selfhosted-mastodon-instance-with-docker/docker-compose.yml.sample -O docker-compose.yml
准备容器映射目录
mkdir -p mastodon/public \
&& sudo chown -R 991:991 mastodon/public \
&& mkdir elasticsearch \
&& sudo chown 1000:1000 -R elasticsearch
提前拉取最新的 Docker 镜像备用
sudo docker compose pull
不建议将 Mastodon 的媒体和文件保存到服务器本机,备份起来会很麻烦。Mastodon 支持使用 S3 或兼容 S3 API 的对象存储,比如 MinIO , Cloudflare R2 , Storj , Tebi.io …更多免费对象存储 在这里 查看。
这里以 Backblaze B2 为例,免费用户 10GB 对象存储,1GB 出站流量,兼容 S3 API,B2 和 Cloudflare 有「带宽联盟」豁免流量,对于单人 Mastodon 实例足够了。
在 Backblaze B2 注册帐号,新建 Bucket(存储桶)

记下 S3 Endpoint

接下来创建一个新的 Application Key

按照下图配置权限

记下 KeyID 和 applicationKey

在这个 Bucket 随便上传一个文件

点击上传的文件,可以看到 Friendly URL

在 Cloudflare DNS 解析里添加一条 CNAME 记录,指向 Friendly URL 的主机名(必须开启小云朵代理)

在 Cloudflare 规则选项卡里面的转换规则中,创建一条重写规则

编辑新创建的转换规则

重写资源路径

在规则设置里打开标准化传入

现在上传到 Backblaze B2 存储的资源可以通过自定义域名访问了,记得设置更长的浏览器缓存时间和边缘缓存时间。将 S3 API 相关配置写入环境变量文件 .env.production
vim .env.production
修改下面字段
# File Storage (optional)
# -----------------------
S3_ENABLED=true
S3_PROTOCOL=https # S3 使用的协议
S3_ENDPOINT=https://s3.xxx.com # S3 API Endpoint
S3_ALIAS_HOST=static.xxx.com # 这里填写您的自定义域名(上面解析用于重写的那个)
S3_BUCKET=<Bucket 名称> # Bucket 名称
AWS_ACCESS_KEY_ID=<S3 API 兼容访问 KeyID> # 对应 B2 KeyID
AWS_SECRET_ACCESS_KEY=<S3 API 兼容访问机密> # 对应 B2 applicationKey
先查看当前路径
pwd
# 比如我的就是
/home/dejavu/container/mastodon
初始化数据库,数据库卷映射目录为
/home/dejavu/container/mastodon/postgres
下面的密码要记好1
sudo docker run --name postgres14 -v $(pwd)/postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD='数据库管理密码' --rm -d postgres:14-alpine
进入 PostgreSQL 控制台
sudo docker exec -it postgres14 psql -U postgres
然后执行下列 SQL 语句
# 在 PostgreSQL 控制台中执行命令
/* 创建名为 mastodon 的用户并设置密码*/
CREATE USER mastodon WITH PASSWORD '密码' CREATEDB;
/* 创建名为 mastodon 的数据库*/
CREATE DATABASE mastodon;
/* 列出当前数据库 */
\l
/* 连接 mastodon 数据库*/
\c mastodon;
/* 出现下面的提示 */
You are now connected to database "mastodon" as user "postgres".
/* 继续执行 */
CREATE extension pg_stat_statements;
/* 退出 PostgreSQL 控制台 */
\q
完成后停止 PostgreSQL 容器
sudo docker stop postgres14
在「预部署」阶段的环境变量文件中,有四个机密信息
# Secrets
# -------
SECRET_KEY_BASE=<浏览器会话机密>
# MFA secret
OTP_SECRET=<多因素认证机密>
# -------
# Web Push
# --------
# Push notification private key
VAPID_PRIVATE_KEY=<推送通知私钥>
# Push notification public key
VAPID_PUBLIC_KEY=<推送通知公钥>
我们可以预先生成并保留备用
# 运行两次
# 一次作为 SECRET_KEY_BASE=<浏览器会话机密>
# 一次作为 OTP_SECRET=<多因素认证机密>
sudo docker compose run --rm web bundle exec rake secret
# 运行一次
# 包含 VAPID_PRIVATE_KEY=<推送通知私钥>
# 和 VAPID_PUBLIC_KEY=<推送通知公钥>
sudo docker compose run --rm web bundle exec rake mastodon:webpush:generate_vapid_key
将上面的信息写入环境变量文件
vim .env.production
完成填写前面的环境变量2 ,比如 SMTP 发信配置。有关更多配置项的说明,请查看 Mastodon 文档 。现在开始准备 Mastodon 的数据库
sudo docker compose run --rm -v $(pwd)/.env.production:/opt/mastodon/.env.production web bundle exec rake db:setup
完成后停止所有容器
sudo docker compose down
先部署相关数据库服务,等待 10s 启动所有服务
sudo docker compose up -d db redis \
&& sleep 10s \
&& sudo docker compose up -d
完成后,在 Cloudflare Zero Trust 控制台添加一个 Tunnel,然后编辑公共主机名(用于 Mastodon 主页,建议裸域)

在这个 Tunnel 上再添加一个公共主机名,这个用于 Mastodon Stream API

现在尝试访问绑定的 Mastodon 主页域名,应该可以正常访问了,那就 OK 了,先不要急着注册用户
直接使用 tootctl 工具来设置 Mastodon 实例管理员,这个帐号我们之后可以直接使用
# 注意修改
# 管理员用户名 username
# 管理员用户的邮箱 [email protected]
sudo docker exec mastodon-web tootctl accounts create "username" --email "[email protected]" --confirmed --role Owner
# 输出:
OK
New password: "初始密码"
上面的初始密码只会显示一次,如果不幸忘记了3 ,可以重置用户密码
sudo docker exec mastodon-web tootctl accounts modify "username" --email "[email protected]" --reset-password
# 输出:
OK
New password: "新的密码"
恭喜您!😎 您刚刚部署的 Mastodon 实例已经可以访问了,欢迎加入联邦宇宙!您也许想要看看 Mastodon 客户端 ?
参考信息