Mastodon,中文名字叫「长毛象」,可以理解为自托管的Twitter/微博。自从马斯克收购了Twitter,施行了一系列匪夷所思的激进政策后,一大群人离开了Twitter,走进了自托管的Mastodon的世界。
看到可以自托管,那么,不如自己搭一个试试?
哦,我失败了……下面是我做过的尝试。
构想
- 由于Mastodon需要的内存有点多(搭好后啥都不干,内存占用2G),搭在1C1G的LightSail小鸡上是不太可能了。所以要么搭在小主机上(N6005+16G内存),要么搭在NAS(J4125+16G内存)上。
- 搭好后,用FRP转发到公网,或者用TailScale组个内网,想办法转发出去
- 肯定是全Docker方案啦~
步骤
docker-compose 文件
Mastodon的Git里面有一个 docker-compose.yaml
文件可以用。拉下来,可以看到整个项目分成这几部分:
- 数据库类:postogres数据库和redis缓存
- 前端:web
- API: streaming
- 后台任务:sidekiq
我们对这个文件做修改:
- 临时地,给postgres加个用户名和密码。不然后面我们得手动加个用户……就懒到极致吧。在
db
的environment
里面,将原来的POSTGRES_HOST_AUTH_METHOD
给干掉,然后加上POSTGRES_DB
、POSTGRES_USER
和POSTGRES_PASSWORD
三个环境变量就好了。 - 删除 web 、 streaming 和 sidekiq 里面的 build,这样就可以用预编译的东西了
- 给所有容器都分配个名字吧,就在每个容器里面加个
container_name
。这样好处是后面填数据库地址、redis地址,可以直接填这个名字,比较方便 - volumes,其实就一个,映射到了容器里面的
/mastodon/public/system
目录。这个目录是用户上传的文件,如果后面想用S3的话就把这个映射给干掉 - 为了简单,就先不开elastic search 吧……直接删掉
安装 Mastodon
好了,前面的编排文件写好了,但是在「安装」这一步(其实是生成一些Token啊,Salt啊之类的配置),我们使用命令行和Portainer有那么一点点不同。
使用命令行安装
如果你比较习惯于用命令行,那么也可以直接跑下面的指令,临时运行个容器来跑安装过程:
docker-compose run --rm web bundle exec rake mastodon:setup
它会问你好多东西,按照你想的填就是了。过程中有几个东西比较重要:
- 它会问你是不是要保存配置,选「是」,然后它会把所有配置都打在屏幕上,我们需要手动复制下来
- 新创建个文件(例如叫
.env.production
,反正和你编排文件里面写的env_file相同就好了),将所有东西复制到这个文件里。 - 之后会问要不要创建数据库,选「是」
- 之后会问你要不要创建管理员用户。这里直接创建的话会有Bug(此时会无视你前面填写的redis地址,强制使用localhost,导致报错),所以暂时选 否,后面再用其他方法创建
这些搞完之后,可以执行 docker-compose down
先关掉所有容器,然后再 docker-compose up -d
运行所有容器。
最后使用下面语句创建管理员用户(这里面的 web 是web容器的名字。如果你制定了名字,就用你指定的;如果没指定,容器可能叫 mastodon_web_1 或者 web_1):
docker exec web tootctl accounts create USERNAME --email EMAIL --confirmed --role Owner
安装好后,输入 curl http://127.0.0.1:3000/health
看看是不是能看到「OK」字样。
使用Portainer安装
由于Portainer会一下将所有容器都启动起来……但你没那些配置还启动不起来容器,这就产生了先有鸡还是先有蛋的问题。所以我们需要临时写一个「简化版」的编排文件,。
首先,保留 db
和 redis
这两段, 其他全删除。然后把 web
改写成这样:
web:
image: tootsuite/mastodon
restart: always
environment:
- "RAILS_ENV=production"
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; tail -f /etc/hosts"
networks:
- external_network
- internal_network
整个stack启动起来后,去web的console里面执行下面这条指令,就能开始「安装」过程:
bundle exec rake mastodon:setup
其他的和上面一样,同样是获取到一大堆环境变量。直接复制出来,然后回到写yaml的那个地方,下面有environment,点击高级,将这一大堆环境变量贴进去。
然后将yaml文件替换为正常的yaml。这里还有个比较重要的点:需要在上面yaml编辑器里面将 web 、 streaming 和 sidekiq 里面的 env_file
改个名字,必须叫 stack.env
。如果使用默认的.env.product
的话,Portainer会给你发脾气,说没有这个文件。
好了,就到这里了!我遇到的问题是,直接访问 http://127.0.0.1:3000
各种报403错误,连明明确实存在的静态文件也会报403;访问 http://127.0.0.1:4000
的话会报没鉴权(符合预期)。所以我就没辙了。下面都是我做过的其他尝试,都没成功。各位如果有成功的,求借鉴一下经验。
设置正向代理
你看到的Mastodon设置里面,都会把Nginx和SSL放为重点中的重点,大篇大篇都在写如何高SSL。查了Issues,就是说,如果没有SSL的话,那么一些高级功能,例如服务端主动推送啥的都会不能用。所以,尽量配个SSL吧。但不配SSL其实吧也能用,体验差点而已。
那么,配置大致SSL有两个方案:第一个是用Nginx做代理,然后用Certbot或者acme.sh 来搞证书;另一种是直接用Caddy来做代理和搞证书。下面两个方案都写一下:
Nginx
Mastodon的repo里面有个nginx的demo。拉下来,然后改改:
- 它说路径是
/home/mastodon/live/public
,但实际上我们需要将中间的live
都去掉。哦对了,这个路径前面说过,是Mastodon的用户上传文件的路径,如果你用S3的话,完全不必操心这个 - 注释里面说,如果用Docker部署,那么需要将所有的
try_files $uri =404;
全部改成try_files $uri @proxy;
- 我自己比较强迫症,所以将
assets
、avatars
、emoji
等目录全都写在了一起……你看嘛,除了路径不同,其他配置都一模一样的,而且用的都是正则,所以合并写在一起,可以立省好几十行:
location ~ ^/(assets|avatars|emoji|headers|packs|shortcuts|sounds|system)/ {
add_header Cache-Control "public, max-age=2419200, must-revalidate";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
try_files $uri =404;
}
然后呢,去改一下原来的 docker-compose.yaml
,把Nginx加进去
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./data/nginx:/etc/nginx/conf.d:ro
- ./logs/nginx:/var/log/nginx
- ./data/acme.sh/deploy:/etc/letsencrypt:ro
- ./data/mastodon/public:/home/mastodon/public:ro
restart: always
SSL
不知道为啥,官方教程、其他教程里面都推荐用CertBot,毕竟是LetsEncrypt项目的亲儿子。但我是N年前从CertBot叛逃到acme.sh的,感觉真香。
那,顺带的,再在 docker-compose.yaml
里面加上个acme.sh呗:
acme.sh:
image: neilpang/acme.sh
container_name: acme.sh
restart: always
command: daemon
volumes:
- ./data/acme.sh/internal:/acme.sh
- ./data/acme.sh/deploy:/etc/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock
那这样差不多就成了。整个项目用 docker-compose up -d
启动起来,然后去申请证书就好了。
Caddy
上面选正向代理的时候比较纠结:Nginx还需要我自己去搞证书,还是个内网的证书,多麻烦。那,不如直接让Caddy代劳,同时完成反代和证书这两个事儿吧。
首先你需要写一份Caddyfile。在Mastodon的一个PR里面找到了一份十分简洁的Caddyfile。有胆量想Merge到官方Repo的代码,应该质量还不错。但同样的,也需要把路径里面的 live
给去掉。
然后是正常搞Caddy。在 docker-compose.yaml
里面加上:
caddy:
image: caddy:<version>
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./data/Caddy/Caddyfile:/etc/caddy/Caddyfile
- ./data/Caddycaddy_data:/data
- ./data/Caddycaddy_config:/config
- ./data/mastodon/public:/home/mastodon/public:ro
LinuxServer的镜像
就是说,LinuxServer这个组织,自己将一些常见的应用重新包装了一下,做成了Docker镜像。有些重打包打得还不错。
可以看这个 https://hub.docker.com/r/linuxserver/mastodon ,它是将Mastoodn的三个应用合到了一起,甚至把Nginx也配在了镜像里,你只要再配置个Postgres和redis就好了。至于环境变量,你可以按照它的Readme里面说的,全部搞成环境变量写在 docker-compose.yaml
里面,也可以像官方教程一样搞 .env
文件。反正除了 docker-compose.yaml
里面镜像个数减少了一点之外,其他也没啥变化。
启动起来后,依然是啥啥都是403 Forbidden,但是比上面官方原版的有一点好是,它静态文件是可以正常工作的。镜像里面似乎比较乱,竟然还有个PHP……emm,不知道该说啥好。
反正就是,啥啥都403 Forbidden,啥啥都用不了,而且是在内网,也搞不到证书,后续的反向代理到公网也没办法实验。而且即使代理到公网上,好像也会遇到证书的问题?那就……作罢!删虚拟机!不玩了!
发表回复